Implement Piston 1/2
Not fully done
This commit is contained in:
parent
3a7f68d049
commit
1edbfa7289
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -323,18 +323,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.37"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.37"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
@ -1365,12 +1365,12 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1415,9 +1415,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.13.0"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465"
|
||||
checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.3",
|
||||
]
|
||||
@ -2022,8 +2022,10 @@ name = "pumpkin-world"
|
||||
version = "0.1.0-dev+1.21.5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitflags 2.9.0",
|
||||
"bytes",
|
||||
"criterion",
|
||||
"crossbeam",
|
||||
"dashmap",
|
||||
"derive-getters",
|
||||
"enum_dispatch",
|
||||
@ -2757,9 +2759,9 @@ checksum = "83176759e9416cf81ee66cb6508dbfe9c96f20b8b56265a39917551c23c70964"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.19.1"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
|
||||
@ -60,4 +60,4 @@ serde_json = "1.0"
|
||||
|
||||
async-trait = "0.1"
|
||||
|
||||
tempfile = "3.19.1"
|
||||
tempfile = "3.20.0"
|
||||
|
||||
@ -357,12 +357,35 @@ pub struct BlockState {
|
||||
pub state_flags: u8,
|
||||
pub instrument: String, // TODO: make this an enum
|
||||
pub luminance: u8,
|
||||
pub piston_behavior: PistonBehavior,
|
||||
pub hardness: f32,
|
||||
pub collision_shapes: Vec<u16>,
|
||||
pub opacity: Option<u8>,
|
||||
pub block_entity_type: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum PistonBehavior {
|
||||
Normal,
|
||||
Destroy,
|
||||
Block,
|
||||
Ignore,
|
||||
PushOnly,
|
||||
}
|
||||
|
||||
impl PistonBehavior {
|
||||
fn to_tokens(&self) -> TokenStream {
|
||||
match self {
|
||||
PistonBehavior::Normal => quote! { PistonBehavior::Normal },
|
||||
PistonBehavior::Destroy => quote! { PistonBehavior::Destroy },
|
||||
PistonBehavior::Block => quote! { PistonBehavior::Block },
|
||||
PistonBehavior::Ignore => quote! { PistonBehavior::Ignore },
|
||||
PistonBehavior::PushOnly => quote! { PistonBehavior::PushOnly },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub struct BlockStateRef {
|
||||
pub id: u16,
|
||||
@ -397,6 +420,7 @@ impl BlockState {
|
||||
.collision_shapes
|
||||
.iter()
|
||||
.map(|shape_id| LitInt::new(&shape_id.to_string(), Span::call_site()));
|
||||
let piston_behavior = &self.piston_behavior.to_tokens();
|
||||
|
||||
tokens.extend(quote! {
|
||||
BlockState {
|
||||
@ -404,6 +428,7 @@ impl BlockState {
|
||||
state_flags: #state_flags,
|
||||
instrument: #instrument,
|
||||
luminance: #luminance,
|
||||
piston_behavior: #piston_behavior,
|
||||
hardness: #hardness,
|
||||
collision_shapes: &[#(#collision_shapes),*],
|
||||
opacity: #opacity,
|
||||
@ -1270,6 +1295,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
|
||||
quote! {
|
||||
use crate::{BlockState, BlockStateRef, Block, CollisionShape};
|
||||
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;
|
||||
|
||||
@ -4,6 +4,7 @@ pub struct BlockState {
|
||||
pub state_flags: u8,
|
||||
pub instrument: &'static str,
|
||||
pub luminance: u8,
|
||||
pub piston_behavior: PistonBehavior,
|
||||
pub hardness: f32,
|
||||
pub collision_shapes: &'static [u16],
|
||||
/// u8::MAX is used as None
|
||||
@ -12,6 +13,15 @@ pub struct BlockState {
|
||||
pub block_entity_type: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PistonBehavior {
|
||||
Normal,
|
||||
Destroy,
|
||||
Block,
|
||||
Ignore,
|
||||
PushOnly,
|
||||
}
|
||||
|
||||
// Add your methods here
|
||||
impl BlockState {
|
||||
pub const fn is_air(&self) -> bool {
|
||||
|
||||
@ -122,7 +122,7 @@ pub mod noise_router {
|
||||
include!(concat!(env!("OUT_DIR"), "/noise_router.rs"));
|
||||
}
|
||||
|
||||
mod block_state;
|
||||
pub mod block_state;
|
||||
mod blocks;
|
||||
mod collision_shape;
|
||||
|
||||
|
||||
@ -116,6 +116,7 @@ impl ClientPacket for CChunkData<'_> {
|
||||
// TODO: block entities
|
||||
write.write_var_int(&VarInt(self.0.block_entities.len() as i32))?;
|
||||
for block_entity in self.0.block_entities.values() {
|
||||
let block_entity = &block_entity.1;
|
||||
let chunk_data_nbt = block_entity.chunk_data_nbt();
|
||||
let pos = block_entity.get_position();
|
||||
let block_entity_id = block_entity.get_id();
|
||||
|
||||
@ -22,9 +22,11 @@ thiserror.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
log.workspace = true
|
||||
crossbeam.workspace = true
|
||||
|
||||
num-derive = "0.4"
|
||||
sha2 = "0.10"
|
||||
bitflags = "2.9.0"
|
||||
|
||||
dashmap = "6.1"
|
||||
|
||||
@ -42,13 +44,13 @@ enum_dispatch = "0.3"
|
||||
derive-getters = "0.5.0"
|
||||
|
||||
thread_local = "1.1.8"
|
||||
lru = "0.13.0"
|
||||
lru = "0.14.0"
|
||||
|
||||
tokio-util = { version = "0.7.15", features = ["rt"] }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.5", features = ["html_reports", "async_tokio"] }
|
||||
temp-dir = "0.1.14"
|
||||
temp-dir = "0.1.16"
|
||||
# Print log info inside tests when needed
|
||||
env_logger = "0.11.8"
|
||||
# Allows us to modify the config
|
||||
|
||||
@ -5,16 +5,18 @@ use barrel::BarrelBlockEntity;
|
||||
use bed::BedBlockEntity;
|
||||
use chest::ChestBlockEntity;
|
||||
use comparator::ComparatorBlockEntity;
|
||||
use piston::PistonBlockEntity;
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use sign::SignBlockEntity;
|
||||
|
||||
use crate::inventory::Inventory;
|
||||
use crate::{inventory::Inventory, world::SimpleWorld};
|
||||
|
||||
pub mod barrel;
|
||||
pub mod bed;
|
||||
pub mod chest;
|
||||
pub mod comparator;
|
||||
pub mod piston;
|
||||
pub mod sign;
|
||||
|
||||
//TODO: We need a mark_dirty for chests
|
||||
@ -24,6 +26,7 @@ pub trait BlockEntity: Send + Sync {
|
||||
fn from_nbt(nbt: &NbtCompound, position: BlockPos) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
async fn tick(&self, _world: &Arc<dyn SimpleWorld>) {}
|
||||
fn identifier(&self) -> &'static str;
|
||||
fn get_position(&self) -> BlockPos;
|
||||
async fn write_internal(&self, nbt: &mut NbtCompound) {
|
||||
@ -73,6 +76,9 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>>
|
||||
BarrelBlockEntity::ID => Some(Arc::new(block_entity_from_generic::<BarrelBlockEntity>(
|
||||
nbt,
|
||||
))),
|
||||
PistonBlockEntity::ID => Some(Arc::new(block_entity_from_generic::<PistonBlockEntity>(
|
||||
nbt,
|
||||
))),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
153
pumpkin-world/src/block/entities/piston.rs
Normal file
153
pumpkin-world/src/block/entities/piston.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use pumpkin_data::{
|
||||
Block, BlockState,
|
||||
block_properties::{get_block_by_state_id, get_state_by_state_id},
|
||||
};
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
|
||||
use crate::{
|
||||
block::BlockDirection,
|
||||
world::{BlockFlags, SimpleWorld},
|
||||
};
|
||||
|
||||
use super::BlockEntity;
|
||||
|
||||
pub struct PistonBlockEntity {
|
||||
pub position: BlockPos,
|
||||
pub pushed_block_state: BlockState,
|
||||
pub facing: BlockDirection,
|
||||
pub current_progress: AtomicCell<f32>,
|
||||
pub last_progress: AtomicCell<f32>,
|
||||
pub extending: bool,
|
||||
pub source: bool,
|
||||
}
|
||||
|
||||
impl PistonBlockEntity {
|
||||
pub const ID: &'static str = "minecraft:piston";
|
||||
|
||||
pub async fn finish(&self, world: Arc<dyn SimpleWorld>) {
|
||||
if self.last_progress.load() < 1.0 {
|
||||
let pos = self.position;
|
||||
world.remove_block_entity(&pos).await;
|
||||
if world.get_block(&pos).await.unwrap() == Block::MOVING_PISTON {
|
||||
let state = if self.source {
|
||||
Block::AIR.default_state_id
|
||||
} else {
|
||||
self.pushed_block_state.id
|
||||
};
|
||||
world
|
||||
.clone()
|
||||
.set_block_state(&pos, state, BlockFlags::NOTIFY_ALL)
|
||||
.await;
|
||||
world
|
||||
.update_neighbor(&pos, &get_block_by_state_id(state).unwrap())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FACING: &str = "facing";
|
||||
const LAST_PROGRESS: &str = "progress";
|
||||
const EXTENDING: &str = "extending";
|
||||
const SOURCE: &str = "source";
|
||||
|
||||
#[async_trait]
|
||||
impl BlockEntity for PistonBlockEntity {
|
||||
fn identifier(&self) -> &'static str {
|
||||
Self::ID
|
||||
}
|
||||
|
||||
fn get_position(&self) -> BlockPos {
|
||||
self.position
|
||||
}
|
||||
|
||||
async fn tick(&self, world: &Arc<dyn SimpleWorld>) {
|
||||
let current_progress = self.current_progress.load();
|
||||
self.last_progress.store(current_progress);
|
||||
if current_progress >= 1.0 {
|
||||
let pos = self.position;
|
||||
world.remove_block_entity(&pos).await;
|
||||
if world.get_block(&pos).await.unwrap() == Block::MOVING_PISTON {
|
||||
if self.pushed_block_state.is_air() {
|
||||
world
|
||||
.clone()
|
||||
.set_block_state(
|
||||
&pos,
|
||||
self.pushed_block_state.id,
|
||||
BlockFlags::FORCE_STATE | BlockFlags::MOVED,
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
world
|
||||
.clone()
|
||||
.set_block_state(
|
||||
&pos,
|
||||
self.pushed_block_state.id,
|
||||
BlockFlags::NOTIFY_ALL | BlockFlags::MOVED,
|
||||
)
|
||||
.await;
|
||||
world
|
||||
.clone()
|
||||
.update_neighbor(
|
||||
&pos,
|
||||
&get_block_by_state_id(self.pushed_block_state.id).unwrap(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.current_progress.store(current_progress + 0.5);
|
||||
if current_progress + 0.5 >= 1.0 {
|
||||
self.current_progress.store(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// TODO
|
||||
let pushed_block_state = get_state_by_state_id(Block::AIR.default_state_id).unwrap();
|
||||
let facing = nbt.get_byte(FACING).unwrap_or(0);
|
||||
let last_progress = nbt.get_float(LAST_PROGRESS).unwrap_or(0.0);
|
||||
let extending = nbt.get_bool(EXTENDING).unwrap_or(false);
|
||||
let source = nbt.get_bool(SOURCE).unwrap_or(false);
|
||||
Self {
|
||||
pushed_block_state,
|
||||
position,
|
||||
facing: BlockDirection::from_index(facing as u8).unwrap_or(BlockDirection::Down),
|
||||
current_progress: last_progress.into(),
|
||||
last_progress: last_progress.into(),
|
||||
extending,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
async fn write_nbt(&self, nbt: &mut pumpkin_nbt::compound::NbtCompound) {
|
||||
// TODO: pushed_block_state
|
||||
nbt.put_byte(FACING, self.facing.to_index() as i8);
|
||||
nbt.put_float(LAST_PROGRESS, self.last_progress.load());
|
||||
nbt.put_bool(EXTENDING, self.extending);
|
||||
nbt.put_bool(SOURCE, self.source);
|
||||
}
|
||||
|
||||
fn chunk_data_nbt(&self) -> Option<NbtCompound> {
|
||||
let mut nbt = NbtCompound::new();
|
||||
// TODO: pushed_block_state
|
||||
nbt.put_byte(FACING, self.facing.to_index() as i8);
|
||||
nbt.put_float(LAST_PROGRESS, self.last_progress.load());
|
||||
nbt.put_bool(EXTENDING, self.extending);
|
||||
nbt.put_bool(SOURCE, self.source);
|
||||
// TODO: duplicated code :c
|
||||
Some(nbt)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -44,6 +44,29 @@ pub struct BlockStateCodec {
|
||||
}
|
||||
|
||||
impl BlockDirection {
|
||||
pub fn to_index(&self) -> u8 {
|
||||
match self {
|
||||
BlockDirection::Down => 0,
|
||||
BlockDirection::Up => 1,
|
||||
BlockDirection::North => 2,
|
||||
BlockDirection::South => 3,
|
||||
BlockDirection::West => 4,
|
||||
BlockDirection::East => 5,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_index(index: u8) -> Option<Self> {
|
||||
match index {
|
||||
0 => Some(Self::Down),
|
||||
1 => Some(Self::Up),
|
||||
2 => Some(Self::North),
|
||||
3 => Some(Self::South),
|
||||
4 => Some(Self::West),
|
||||
5 => Some(Self::East),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_offset(&self) -> Vector3<i32> {
|
||||
match self {
|
||||
BlockDirection::Down => (0, -1, 0),
|
||||
|
||||
@ -885,7 +885,7 @@ pub async fn chunk_to_bytes(chunk_data: &ChunkData) -> Result<Vec<u8>, ChunkSeri
|
||||
block_entities: join_all(chunk_data.block_entities.values().map(
|
||||
|block_entity| async move {
|
||||
let mut nbt = NbtCompound::new();
|
||||
block_entity.write_internal(&mut nbt).await;
|
||||
block_entity.1.write_internal(&mut nbt).await;
|
||||
nbt
|
||||
},
|
||||
))
|
||||
|
||||
@ -8,7 +8,7 @@ use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
ChunkData, ChunkHeightmaps, ChunkLightEngine, ChunkParsingError, ChunkSections, ScheduledTick,
|
||||
ChunkData, ChunkHeightmaps, ChunkLight, ChunkParsingError, ChunkSections, ScheduledTick,
|
||||
SubChunk, TickPriority,
|
||||
palette::{BiomePalette, BlockPalette},
|
||||
};
|
||||
@ -82,7 +82,7 @@ impl ChunkData {
|
||||
)));
|
||||
}
|
||||
|
||||
let light_engine = ChunkLightEngine {
|
||||
let light_engine = ChunkLight {
|
||||
block_light: (0..chunk_data.sections.len() + 2)
|
||||
.map(|index| {
|
||||
chunk_data
|
||||
@ -167,7 +167,7 @@ impl ChunkData {
|
||||
for nbt in chunk_data.block_entities {
|
||||
let block_entity = block_entity_from_nbt(&nbt);
|
||||
if let Some(block_entity) = block_entity {
|
||||
block_entities.insert(block_entity.get_position(), block_entity);
|
||||
block_entities.insert(block_entity.get_position(), (nbt, block_entity));
|
||||
}
|
||||
}
|
||||
block_entities
|
||||
|
||||
@ -297,7 +297,7 @@ 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.dirty || chunk.block_entities.values().any(|block_entity| block_entity.is_dirty());
|
||||
let chunk_is_dirty = chunk.dirty || chunk.block_entities.values().any(|block_entity| block_entity.1.is_dirty());
|
||||
// Edge case: this chunk is loaded while we were saving, mark it as cleaned since we are
|
||||
// updating what we will write here
|
||||
chunk.dirty = false;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::block::entities::BlockEntity;
|
||||
use palette::{BiomePalette, BlockPalette};
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
use pumpkin_nbt::nbt_long_array;
|
||||
use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -115,8 +116,8 @@ pub struct ChunkData {
|
||||
pub position: Vector2<i32>,
|
||||
pub block_ticks: Vec<ScheduledTick>,
|
||||
pub fluid_ticks: Vec<ScheduledTick>,
|
||||
pub block_entities: HashMap<BlockPos, Arc<dyn BlockEntity>>,
|
||||
pub light_engine: ChunkLightEngine,
|
||||
pub block_entities: HashMap<BlockPos, (NbtCompound, Arc<dyn BlockEntity>)>,
|
||||
pub light_engine: ChunkLight,
|
||||
|
||||
pub dirty: bool,
|
||||
}
|
||||
@ -166,7 +167,7 @@ pub struct SubChunk {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ChunkLightEngine {
|
||||
pub struct ChunkLight {
|
||||
pub sky_light: Box<[LightContainer]>,
|
||||
pub block_light: Box<[LightContainer]>,
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use super::{
|
||||
noise_router::proto_noise_router::ProtoNoiseRouters,
|
||||
settings::{GENERATION_SETTINGS, GeneratorSetting},
|
||||
};
|
||||
use crate::chunk::ChunkLightEngine;
|
||||
use crate::chunk::ChunkLight;
|
||||
use crate::chunk::format::LightContainer;
|
||||
use crate::{
|
||||
chunk::{
|
||||
@ -81,7 +81,7 @@ impl WorldGenerator for VanillaGenerator {
|
||||
}
|
||||
|
||||
ChunkData {
|
||||
light_engine: ChunkLightEngine {
|
||||
light_engine: ChunkLight {
|
||||
sky_light: (0..sections.sections.len() + 2)
|
||||
.map(|_| LightContainer::new_filled(15))
|
||||
.collect(),
|
||||
|
||||
@ -13,6 +13,7 @@ pub mod inventory;
|
||||
pub mod item;
|
||||
pub mod level;
|
||||
mod lock;
|
||||
pub mod world;
|
||||
pub mod world_info;
|
||||
|
||||
pub type BlockId = u16;
|
||||
|
||||
62
pumpkin-world/src/world.rs
Normal file
62
pumpkin-world/src/world.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockDirection;
|
||||
use async_trait::async_trait;
|
||||
use bitflags::bitflags;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::BlockStateId;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct BlockFlags: u32 {
|
||||
const NOTIFY_NEIGHBORS = 0b000_0000_0001;
|
||||
const NOTIFY_LISTENERS = 0b000_0000_0010;
|
||||
const NOTIFY_ALL = 0b000_0000_0011;
|
||||
const FORCE_STATE = 0b000_0000_0100;
|
||||
const SKIP_DROPS = 0b000_0000_1000;
|
||||
const MOVED = 0b000_0001_0000;
|
||||
const SKIP_REDSTONE_WIRE_STATE_REPLACEMENT = 0b000_0010_0000;
|
||||
const SKIP_BLOCK_ENTITY_REPLACED_CALLBACK = 0b000_0100_0000;
|
||||
const SKIP_BLOCK_ADDED_CALLBACK = 0b000_1000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GetBlockError {
|
||||
InvalidBlockId,
|
||||
BlockOutOfWorldBounds,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GetBlockError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait SimpleWorld: Send + Sync {
|
||||
async fn set_block_state(
|
||||
self: Arc<Self>,
|
||||
position: &BlockPos,
|
||||
block_state_id: BlockStateId,
|
||||
flags: BlockFlags,
|
||||
) -> BlockStateId;
|
||||
|
||||
async fn get_block(&self, position: &BlockPos) -> Result<pumpkin_data::Block, GetBlockError>;
|
||||
|
||||
async fn update_neighbor(
|
||||
self: Arc<Self>,
|
||||
neighbor_block_pos: &BlockPos,
|
||||
source_block: &pumpkin_data::Block,
|
||||
);
|
||||
|
||||
async fn update_neighbors(
|
||||
self: Arc<Self>,
|
||||
block_pos: &BlockPos,
|
||||
except: Option<BlockDirection>,
|
||||
);
|
||||
|
||||
async fn remove_block_entity(&self, block_pos: &BlockPos);
|
||||
}
|
||||
@ -57,7 +57,7 @@ impl PumpkinBlock for BarrelBlock {
|
||||
world: &Arc<World>,
|
||||
) {
|
||||
if let Some(block_entity) = world.get_block_entity(&location).await {
|
||||
if let Some(inventory) = block_entity.get_inventory() {
|
||||
if let Some(inventory) = block_entity.1.get_inventory() {
|
||||
player
|
||||
.open_handled_screen(&BarrelScreenFactory(inventory))
|
||||
.await;
|
||||
@ -75,7 +75,7 @@ impl PumpkinBlock for BarrelBlock {
|
||||
world: &Arc<World>,
|
||||
) -> BlockActionResult {
|
||||
if let Some(block_entity) = world.get_block_entity(&location).await {
|
||||
if let Some(inventory) = block_entity.get_inventory() {
|
||||
if let Some(inventory) = block_entity.1.get_inventory() {
|
||||
player
|
||||
.open_handled_screen(&BarrelScreenFactory(inventory))
|
||||
.await;
|
||||
|
||||
@ -9,12 +9,12 @@ use pumpkin_util::GameMode;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::entity::player::Player;
|
||||
use crate::world::BlockFlags;
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
|
||||
use crate::server::Server;
|
||||
|
||||
@ -12,11 +12,11 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
#[pumpkin_block("minecraft:cactus")]
|
||||
|
||||
@ -13,10 +13,11 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::block::entities::chest::ChestBlockEntity;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::entity::EntityBase;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use crate::{
|
||||
block::{pumpkin_block::PumpkinBlock, registry::BlockActionResult},
|
||||
entity::player::Player,
|
||||
|
||||
@ -4,7 +4,6 @@ use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
@ -14,6 +13,7 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
#[pumpkin_block("minecraft:dirt_path")]
|
||||
pub struct DirtPathBlock;
|
||||
|
||||
@ -14,6 +14,7 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::block::HorizontalFacingExt;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
@ -21,7 +22,6 @@ use crate::block::blocks::redstone::block_receives_redstone_power;
|
||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::entity::player::Player;
|
||||
use crate::world::BlockFlags;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
@ -14,6 +13,7 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
#[pumpkin_block("minecraft:farmland")]
|
||||
pub struct FarmLandBlock;
|
||||
|
||||
@ -11,11 +11,11 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
use pumpkin_data::item::Item;
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_data::world::WorldEvent;
|
||||
@ -15,6 +15,7 @@ use pumpkin_data::{
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_registry::SYNCED_REGISTRIES;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
#[pumpkin_block("minecraft:jukebox")]
|
||||
pub struct JukeboxBlock;
|
||||
|
||||
@ -16,6 +16,7 @@ pub mod jukebox;
|
||||
pub mod logs;
|
||||
pub mod nether_portal;
|
||||
pub mod note;
|
||||
pub mod piston;
|
||||
pub mod pumpkin;
|
||||
pub mod redstone;
|
||||
pub mod signs;
|
||||
|
||||
@ -18,11 +18,9 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::{
|
||||
block::pumpkin_block::PumpkinBlock,
|
||||
world::{BlockFlags, World},
|
||||
};
|
||||
use crate::{block::pumpkin_block::PumpkinBlock, world::World};
|
||||
|
||||
use super::redstone::block_receives_redstone_power;
|
||||
|
||||
|
||||
238
pumpkin/src/block/blocks/piston/mod.rs
Normal file
238
pumpkin/src/block/blocks/piston/mod.rs
Normal file
@ -0,0 +1,238 @@
|
||||
use piston::PistonBlock;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::block_state::PistonBehavior;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
|
||||
use crate::world::World;
|
||||
|
||||
#[expect(clippy::module_inception)]
|
||||
pub(crate) mod piston;
|
||||
pub(crate) mod piston_extension;
|
||||
pub(crate) mod piston_head;
|
||||
|
||||
const MAX_MOVABLE_BLOCKS: usize = 12;
|
||||
|
||||
pub struct PistonHandler<'a> {
|
||||
world: &'a World,
|
||||
pos_from: BlockPos,
|
||||
retracted: bool,
|
||||
pos_to: BlockPos,
|
||||
motion_direction: BlockDirection,
|
||||
pub moved_blocks: Vec<BlockPos>,
|
||||
pub broken_blocks: Vec<BlockPos>,
|
||||
_piston_direction: BlockDirection,
|
||||
}
|
||||
|
||||
impl<'a> PistonHandler<'a> {
|
||||
pub fn new(world: &'a World, pos: BlockPos, dir: BlockDirection, retracted: bool) -> Self {
|
||||
let motion_direction;
|
||||
let pos_to = if retracted {
|
||||
motion_direction = dir;
|
||||
pos.offset_dir(dir.to_offset(), 1)
|
||||
} else {
|
||||
motion_direction = dir.opposite();
|
||||
pos.offset_dir(dir.to_offset(), 2)
|
||||
};
|
||||
PistonHandler {
|
||||
world,
|
||||
pos_from: pos,
|
||||
_piston_direction: dir,
|
||||
retracted,
|
||||
motion_direction,
|
||||
pos_to,
|
||||
moved_blocks: Vec::new(),
|
||||
broken_blocks: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn calculate_push(&mut self) -> bool {
|
||||
self.moved_blocks.clear();
|
||||
self.broken_blocks.clear();
|
||||
let (block, block_state) = self
|
||||
.world
|
||||
.get_block_and_block_state(&self.pos_to)
|
||||
.await
|
||||
.unwrap();
|
||||
if !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// self.pos_to,
|
||||
// self.motion_direction,
|
||||
// false,
|
||||
// self.piston_direction,
|
||||
) {
|
||||
if self.retracted && block_state.piston_behavior == PistonBehavior::Destroy {
|
||||
self.broken_blocks.push(self.pos_to);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if !self.try_move(self.pos_to, self.motion_direction).await {
|
||||
return false;
|
||||
}
|
||||
for block_pos in self.moved_blocks.clone() {
|
||||
let block = self.world.get_block(&block_pos).await.unwrap();
|
||||
if Self::is_block_sticky(&block)
|
||||
&& !self.try_move_adjacent_block(&block, block_pos).await
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn is_block_sticky(block: &Block) -> bool {
|
||||
block == &Block::SLIME_BLOCK || block == &Block::HONEY_BLOCK
|
||||
}
|
||||
|
||||
fn is_adjacent_block_stuck(state: &Block, adjacent_state: &Block) -> bool {
|
||||
if state == &Block::HONEY_BLOCK && adjacent_state == &Block::SLIME_BLOCK {
|
||||
return false;
|
||||
}
|
||||
if state == &Block::SLIME_BLOCK && adjacent_state == &Block::HONEY_BLOCK {
|
||||
return false;
|
||||
}
|
||||
Self::is_block_sticky(state) || Self::is_block_sticky(adjacent_state)
|
||||
}
|
||||
|
||||
async fn try_move(&mut self, pos: BlockPos, _dir: BlockDirection) -> bool {
|
||||
let (mut block, mut block_state) =
|
||||
self.world.get_block_and_block_state(&pos).await.unwrap();
|
||||
if block_state.is_air() {
|
||||
return true;
|
||||
}
|
||||
if !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// pos,
|
||||
// self.motion_direction,
|
||||
// false,
|
||||
// dir,
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if pos == self.pos_from {
|
||||
return true;
|
||||
}
|
||||
if self.moved_blocks.contains(&pos) {
|
||||
return true;
|
||||
}
|
||||
let mut i = 1;
|
||||
if i + self.moved_blocks.len() > MAX_MOVABLE_BLOCKS {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
.unwrap();
|
||||
if block_state.is_air()
|
||||
|| !Self::is_adjacent_block_stuck(&block2, &block)
|
||||
|| !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// block_pos,
|
||||
// self.motion_direction,
|
||||
// false,
|
||||
// self.motion_direction.opposite(),
|
||||
)
|
||||
|| block_pos == self.pos_from
|
||||
{
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
if i + self.moved_blocks.len() > MAX_MOVABLE_BLOCKS {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let mut j = 0;
|
||||
for k in (0..i).rev() {
|
||||
self.moved_blocks
|
||||
.push(pos.offset_dir(self.motion_direction.opposite().to_offset(), k as i32));
|
||||
j += 1;
|
||||
}
|
||||
let mut k = 1;
|
||||
loop {
|
||||
let block_pos2 = pos.offset_dir(self.motion_direction.to_offset(), k);
|
||||
if let Some(l) = self.moved_blocks.iter().position(|&p| p == block_pos2) {
|
||||
self.set_moved_blocks(j, l);
|
||||
for m in 0..=(l + j) {
|
||||
let block_pos3 = self.moved_blocks[m];
|
||||
let block = self.world.get_block(&block_pos3).await.unwrap();
|
||||
if Self::is_block_sticky(&block)
|
||||
&& !Box::pin(self.try_move_adjacent_block(&block, block_pos3)).await
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
(block, block_state) = self
|
||||
.world
|
||||
.get_block_and_block_state(&block_pos2)
|
||||
.await
|
||||
.unwrap();
|
||||
if block_state.is_air() {
|
||||
return true;
|
||||
}
|
||||
if !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// block_pos2,
|
||||
// self.motion_direction,
|
||||
// true,
|
||||
// self.motion_direction,
|
||||
) || block_pos2 == self.pos_from
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if block_state.piston_behavior == PistonBehavior::Destroy {
|
||||
self.broken_blocks.push(block_pos2);
|
||||
return true;
|
||||
}
|
||||
if self.moved_blocks.len() >= MAX_MOVABLE_BLOCKS {
|
||||
return false;
|
||||
}
|
||||
self.moved_blocks.push(block_pos2);
|
||||
j += 1;
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_moved_blocks(&mut self, from: usize, to: usize) {
|
||||
let mut list = Vec::new();
|
||||
let mut list2 = Vec::new();
|
||||
let mut list3 = Vec::new();
|
||||
list.extend_from_slice(&self.moved_blocks[0..to]);
|
||||
list2.extend_from_slice(&self.moved_blocks[self.moved_blocks.len() - from..]);
|
||||
list3.extend_from_slice(&self.moved_blocks[to..self.moved_blocks.len() - from]);
|
||||
self.moved_blocks.clear();
|
||||
self.moved_blocks.extend(list);
|
||||
self.moved_blocks.extend(list2);
|
||||
self.moved_blocks.extend(list3);
|
||||
}
|
||||
|
||||
async fn try_move_adjacent_block(&mut self, block: &Block, pos: BlockPos) -> bool {
|
||||
for direction in BlockDirection::all() {
|
||||
if direction.to_axis() == self.motion_direction.to_axis() {
|
||||
continue;
|
||||
}
|
||||
let block_pos = pos.offset(direction.to_offset());
|
||||
let block_state2 = self.world.get_block(&block_pos).await.unwrap();
|
||||
if Self::is_adjacent_block_stuck(&block_state2, block)
|
||||
&& !self.try_move(block_pos, direction).await
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
462
pumpkin/src/block/blocks/piston/piston.rs
Normal file
462
pumpkin/src/block/blocks/piston/piston.rs
Normal file
@ -0,0 +1,462 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::{
|
||||
Block, BlockState,
|
||||
block_properties::{
|
||||
BlockProperties, MovingPistonLikeProperties, PistonHeadLikeProperties, PistonType,
|
||||
get_block_by_state_id, get_state_by_state_id,
|
||||
},
|
||||
};
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{
|
||||
BlockStateId,
|
||||
block::{
|
||||
BlockDirection, FacingExt,
|
||||
entities::{BlockEntity, piston::PistonBlockEntity},
|
||||
},
|
||||
world::BlockFlags,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
block::{
|
||||
BlockIsReplacing,
|
||||
blocks::redstone::is_emitting_redstone_power,
|
||||
pumpkin_block::{BlockMetadata, PumpkinBlock},
|
||||
},
|
||||
entity::player::Player,
|
||||
server::Server,
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::{PistonHandler, piston_extension::MovingPistonProps};
|
||||
|
||||
pub(crate) type PistonProps = pumpkin_data::block_properties::StickyPistonLikeProperties;
|
||||
|
||||
pub struct PistonBlock;
|
||||
|
||||
impl BlockMetadata for PistonBlock {
|
||||
fn namespace(&self) -> &'static str {
|
||||
"minecraft"
|
||||
}
|
||||
|
||||
fn ids(&self) -> &'static [&'static str] {
|
||||
&[Block::PISTON.name, Block::STICKY_PISTON.name]
|
||||
}
|
||||
}
|
||||
|
||||
impl PistonBlock {
|
||||
pub fn is_movable(block: &Block, state: &BlockState) -> bool {
|
||||
// TODO: more checks
|
||||
if state.is_air() {
|
||||
return true;
|
||||
}
|
||||
// Vanilla hardcoded them aswell
|
||||
if block == &Block::OBSIDIAN
|
||||
|| block == &Block::CRYING_OBSIDIAN
|
||||
|| block == &Block::RESPAWN_ANCHOR
|
||||
|| block == &Block::REINFORCED_DEEPSLATE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl PumpkinBlock for PistonBlock {
|
||||
async fn on_place(
|
||||
&self,
|
||||
_server: &Server,
|
||||
_world: &World,
|
||||
player: &Player,
|
||||
block: &Block,
|
||||
_block_pos: &BlockPos,
|
||||
_face: BlockDirection,
|
||||
_replacing: BlockIsReplacing,
|
||||
_use_item_on: &SUseItemOn,
|
||||
) -> BlockStateId {
|
||||
let mut props = PistonProps::default(block);
|
||||
props.extended = false;
|
||||
props.facing = player.living_entity.entity.get_facing().opposite();
|
||||
props.to_state_id(block)
|
||||
}
|
||||
|
||||
async fn placed(
|
||||
&self,
|
||||
world: &Arc<World>,
|
||||
block: &Block,
|
||||
state_id: BlockStateId,
|
||||
pos: &BlockPos,
|
||||
old_state_id: BlockStateId,
|
||||
_notify: bool,
|
||||
) {
|
||||
if old_state_id == state_id {
|
||||
return;
|
||||
}
|
||||
try_move(world, block, pos).await;
|
||||
}
|
||||
|
||||
async fn on_neighbor_update(
|
||||
&self,
|
||||
world: &Arc<World>,
|
||||
block: &Block,
|
||||
block_pos: &BlockPos,
|
||||
_source_block: &Block,
|
||||
_notify: bool,
|
||||
) {
|
||||
try_move(world, block, block_pos).await;
|
||||
}
|
||||
|
||||
async fn on_synced_block_event(
|
||||
&self,
|
||||
block: &Block,
|
||||
world: &Arc<World>,
|
||||
pos: &BlockPos,
|
||||
r#type: u8,
|
||||
_data: u8,
|
||||
) -> bool {
|
||||
let state = world.get_block_state(pos).await.unwrap();
|
||||
let mut props = PistonProps::from_state_id(state.id, block);
|
||||
let dir = props.facing.to_block_direction();
|
||||
|
||||
// I don't think this is optimal ?
|
||||
let sticky = block == &Block::STICKY_PISTON;
|
||||
|
||||
let should_extend = should_extend(world, block, &state, pos, dir).await;
|
||||
if should_extend && (r#type == 1 || r#type == 2) {
|
||||
props.extended = true;
|
||||
world
|
||||
.set_block_state(pos, props.to_state_id(block), BlockFlags::NOTIFY_LISTENERS)
|
||||
.await;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This may prevents when something happens in the one tick before this function got called
|
||||
if !should_extend && r#type == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if r#type == 0 {
|
||||
if !move_piston(world, dir, pos, true, sticky).await {
|
||||
return false;
|
||||
}
|
||||
props.extended = true;
|
||||
world
|
||||
.set_block_state(
|
||||
pos,
|
||||
props.to_state_id(block),
|
||||
BlockFlags::NOTIFY_ALL | BlockFlags::MOVED,
|
||||
)
|
||||
.await;
|
||||
return true;
|
||||
}
|
||||
let extended_pos = pos.offset(dir.to_offset());
|
||||
|
||||
if let Some((block_entity_nbt, _block_entity)) = world.get_block_entity(&extended_pos).await
|
||||
{
|
||||
PistonBlockEntity::from_nbt(&block_entity_nbt, extended_pos)
|
||||
.finish(world.clone())
|
||||
.await;
|
||||
}
|
||||
|
||||
let mut props = MovingPistonLikeProperties::default(&Block::MOVING_PISTON);
|
||||
props.facing = dir.to_facing();
|
||||
props.r#type = if sticky {
|
||||
PistonType::Sticky
|
||||
} else {
|
||||
PistonType::Normal
|
||||
};
|
||||
|
||||
let state = props.to_state_id(&Block::MOVING_PISTON);
|
||||
|
||||
world
|
||||
.set_block_state(pos, state, BlockFlags::FORCE_STATE)
|
||||
.await;
|
||||
|
||||
world
|
||||
.add_block_entity(Arc::new(PistonBlockEntity {
|
||||
position: *pos,
|
||||
facing: dir.to_facing().to_block_direction(),
|
||||
pushed_block_state: get_state_by_state_id(state).unwrap(),
|
||||
current_progress: 0.0.into(),
|
||||
last_progress: 0.0.into(),
|
||||
extending: false,
|
||||
source: true,
|
||||
}))
|
||||
.await;
|
||||
world.update_neighbors(pos, None).await;
|
||||
if sticky {
|
||||
} else {
|
||||
world
|
||||
.set_block_state(
|
||||
&extended_pos,
|
||||
Block::AIR.default_state_id,
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async fn should_extend(
|
||||
world: &Arc<World>,
|
||||
block: &Block,
|
||||
state: &BlockState,
|
||||
block_pos: &BlockPos,
|
||||
piston_dir: BlockDirection,
|
||||
) -> bool {
|
||||
// Pistons can't be powered from the same direction as they are facing
|
||||
for dir in BlockDirection::all() {
|
||||
if dir == piston_dir
|
||||
|| !is_emitting_redstone_power(
|
||||
block,
|
||||
state,
|
||||
world,
|
||||
&block_pos.offset(dir.to_offset()),
|
||||
dir,
|
||||
)
|
||||
.await
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if is_emitting_redstone_power(block, state, world, block_pos, BlockDirection::Down).await {
|
||||
return true;
|
||||
}
|
||||
for dir in BlockDirection::all() {
|
||||
if dir == BlockDirection::Down
|
||||
|| !is_emitting_redstone_power(
|
||||
block,
|
||||
state,
|
||||
world,
|
||||
&block_pos.up().offset(dir.to_offset()),
|
||||
dir,
|
||||
)
|
||||
.await
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
|
||||
let state = world.get_block_state(block_pos).await.unwrap();
|
||||
let props = PistonProps::from_state_id(state.id, block);
|
||||
let dir = props.facing.to_block_direction();
|
||||
let should_extent = should_extend(world, block, &state, block_pos, dir).await;
|
||||
|
||||
if should_extent && !props.extended {
|
||||
if PistonHandler::new(world, *block_pos, dir, true)
|
||||
.calculate_push()
|
||||
.await
|
||||
{
|
||||
world
|
||||
.add_synced_block_event(*block_pos, 0, dir.to_index() as u8)
|
||||
.await;
|
||||
}
|
||||
} else if !should_extent && props.extended {
|
||||
let new_pos = block_pos.offset_dir(dir.to_offset(), 2);
|
||||
let (new_block, new_state) = world.get_block_and_block_state(&new_pos).await.unwrap();
|
||||
let mut r#type = 1;
|
||||
if new_block == Block::MOVING_PISTON {
|
||||
let new_props = MovingPistonProps::from_state_id(new_state.id, &new_block);
|
||||
// TODO: check more things
|
||||
if new_props.facing == props.facing {
|
||||
r#type = 2;
|
||||
}
|
||||
}
|
||||
world
|
||||
.add_synced_block_event(*block_pos, r#type, dir.to_index() as u8)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_lines)]
|
||||
async fn move_piston(
|
||||
world: &Arc<World>,
|
||||
dir: BlockDirection,
|
||||
block_pos: &BlockPos,
|
||||
extend: bool,
|
||||
sticky: bool,
|
||||
) -> bool {
|
||||
let extended_pos = block_pos.offset(dir.to_offset());
|
||||
if !extend && world.get_block(&extended_pos).await.unwrap() == Block::PISTON_HEAD {
|
||||
world
|
||||
.set_block_state(
|
||||
&extended_pos,
|
||||
Block::AIR.default_state_id,
|
||||
BlockFlags::FORCE_STATE,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
let mut handler = PistonHandler::new(world, *block_pos, dir, extend);
|
||||
if !handler.calculate_push().await {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut moved_blocks_map: HashMap<BlockPos, BlockState> = HashMap::new();
|
||||
let moved_blocks: Vec<BlockPos> = handler.moved_blocks;
|
||||
dbg!(&moved_blocks);
|
||||
|
||||
let mut moved_block_states: Vec<BlockState> = Vec::new();
|
||||
|
||||
for &block_pos in &moved_blocks {
|
||||
let block_state = world.get_block_state(&block_pos).await.unwrap();
|
||||
dbg!(block_state.id);
|
||||
moved_block_states.push(block_state.clone());
|
||||
moved_blocks_map.insert(block_pos, block_state);
|
||||
}
|
||||
|
||||
let broken_blocks: Vec<BlockPos> = handler.broken_blocks;
|
||||
dbg!(&broken_blocks);
|
||||
let mut affected_block_states: Vec<BlockState> =
|
||||
Vec::with_capacity(moved_blocks.len() + broken_blocks.len());
|
||||
let move_direction = if extend { dir } else { dir.opposite() };
|
||||
|
||||
for &broken_block_pos in broken_blocks.iter().rev() {
|
||||
let block_state = world.get_block_state(&broken_block_pos).await.unwrap();
|
||||
world
|
||||
.break_block(&broken_block_pos, None, BlockFlags::empty())
|
||||
.await;
|
||||
affected_block_states.push(block_state);
|
||||
}
|
||||
|
||||
for (index, &moved_block_pos) in moved_blocks.iter().rev().enumerate() {
|
||||
let block_state = world.get_block_state(&moved_block_pos).await.unwrap();
|
||||
let target_pos = moved_block_pos.offset(move_direction.to_offset());
|
||||
moved_blocks_map.remove(&target_pos);
|
||||
|
||||
let mut props = MovingPistonLikeProperties::default(&Block::MOVING_PISTON);
|
||||
props.facing = dir.to_facing();
|
||||
let state = props.to_state_id(&Block::MOVING_PISTON);
|
||||
|
||||
world
|
||||
.set_block_state(&target_pos, state, BlockFlags::MOVED)
|
||||
.await;
|
||||
|
||||
if let Some(moved_state) = moved_block_states.get(index) {
|
||||
world
|
||||
.add_block_entity(Arc::new(PistonBlockEntity {
|
||||
position: extended_pos,
|
||||
facing: dir.to_facing().to_block_direction(),
|
||||
pushed_block_state: moved_state.clone(),
|
||||
current_progress: 0.0.into(),
|
||||
last_progress: 0.0.into(),
|
||||
extending: extend,
|
||||
source: false,
|
||||
}))
|
||||
.await;
|
||||
}
|
||||
affected_block_states.push(block_state);
|
||||
}
|
||||
|
||||
if extend {
|
||||
let pistion_type = if sticky {
|
||||
PistonType::Sticky
|
||||
} else {
|
||||
PistonType::Normal
|
||||
};
|
||||
let mut props = MovingPistonLikeProperties::default(&Block::MOVING_PISTON);
|
||||
props.facing = dir.to_facing();
|
||||
props.r#type = pistion_type;
|
||||
moved_blocks_map.remove(&extended_pos);
|
||||
world
|
||||
.set_block_state(
|
||||
&extended_pos,
|
||||
props.to_state_id(&Block::MOVING_PISTON),
|
||||
BlockFlags::MOVED,
|
||||
)
|
||||
.await;
|
||||
let mut props = PistonHeadLikeProperties::default(&Block::PISTON_HEAD);
|
||||
props.facing = dir.to_facing();
|
||||
props.r#type = pistion_type;
|
||||
world
|
||||
.add_block_entity(Arc::new(PistonBlockEntity {
|
||||
position: extended_pos,
|
||||
facing: dir.to_facing().to_block_direction(),
|
||||
pushed_block_state: get_state_by_state_id(props.to_state_id(&Block::PISTON_HEAD))
|
||||
.unwrap(),
|
||||
current_progress: 0.0.into(),
|
||||
last_progress: 0.0.into(),
|
||||
extending: true,
|
||||
source: true,
|
||||
}))
|
||||
.await;
|
||||
}
|
||||
|
||||
let air_state = Block::AIR.default_state_id;
|
||||
for &pos in moved_blocks_map.keys() {
|
||||
world
|
||||
.set_block_state(
|
||||
&pos,
|
||||
air_state,
|
||||
BlockFlags::NOTIFY_LISTENERS | BlockFlags::FORCE_STATE | BlockFlags::MOVED,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
for (pos, state) in &moved_blocks_map {
|
||||
// state.prepare(world, pos, BlockFlags::NOTIFY_LISTENERS);
|
||||
world
|
||||
.block_registry
|
||||
.prepare(
|
||||
world,
|
||||
pos,
|
||||
&get_block_by_state_id(state.id).unwrap(),
|
||||
state.id,
|
||||
BlockFlags::NOTIFY_LISTENERS,
|
||||
)
|
||||
.await;
|
||||
world.update_neighbors(pos, None).await;
|
||||
world
|
||||
.block_registry
|
||||
.prepare(
|
||||
world,
|
||||
pos,
|
||||
&Block::AIR,
|
||||
air_state,
|
||||
BlockFlags::NOTIFY_LISTENERS,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
for (i, &broken_block_pos) in broken_blocks.iter().rev().enumerate() {
|
||||
if let Some(block_state) = affected_block_states.get(i).cloned() {
|
||||
world
|
||||
.block_registry
|
||||
.on_state_replaced(
|
||||
world,
|
||||
&get_block_by_state_id(block_state.id).unwrap(),
|
||||
broken_block_pos,
|
||||
block_state.id, // ?
|
||||
false,
|
||||
)
|
||||
.await;
|
||||
world
|
||||
.block_registry
|
||||
.prepare(
|
||||
world,
|
||||
&broken_block_pos,
|
||||
&get_block_by_state_id(block_state.id).unwrap(),
|
||||
block_state.id,
|
||||
BlockFlags::NOTIFY_LISTENERS,
|
||||
)
|
||||
.await;
|
||||
world.update_neighbors(&broken_block_pos, None).await;
|
||||
}
|
||||
}
|
||||
|
||||
for &moved_block_pos in moved_blocks.iter().rev() {
|
||||
world.update_neighbors(&moved_block_pos, None).await;
|
||||
}
|
||||
|
||||
// world.update_neighbors(&extended_pos, None).await;
|
||||
|
||||
true
|
||||
}
|
||||
46
pumpkin/src/block/blocks/piston/piston_extension.rs
Normal file
46
pumpkin/src/block/blocks/piston/piston_extension.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::block_properties::BlockProperties;
|
||||
use pumpkin_data::{Block, BlockState};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{block::FacingExt, world::BlockFlags};
|
||||
|
||||
use crate::entity::player::Player;
|
||||
use crate::{
|
||||
block::pumpkin_block::{BlockMetadata, PumpkinBlock},
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::piston::{PistonBlock, PistonProps};
|
||||
|
||||
pub(crate) type MovingPistonProps = pumpkin_data::block_properties::MovingPistonLikeProperties;
|
||||
|
||||
use crate::server::Server;
|
||||
#[pumpkin_block("minecraft:moving_piston")]
|
||||
pub struct PistonExtensionBlock;
|
||||
|
||||
#[async_trait]
|
||||
impl PumpkinBlock for PistonExtensionBlock {
|
||||
async fn broken(
|
||||
&self,
|
||||
_block: &Block,
|
||||
_player: &Arc<Player>,
|
||||
location: BlockPos,
|
||||
_server: &Server,
|
||||
world: Arc<World>,
|
||||
state: 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.unwrap();
|
||||
if PistonBlock::ids(&PistonBlock).contains(&new_block.name) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
pumpkin/src/block/blocks/piston/piston_head.rs
Normal file
10
pumpkin/src/block/blocks/piston/piston_head.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
|
||||
#[pumpkin_block("minecraft:piston_head")]
|
||||
pub struct PistonHeadBlock;
|
||||
|
||||
#[async_trait]
|
||||
impl PumpkinBlock for PistonHeadBlock {}
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::entity::item::ItemEntity;
|
||||
use crate::server::Server;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use crate::{block::registry::BlockActionResult, entity::player::Player};
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
@ -9,6 +9,7 @@ use pumpkin_data::item::Item;
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::item::ItemStack;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
#[pumpkin_block("minecraft:pumpkin")]
|
||||
pub struct PumpkinBlock;
|
||||
|
||||
@ -13,6 +13,7 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
type ButtonLikeProperties = pumpkin_data::block_properties::LeverLikeProperties;
|
||||
|
||||
@ -22,7 +23,6 @@ use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
async fn click_button(world: &Arc<World>, block_pos: &BlockPos) {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::world::BlockFlags;
|
||||
use crate::{block::BlockIsReplacing, entity::player::Player};
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::{
|
||||
@ -11,8 +10,8 @@ use pumpkin_data::{
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::{BlockDirection, HorizontalFacingExt};
|
||||
use pumpkin_world::{BlockStateId, world::BlockFlags};
|
||||
|
||||
use crate::{
|
||||
block::{pumpkin_block::PumpkinBlock, registry::BlockActionResult},
|
||||
|
||||
@ -43,20 +43,30 @@ pub async fn update_wire_neighbors(world: &Arc<World>, pos: &BlockPos) {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn is_emitting_redstone_power(
|
||||
block: &Block,
|
||||
state: &BlockState,
|
||||
world: &World,
|
||||
pos: &BlockPos,
|
||||
facing: BlockDirection,
|
||||
) -> bool {
|
||||
get_redstone_power(block, state, world, pos, facing).await > 0
|
||||
}
|
||||
|
||||
pub async fn get_redstone_power(
|
||||
block: &Block,
|
||||
state: &BlockState,
|
||||
world: &World,
|
||||
pos: BlockPos,
|
||||
pos: &BlockPos,
|
||||
facing: BlockDirection,
|
||||
) -> u8 {
|
||||
if state.is_solid() {
|
||||
return std::cmp::max(
|
||||
get_max_strong_power(world, &pos, true).await,
|
||||
get_weak_power(block, state, world, &pos, facing, true).await,
|
||||
get_max_strong_power(world, pos, true).await,
|
||||
get_weak_power(block, state, world, pos, facing, true).await,
|
||||
);
|
||||
}
|
||||
get_weak_power(block, state, world, &pos, facing, true).await
|
||||
get_weak_power(block, state, world, pos, facing, true).await
|
||||
}
|
||||
|
||||
async fn get_redstone_power_no_dust(
|
||||
@ -160,7 +170,7 @@ pub async fn block_receives_redstone_power(world: &World, pos: &BlockPos) -> boo
|
||||
.get_block_and_block_state(&neighbor_pos)
|
||||
.await
|
||||
.unwrap();
|
||||
if get_redstone_power(&block, &state, world, neighbor_pos, face).await > 0 {
|
||||
if is_emitting_redstone_power(&block, &state, world, pos, face).await {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -174,7 +184,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.unwrap();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -13,13 +13,10 @@ use pumpkin_world::{
|
||||
BlockStateId,
|
||||
block::{BlockDirection, FacingExt},
|
||||
chunk::TickPriority,
|
||||
world::BlockFlags,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
block::pumpkin_block::PumpkinBlock,
|
||||
server::Server,
|
||||
world::{BlockFlags, World},
|
||||
};
|
||||
use crate::{block::pumpkin_block::PumpkinBlock, server::Server, world::World};
|
||||
|
||||
#[pumpkin_block("minecraft:observer")]
|
||||
pub struct ObserverBlock;
|
||||
|
||||
@ -5,12 +5,12 @@ use async_trait::async_trait;
|
||||
use pumpkin_data::{Block, block_properties::BlockProperties};
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{BlockStateId, block::BlockDirection};
|
||||
use pumpkin_world::{BlockStateId, block::BlockDirection, world::BlockFlags};
|
||||
|
||||
use crate::{
|
||||
block::pumpkin_block::{BlockMetadata, PumpkinBlock},
|
||||
server::Server,
|
||||
world::{BlockFlags, World},
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::block_receives_redstone_power;
|
||||
|
||||
@ -5,13 +5,13 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
use super::RailProperties;
|
||||
|
||||
@ -5,9 +5,9 @@ use pumpkin_data::{
|
||||
block_properties::{HorizontalFacing, RailShape, StraightRailShape},
|
||||
};
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::{BlockStateId, world::BlockFlags};
|
||||
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
|
||||
use super::{HorizontalFacingRailExt, Rail, RailElevation, RailProperties, StraightRailShapeExt};
|
||||
|
||||
|
||||
@ -5,13 +5,13 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
use super::RailProperties;
|
||||
|
||||
@ -5,13 +5,13 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
use super::RailProperties;
|
||||
|
||||
@ -7,13 +7,13 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
use super::StraightRailShapeExt;
|
||||
|
||||
@ -6,13 +6,9 @@ use pumpkin_data::{Block, block_properties::BlockProperties};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{BlockStateId, block::BlockDirection, chunk::TickPriority};
|
||||
use pumpkin_world::{BlockStateId, block::BlockDirection, chunk::TickPriority, world::BlockFlags};
|
||||
|
||||
use crate::{
|
||||
block::pumpkin_block::PumpkinBlock,
|
||||
server::Server,
|
||||
world::{BlockFlags, World},
|
||||
};
|
||||
use crate::{block::pumpkin_block::PumpkinBlock, server::Server, world::World};
|
||||
|
||||
use super::block_receives_redstone_power;
|
||||
|
||||
|
||||
@ -12,13 +12,13 @@ use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::block::HorizontalFacingExt;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
type RWallTorchProps = pumpkin_data::block_properties::FurnaceLikeProperties;
|
||||
type RTorchProps = pumpkin_data::block_properties::RedstoneOreLikeProperties;
|
||||
|
||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
use super::get_redstone_power;
|
||||
@ -209,7 +209,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.unwrap();
|
||||
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) {
|
||||
|
||||
@ -13,11 +13,11 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::{BlockDirection, HorizontalFacingExt};
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::entity::player::Player;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::{block::pumpkin_block::PumpkinBlock, server::Server, world::World};
|
||||
|
||||
use super::turbo::RedstoneWireTurbo;
|
||||
|
||||
@ -9,14 +9,17 @@ use pumpkin_data::{
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::{BlockDirection, HorizontalFacingExt};
|
||||
use pumpkin_world::{BlockStateId, chunk::TickPriority};
|
||||
use pumpkin_world::{
|
||||
block::{BlockDirection, HorizontalFacingExt},
|
||||
world::BlockFlags,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
block::{BlockIsReplacing, pumpkin_block::PumpkinBlock, registry::BlockActionResult},
|
||||
entity::player::Player,
|
||||
server::Server,
|
||||
world::{BlockFlags, World},
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::{diode_get_input_strength, get_weak_power, is_diode};
|
||||
|
||||
@ -7,11 +7,11 @@ use pumpkin_data::{
|
||||
block_properties::{BlockProperties, EnumVariants, Integer0To15, RedstoneWireLikeProperties},
|
||||
};
|
||||
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::{block::BlockDirection, world::BlockFlags};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
|
||||
use super::get_redstone_power_no_dust;
|
||||
|
||||
|
||||
@ -11,11 +11,11 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::BlockIsReplacing;
|
||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
use crate::{entity::player::Player, server::Server};
|
||||
|
||||
|
||||
@ -13,11 +13,11 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
|
||||
#[pumpkin_block("minecraft:sugar_cane")]
|
||||
|
||||
@ -5,7 +5,7 @@ use crate::block::registry::BlockActionResult;
|
||||
use crate::entity::player::Player;
|
||||
use crate::entity::tnt::TNTEntity;
|
||||
use crate::server::Server;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::entity::EntityType;
|
||||
@ -15,6 +15,7 @@ use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use rand::Rng;
|
||||
|
||||
use super::redstone::block_receives_redstone_power;
|
||||
|
||||
@ -7,9 +7,9 @@ use pumpkin_data::{
|
||||
fluid::{EnumVariants, Falling, Fluid, FluidProperties, Level},
|
||||
};
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{BlockId, BlockStateId, block::BlockDirection};
|
||||
use pumpkin_world::{BlockId, BlockStateId, block::BlockDirection, world::BlockFlags};
|
||||
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
type FlowingFluidProperties = pumpkin_data::fluid::FlowingWaterLikeFluidProperties;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@ -13,6 +13,7 @@ use blocks::iron_bars::IronBarsBlock;
|
||||
use blocks::logs::LogBlock;
|
||||
use blocks::nether_portal::NetherPortalBlock;
|
||||
use blocks::note::NoteBlock;
|
||||
use blocks::piston::piston_extension::PistonExtensionBlock;
|
||||
use blocks::pumpkin::PumpkinBlock;
|
||||
use blocks::redstone::buttons::ButtonBlock;
|
||||
use blocks::redstone::observer::ObserverBlock;
|
||||
@ -101,7 +102,11 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
manager.register(ButtonBlock);
|
||||
manager.register(LeverBlock);
|
||||
manager.register(ObserverBlock);
|
||||
|
||||
// Piston
|
||||
manager.register(PistonBlock);
|
||||
manager.register(PistonExtensionBlock);
|
||||
|
||||
manager.register(RedstoneBlock);
|
||||
manager.register(RedstoneLamp);
|
||||
manager.register(RedstoneTorchBlock);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_data::{Block, BlockState};
|
||||
@ -9,6 +9,7 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::BlockIsReplacing;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use pumpkin_data::fluid::Fluid;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_data::{Block, BlockState};
|
||||
@ -9,6 +9,7 @@ use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@ -4,12 +4,12 @@ use crate::command::args::{ConsumedArgs, FindArg};
|
||||
use crate::command::tree::CommandTree;
|
||||
use crate::command::tree::builder::{argument, literal};
|
||||
use crate::command::{CommandError, CommandExecutor, CommandSender};
|
||||
use crate::world::BlockFlags;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
const NAMES: [&str; 1] = ["fill"];
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::command::args::block::BlockArgumentConsumer;
|
||||
use crate::command::args::position_block::BlockPosArgumentConsumer;
|
||||
@ -7,7 +8,6 @@ use crate::command::args::{ConsumedArgs, FindArg};
|
||||
use crate::command::tree::CommandTree;
|
||||
use crate::command::tree::builder::{argument, literal};
|
||||
use crate::command::{CommandError, CommandExecutor, CommandSender};
|
||||
use crate::world::BlockFlags;
|
||||
|
||||
const NAMES: [&str; 1] = ["setblock"];
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use crate::entity::player::Player;
|
||||
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::block_properties::BlockProperties;
|
||||
@ -10,6 +9,7 @@ use pumpkin_data::item::Item;
|
||||
use pumpkin_data::tag::Tagable;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
pub struct AxeItem;
|
||||
|
||||
|
||||
@ -8,9 +8,10 @@ use pumpkin_data::item::Item;
|
||||
use pumpkin_util::GameMode;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
|
||||
pub struct EmptyBucketItem;
|
||||
pub struct FilledBucketItem;
|
||||
|
||||
@ -3,12 +3,12 @@ use pumpkin_data::Block;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
use crate::block::blocks::fire::FireBlockBase;
|
||||
use crate::entity::player::Player;
|
||||
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
|
||||
pub struct FlintAndSteelItem;
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@ use crate::entity::item::ItemEntity;
|
||||
use crate::entity::player::Player;
|
||||
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::entity::EntityType;
|
||||
@ -11,6 +10,7 @@ use pumpkin_data::tag::Tagable;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::item::ItemStack;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct HoeItem;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use crate::entity::player::Player;
|
||||
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::block_properties::BlockProperties;
|
||||
@ -10,6 +9,7 @@ use pumpkin_data::item::Item;
|
||||
use pumpkin_data::tag::Tagable;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
pub struct HoneyCombItem;
|
||||
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
use crate::entity::player::Player;
|
||||
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||
use crate::server::Server;
|
||||
use crate::world::BlockFlags;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_data::tag::Tagable;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
|
||||
pub struct ShovelItem;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ use pumpkin_data::item::Item;
|
||||
use pumpkin_inventory::InventoryError;
|
||||
use pumpkin_inventory::equipment_slot::EquipmentSlot;
|
||||
use pumpkin_inventory::screen_handler::ScreenHandler;
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use rsa::pkcs1v15::{Signature as RsaPkcs1v15Signature, VerifyingKey};
|
||||
use rsa::signature::Verifier;
|
||||
use sha1::Sha1;
|
||||
@ -21,7 +22,7 @@ use crate::plugin::player::player_chat::PlayerChatEvent;
|
||||
use crate::plugin::player::player_command_send::PlayerCommandSendEvent;
|
||||
use crate::plugin::player::player_move::PlayerMoveEvent;
|
||||
use crate::server::seasonal_events;
|
||||
use crate::world::{BlockFlags, World};
|
||||
use crate::world::World;
|
||||
use crate::{
|
||||
command::CommandSender,
|
||||
entity::player::{ChatMode, Hand, Player},
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
use std::hash::Hash;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, atomic::Ordering},
|
||||
@ -23,7 +22,7 @@ use crate::{
|
||||
},
|
||||
server::Server,
|
||||
};
|
||||
use bitflags::bitflags;
|
||||
use async_trait::async_trait;
|
||||
use border::Worldborder;
|
||||
use bytes::{BufMut, Bytes};
|
||||
use explosion::Explosion;
|
||||
@ -42,7 +41,7 @@ use pumpkin_data::{
|
||||
world::{RAW, WorldEvent},
|
||||
};
|
||||
use pumpkin_macros::send_cancellable;
|
||||
use pumpkin_nbt::to_bytes_unnamed;
|
||||
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
|
||||
use pumpkin_protocol::client::play::{
|
||||
CBlockEvent, CRemoveMobEffect, CSetEntityMetadata, MetaDataType, Metadata,
|
||||
};
|
||||
@ -68,19 +67,20 @@ use pumpkin_registry::DimensionType;
|
||||
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
|
||||
use pumpkin_util::math::{position::chunk_section_from_pos, vector2::Vector2};
|
||||
use pumpkin_util::text::{TextComponent, color::NamedColor};
|
||||
use pumpkin_world::entity::entity_data_flags::{
|
||||
DATA_PLAYER_MAIN_HAND, DATA_PLAYER_MODE_CUSTOMISATION,
|
||||
};
|
||||
use pumpkin_world::world::BlockFlags;
|
||||
use pumpkin_world::{
|
||||
BlockStateId, GENERATION_SETTINGS, GeneratorSetting, biome, block::entities::BlockEntity,
|
||||
level::SyncChunk,
|
||||
};
|
||||
use pumpkin_world::{block::BlockDirection, chunk::ChunkData};
|
||||
use pumpkin_world::{chunk::TickPriority, level::Level};
|
||||
use pumpkin_world::{
|
||||
entity::entity_data_flags::{DATA_PLAYER_MAIN_HAND, DATA_PLAYER_MODE_CUSTOMISATION},
|
||||
world::GetBlockError,
|
||||
};
|
||||
use rand::{Rng, thread_rng};
|
||||
use scoreboard::Scoreboard;
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
use time::LevelTime;
|
||||
use tokio::sync::{RwLock, mpsc};
|
||||
use tokio::{
|
||||
@ -96,33 +96,6 @@ pub mod weather;
|
||||
|
||||
use weather::Weather;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct BlockFlags: u32 {
|
||||
const NOTIFY_NEIGHBORS = 0b000_0000_0001;
|
||||
const NOTIFY_LISTENERS = 0b000_0000_0010;
|
||||
const NOTIFY_ALL = 0b000_0000_0011;
|
||||
const FORCE_STATE = 0b000_0000_0100;
|
||||
const SKIP_DROPS = 0b000_0000_1000;
|
||||
const MOVED = 0b000_0001_0000;
|
||||
const SKIP_REDSTONE_WIRE_STATE_REPLACEMENT = 0b000_0010_0000;
|
||||
const SKIP_BLOCK_ENTITY_REPLACED_CALLBACK = 0b000_0100_0000;
|
||||
const SKIP_BLOCK_ADDED_CALLBACK = 0b000_1000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GetBlockError {
|
||||
InvalidBlockId,
|
||||
BlockOutOfWorldBounds,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GetBlockError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl PumpkinError for GetBlockError {
|
||||
fn is_kick(&self) -> bool {
|
||||
false
|
||||
@ -226,10 +199,7 @@ impl World {
|
||||
|
||||
async fn flush_synced_block_events(self: &Arc<Self>) {
|
||||
let mut queue = self.synced_block_event_queue.lock().await;
|
||||
let events: Vec<BlockEvent> = queue.drain(..).collect();
|
||||
// lets drop it here, allows us to add new things
|
||||
drop(queue);
|
||||
for event in events {
|
||||
for event in queue.drain(..) {
|
||||
let block = self.get_block(&event.pos).await.unwrap(); // TODO
|
||||
if !self
|
||||
.block_registry
|
||||
@ -1731,7 +1701,10 @@ impl World {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_block_entity(&self, block_pos: &BlockPos) -> Option<Arc<dyn BlockEntity>> {
|
||||
pub async fn get_block_entity(
|
||||
&self,
|
||||
block_pos: &BlockPos,
|
||||
) -> Option<(NbtCompound, Arc<dyn BlockEntity>)> {
|
||||
let chunk = self.get_chunk(block_pos).await;
|
||||
let chunk: tokio::sync::RwLockReadGuard<ChunkData> = chunk.read().await;
|
||||
|
||||
@ -1744,9 +1717,9 @@ impl World {
|
||||
let mut chunk: tokio::sync::RwLockWriteGuard<ChunkData> = chunk.write().await;
|
||||
let block_entity_nbt = block_entity.chunk_data_nbt();
|
||||
|
||||
if let Some(nbt) = block_entity_nbt {
|
||||
if let Some(nbt) = &block_entity_nbt {
|
||||
let mut bytes = Vec::new();
|
||||
to_bytes_unnamed(&nbt, &mut bytes).unwrap();
|
||||
to_bytes_unnamed(nbt, &mut bytes).unwrap();
|
||||
self.broadcast_packet_all(&CBlockEntityData::new(
|
||||
block_entity.get_position(),
|
||||
VarInt(block_entity.get_id() as i32),
|
||||
@ -1755,7 +1728,10 @@ impl World {
|
||||
.await;
|
||||
}
|
||||
|
||||
chunk.block_entities.insert(block_pos, block_entity);
|
||||
chunk.block_entities.insert(
|
||||
block_pos,
|
||||
(block_entity_nbt.unwrap_or_default(), block_entity),
|
||||
);
|
||||
chunk.dirty = true;
|
||||
}
|
||||
|
||||
@ -1868,3 +1844,35 @@ impl World {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl pumpkin_world::world::SimpleWorld for World {
|
||||
async fn set_block_state(
|
||||
self: Arc<Self>,
|
||||
position: &BlockPos,
|
||||
block_state_id: BlockStateId,
|
||||
flags: BlockFlags,
|
||||
) -> BlockStateId {
|
||||
Self::set_block_state(&self, position, block_state_id, flags).await
|
||||
}
|
||||
|
||||
async fn get_block(&self, position: &BlockPos) -> Result<pumpkin_data::Block, GetBlockError> {
|
||||
Self::get_block(self, position).await
|
||||
}
|
||||
|
||||
async fn update_neighbor(self: Arc<Self>, neighbor_block_pos: &BlockPos, source_block: &Block) {
|
||||
Self::update_neighbor(&self, neighbor_block_pos, source_block).await;
|
||||
}
|
||||
|
||||
async fn update_neighbors(
|
||||
self: Arc<Self>,
|
||||
block_pos: &BlockPos,
|
||||
except: Option<BlockDirection>,
|
||||
) {
|
||||
Self::update_neighbors(&self, block_pos, except).await;
|
||||
}
|
||||
|
||||
async fn remove_block_entity(&self, block_pos: &BlockPos) {
|
||||
self.remove_block_entity(block_pos).await;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user