feat: Spawners now work for generated Structures
This commit is contained in:
parent
e312c4cbd9
commit
4aaaea7cc7
@ -36,7 +36,7 @@ impl MobSpawnerBlockEntity {
|
|||||||
pub const DEFAULT_SPAWN_RANGE: i32 = 4;
|
pub const DEFAULT_SPAWN_RANGE: i32 = 4;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(position: BlockPos) -> Self {
|
pub const fn new(position: BlockPos, entity_type: Option<&'static EntityType>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
position,
|
position,
|
||||||
delay: AtomicI32::new(Self::DEFAULT_DELAY),
|
delay: AtomicI32::new(Self::DEFAULT_DELAY),
|
||||||
@ -44,7 +44,26 @@ impl MobSpawnerBlockEntity {
|
|||||||
min_delay: Self::DEFAULT_MIN_SPAWN_DELAY,
|
min_delay: Self::DEFAULT_MIN_SPAWN_DELAY,
|
||||||
spawn_count: Self::DEFAULT_SPAWN_COUNT,
|
spawn_count: Self::DEFAULT_SPAWN_COUNT,
|
||||||
spawn_range: Self::DEFAULT_SPAWN_RANGE,
|
spawn_range: Self::DEFAULT_SPAWN_RANGE,
|
||||||
entity_type: AtomicCell::new(None),
|
entity_type: AtomicCell::new(entity_type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_nbt<'a>(&'a self, nbt: &'a mut NbtCompound) {
|
||||||
|
// TODO: this is ugly af
|
||||||
|
nbt.put_string("id", self.resource_location().to_string());
|
||||||
|
let position = self.get_position();
|
||||||
|
nbt.put_int("x", position.0.x);
|
||||||
|
nbt.put_int("y", position.0.y);
|
||||||
|
nbt.put_int("z", position.0.z);
|
||||||
|
if let Some(entity_type) = self.entity_type.load() {
|
||||||
|
let mut spawn_entry = NbtCompound::new();
|
||||||
|
|
||||||
|
let mut entity_nbt = NbtCompound::new();
|
||||||
|
entity_nbt.put_string("id", format!("minecraft:{}", entity_type.resource_name));
|
||||||
|
|
||||||
|
spawn_entry.put_compound("entity", entity_nbt);
|
||||||
|
|
||||||
|
nbt.put_compound("SpawnData", spawn_entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +170,15 @@ impl BlockEntity for MobSpawnerBlockEntity {
|
|||||||
let spawn_range = nbt
|
let spawn_range = nbt
|
||||||
.get_int("SpawnRange")
|
.get_int("SpawnRange")
|
||||||
.unwrap_or(Self::DEFAULT_SPAWN_RANGE);
|
.unwrap_or(Self::DEFAULT_SPAWN_RANGE);
|
||||||
let _spawn_entry = nbt.get_compound("SpawnData");
|
|
||||||
|
let entity_type = nbt
|
||||||
|
.get_compound("SpawnData")
|
||||||
|
.and_then(|data| data.get_compound("entity"))
|
||||||
|
.and_then(|entity| entity.get_string("id"))
|
||||||
|
.and_then(|id| {
|
||||||
|
let name = id.strip_prefix("minecraft:").unwrap_or(id);
|
||||||
|
EntityType::from_name(name)
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
position,
|
position,
|
||||||
@ -160,7 +187,7 @@ impl BlockEntity for MobSpawnerBlockEntity {
|
|||||||
min_delay,
|
min_delay,
|
||||||
spawn_count,
|
spawn_count,
|
||||||
spawn_range,
|
spawn_range,
|
||||||
entity_type: AtomicCell::new(None), // TODO
|
entity_type: AtomicCell::new(entity_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +196,7 @@ impl BlockEntity for MobSpawnerBlockEntity {
|
|||||||
nbt: &'a mut NbtCompound,
|
nbt: &'a mut NbtCompound,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let Some(entity_type) = self.entity_type.load() {
|
self.write_nbt(nbt);
|
||||||
let mut entity_nbt = NbtCompound::new();
|
|
||||||
entity_nbt.put_string("id", format!("minecraft:{}", entity_type.resource_name));
|
|
||||||
|
|
||||||
nbt.put_compound("entity", entity_nbt);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
|||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
use pumpkin_data::fluid::{Fluid, FluidState};
|
use pumpkin_data::fluid::{Fluid, FluidState};
|
||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState};
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
use pumpkin_util::HeightMap;
|
use pumpkin_util::HeightMap;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
@ -205,6 +206,29 @@ impl GenerationCache for Cache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_block_entity(&mut self, pos: &Vector3<i32>, nbt: NbtCompound) {
|
||||||
|
let dx = (pos.x >> 4) - self.x;
|
||||||
|
let dz = (pos.z >> 4) - self.z;
|
||||||
|
// debug_assert!(dx < self.size && dz < self.size);
|
||||||
|
// debug_assert!(dx >= 0 && dz >= 0);
|
||||||
|
if !(dx < self.size && dz < self.size && dx >= 0 && dz >= 0) {
|
||||||
|
// breakpoint here
|
||||||
|
debug!(
|
||||||
|
"illegal set_block_state {pos:?} cache pos ({}, {}) size {}",
|
||||||
|
self.x, self.z, self.size
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match &mut self.chunks[(dx * self.size + dz) as usize] {
|
||||||
|
Chunk::Level(_data) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
Chunk::Proto(data) => {
|
||||||
|
data.add_block_entity(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32 {
|
fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32 {
|
||||||
match heightmap {
|
match heightmap {
|
||||||
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z),
|
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z),
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
use pumpkin_data::{Block, BlockDirection};
|
use pumpkin_data::{Block, BlockDirection, entity::EntityType};
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::{position::BlockPos, vector3::Vector3},
|
math::{position::BlockPos, vector3::Vector3},
|
||||||
random::{RandomGenerator, RandomImpl},
|
random::{RandomGenerator, RandomImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::generation::proto_chunk::GenerationCache;
|
use crate::{
|
||||||
|
block::entities::mob_spawner::MobSpawnerBlockEntity, generation::proto_chunk::GenerationCache,
|
||||||
|
};
|
||||||
|
|
||||||
/// The three mob types that can appear in a dungeon spawner.
|
/// The three mob types that can appear in a dungeon spawner.
|
||||||
///
|
///
|
||||||
@ -143,8 +146,12 @@ impl DungeonFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: set spawner entity type
|
// TODO: set spawner entity type
|
||||||
let _ = DUNGEON_MOBS[random.next_bounded_i32(DUNGEON_MOBS.len() as i32) as usize];
|
let mob = DUNGEON_MOBS[random.next_bounded_i32(DUNGEON_MOBS.len() as i32) as usize];
|
||||||
chunk.set_block_state(&pos.0, Block::SPAWNER.default_state);
|
chunk.set_block_state(&pos.0, Block::SPAWNER.default_state);
|
||||||
|
let spawner_block_entity = MobSpawnerBlockEntity::new(pos, EntityType::from_name(mob));
|
||||||
|
let mut entity_nbt = NbtCompound::new();
|
||||||
|
spawner_block_entity.write_nbt(&mut entity_nbt);
|
||||||
|
chunk.add_block_entity(&pos.0, entity_nbt);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ pub trait GenerationCache: HeightLimitView + BlockAccessor {
|
|||||||
fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState;
|
fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState;
|
||||||
fn get_fluid_and_fluid_state(&self, position: &Vector3<i32>) -> (Fluid, FluidState);
|
fn get_fluid_and_fluid_state(&self, position: &Vector3<i32>) -> (Fluid, FluidState);
|
||||||
fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState);
|
fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState);
|
||||||
|
fn add_block_entity(&mut self, pos: &Vector3<i32>, nbt: NbtCompound);
|
||||||
fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32;
|
fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32;
|
||||||
fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32;
|
fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32;
|
||||||
fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32;
|
fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32;
|
||||||
@ -350,7 +351,7 @@ impl ProtoChunk {
|
|||||||
/// Adds a pending block entity to be created when the chunk is finalized.
|
/// Adds a pending block entity to be created when the chunk is finalized.
|
||||||
///
|
///
|
||||||
/// The NBT compound should include the block entity's position (x, y, z) and id fields.
|
/// The NBT compound should include the block entity's position (x, y, z) and id fields.
|
||||||
pub fn add_pending_block_entity(&mut self, nbt: NbtCompound) {
|
pub fn add_block_entity(&mut self, nbt: NbtCompound) {
|
||||||
self.pending_block_entities.push(nbt);
|
self.pending_block_entities.push(nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,18 @@
|
|||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
Block,
|
Block,
|
||||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||||
|
entity::EntityType,
|
||||||
|
};
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::{
|
||||||
|
BlockDirection,
|
||||||
|
math::{block_box::BlockBox, position::BlockPos},
|
||||||
|
random::RandomGenerator,
|
||||||
};
|
};
|
||||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ProtoChunk,
|
ProtoChunk,
|
||||||
|
block::entities::mob_spawner::MobSpawnerBlockEntity,
|
||||||
generation::structure::{
|
generation::structure::{
|
||||||
piece::StructurePieceType,
|
piece::StructurePieceType,
|
||||||
structures::{
|
structures::{
|
||||||
@ -140,7 +147,11 @@ impl StructurePieceBase for BridgePlatformPiece {
|
|||||||
spawner_pos.z,
|
spawner_pos.z,
|
||||||
Block::SPAWNER.default_state,
|
Block::SPAWNER.default_state,
|
||||||
);
|
);
|
||||||
// TODO: set spawner entity type to Blaze via block entity data
|
let spawner_block_entity =
|
||||||
|
MobSpawnerBlockEntity::new(BlockPos(spawner_pos), Some(&EntityType::BLAZE));
|
||||||
|
let mut entity_nbt = NbtCompound::new();
|
||||||
|
spawner_block_entity.write_nbt(&mut entity_nbt);
|
||||||
|
chunk.add_block_entity(entity_nbt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,15 +4,18 @@ use pumpkin_data::{
|
|||||||
BlockProperties, EndPortalFrameLikeProperties, HorizontalFacing, OakFenceLikeProperties,
|
BlockProperties, EndPortalFrameLikeProperties, HorizontalFacing, OakFenceLikeProperties,
|
||||||
OakStairsLikeProperties,
|
OakStairsLikeProperties,
|
||||||
},
|
},
|
||||||
|
entity::EntityType,
|
||||||
};
|
};
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
BlockDirection,
|
BlockDirection,
|
||||||
math::block_box::BlockBox,
|
math::{block_box::BlockBox, position::BlockPos},
|
||||||
random::{RandomGenerator, RandomImpl},
|
random::{RandomGenerator, RandomImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ProtoChunk,
|
ProtoChunk,
|
||||||
|
block::entities::mob_spawner::MobSpawnerBlockEntity,
|
||||||
generation::structure::{
|
generation::structure::{
|
||||||
piece::StructurePieceType,
|
piece::StructurePieceType,
|
||||||
structures::{
|
structures::{
|
||||||
@ -355,8 +358,11 @@ impl StructurePieceBase for PortalRoomPiece {
|
|||||||
self.spawner_placed = true;
|
self.spawner_placed = true;
|
||||||
let spawner = Block::SPAWNER.default_state;
|
let spawner = Block::SPAWNER.default_state;
|
||||||
inner.add_block(chunk, spawner, 5, 3, 6, &box_limit);
|
inner.add_block(chunk, spawner, 5, 3, 6, &box_limit);
|
||||||
// Note: You must check your engine's API to set the BlockEntity (Silverfish).
|
let spawner_block_entity =
|
||||||
// Example: chunk.set_block_entity(pos, BlockEntity::Spawner(EntityType::Silverfish));
|
MobSpawnerBlockEntity::new(BlockPos(pos), Some(&EntityType::SILVERFISH));
|
||||||
|
let mut entity_nbt = NbtCompound::new();
|
||||||
|
spawner_block_entity.write_nbt(&mut entity_nbt);
|
||||||
|
chunk.add_block_entity(entity_nbt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,10 +96,10 @@ pub fn place_template(
|
|||||||
let block_entity_id = block_entity_id.unwrap_or(&palette_entry.name);
|
let block_entity_id = block_entity_id.unwrap_or(&palette_entry.name);
|
||||||
let mut block_entity_nbt = NbtCompound::new();
|
let mut block_entity_nbt = NbtCompound::new();
|
||||||
|
|
||||||
|
block_entity_nbt.put_string("id", block_entity_id.to_string());
|
||||||
block_entity_nbt.put_int("x", wx);
|
block_entity_nbt.put_int("x", wx);
|
||||||
block_entity_nbt.put_int("y", wy);
|
block_entity_nbt.put_int("y", wy);
|
||||||
block_entity_nbt.put_int("z", wz);
|
block_entity_nbt.put_int("z", wz);
|
||||||
block_entity_nbt.put_string("id", block_entity_id.to_string());
|
|
||||||
|
|
||||||
if let Some(template_nbt) = &block.nbt {
|
if let Some(template_nbt) = &block.nbt {
|
||||||
for (key, value) in &template_nbt.child_tags {
|
for (key, value) in &template_nbt.child_tags {
|
||||||
@ -111,7 +111,7 @@ pub fn place_template(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.add_pending_block_entity(block_entity_nbt);
|
chunk.add_block_entity(block_entity_nbt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ pub struct SpawnerBlock;
|
|||||||
impl BlockBehaviour for SpawnerBlock {
|
impl BlockBehaviour for SpawnerBlock {
|
||||||
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let hopper_block_entity = MobSpawnerBlockEntity::new(*args.position);
|
let hopper_block_entity = MobSpawnerBlockEntity::new(*args.position, None);
|
||||||
args.world
|
args.world
|
||||||
.add_block_entity(Arc::new(hopper_block_entity))
|
.add_block_entity(Arc::new(hopper_block_entity))
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user