diff --git a/README.md b/README.md index 5730fb3cb..ef6e801f8 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ and customizable experience. It prioritizes performance and player enjoyment while adhering to the core mechanics of the game.
-![chunk loading](/assets/pumpkin_chunk_loading.GIF) +![chunk loading](/assets/pumpkin_chunk_loading.webp)
@@ -35,12 +35,6 @@ and customizable experience. It prioritizes performance and player enjoyment whi - Networking - [x] Encryption - [x] Packet Compression -- Player Configuration - - [x] Registries (biome types, paintings, dimensions) - - [x] Server Brand - - [x] Server Links - - [x] Set Resource Pack - - [x] Cookies - World - [x] World Joining - [x] Player Tab-list @@ -53,7 +47,6 @@ and customizable experience. It prioritizes performance and player enjoyment whi - [x] Entity Spawning - [x] Item drops (W.I.P) - [x] Bossbar - - [x] TNT - [x] Chunk Loading (Vanilla, Linear) - [x] Chunk Generation - [x] Chunk Saving (Vanilla, Linear) @@ -64,7 +57,6 @@ and customizable experience. It prioritizes performance and player enjoyment whi - [ ] Structure Generation - Player - [x] Skins - - [x] Client brand - [x] Teleport - [x] Movement - [x] Animation diff --git a/assets/pumpkin_chunk_loading.GIF b/assets/pumpkin_chunk_loading.webp similarity index 68% rename from assets/pumpkin_chunk_loading.GIF rename to assets/pumpkin_chunk_loading.webp index e334286bc..a28912c55 100644 Binary files a/assets/pumpkin_chunk_loading.GIF and b/assets/pumpkin_chunk_loading.webp differ diff --git a/pumpkin-world/src/chunk/format/mod.rs b/pumpkin-world/src/chunk/format/mod.rs index 5ebf4b550..2e3df4c4e 100644 --- a/pumpkin-world/src/chunk/format/mod.rs +++ b/pumpkin-world/src/chunk/format/mod.rs @@ -299,9 +299,11 @@ impl ChunkEntityData { | (uuid[3] as u128), ), None => { - println!( + log::debug!( "Entity in chunk {},{} is missing UUID: {:?}", - position.x, position.y, entity_nbt + position.x, + position.y, + entity_nbt ); continue; } diff --git a/pumpkin/src/block/blocks/mod.rs b/pumpkin/src/block/blocks/mod.rs index cb2c040a2..95f625201 100644 --- a/pumpkin/src/block/blocks/mod.rs +++ b/pumpkin/src/block/blocks/mod.rs @@ -8,7 +8,6 @@ pub mod candle_cakes; pub mod candles; pub mod carpet; pub mod carved_pumpkin; -pub mod wither_skull; pub mod chain; pub mod chests; pub mod chiseled_bookshelf; @@ -54,6 +53,7 @@ pub mod torches; pub mod trapdoor; pub mod vine; pub mod walls; +pub mod wither_skull; pub mod banners; pub mod shulker_box; diff --git a/pumpkin/src/block/blocks/skull_block.rs b/pumpkin/src/block/blocks/skull_block.rs index 08b22193f..2588fd0fa 100644 --- a/pumpkin/src/block/blocks/skull_block.rs +++ b/pumpkin/src/block/blocks/skull_block.rs @@ -17,7 +17,6 @@ impl BlockMetadata for SkullBlock { fn ids(&self) -> &'static [&'static str] { &[ "skeleton_skull", - "wither_skeleton_skull", "player_head", "zombie_head", "creeper_head", diff --git a/pumpkin/src/block/blocks/wither_skull.rs b/pumpkin/src/block/blocks/wither_skull.rs index e69de29bb..6412ca648 100644 --- a/pumpkin/src/block/blocks/wither_skull.rs +++ b/pumpkin/src/block/blocks/wither_skull.rs @@ -0,0 +1,103 @@ +use pumpkin_data::{Block, BlockDirection, entity::EntityType, world::WorldEvent}; +use pumpkin_world::{BlockStateId, world::BlockFlags}; + +use crate::{ + block::{ + BlockBehaviour, BlockFuture, BlockMetadata, OnPlaceArgs, PlacedArgs, + blocks::skull_block::SkullBlock, + }, + entity::{Entity, boss::wither::WitherEntity}, +}; + +pub struct WitherSkeletonSkullBlock; + +impl BlockMetadata for WitherSkeletonSkullBlock { + fn namespace(&self) -> &'static str { + "minecraft" + } + + fn ids(&self) -> &'static [&'static str] { + &[Block::WITHER_SKELETON_SKULL.name] + } +} + +impl BlockBehaviour for WitherSkeletonSkullBlock { + fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { + SkullBlock::on_place(&SkullBlock, args) + } + + fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { + Box::pin(async move { + let world = args.world; + let pos = args.position; + + let is_soul_block = + |block: &Block| block == &Block::SOUL_SAND || block == &Block::SOUL_SOIL; + let is_skull = |block: &Block| block == &Block::WITHER_SKELETON_SKULL; + + for dir in [BlockDirection::North, BlockDirection::West] { + let opposite = dir.opposite(); + for offset in 0..3 { + let center_skull_pos = match offset { + 0 => *pos, + 1 => pos.offset(opposite.to_offset()), + 2 => pos.offset(dir.to_offset()), + _ => unreachable!(), + }; + + let top_middle = center_skull_pos.down(); + let base = top_middle.down(); + let arm1 = top_middle.offset(dir.to_offset()); + let arm2 = top_middle.offset(opposite.to_offset()); + let skull1_pos = arm1.up(); + let skull2_pos = arm2.up(); + + if is_soul_block(world.get_block(&top_middle).await) + && is_soul_block(world.get_block(&base).await) + && is_soul_block(world.get_block(&arm1).await) + && is_soul_block(world.get_block(&arm2).await) + && is_skull(world.get_block(¢er_skull_pos).await) + && is_skull(world.get_block(&skull1_pos).await) + && is_skull(world.get_block(&skull2_pos).await) + { + let pattern = [ + center_skull_pos, + skull1_pos, + skull2_pos, + top_middle, + arm1, + arm2, + base, + ]; + + for p in pattern { + world + .set_block_state( + &p, + Block::AIR.default_state.id, + BlockFlags::NOTIFY_ALL, + ) + .await; + world + .sync_world_event( + WorldEvent::BlockBroken, + p, + Block::SOUL_SAND.default_state.id.into(), + ) + .await; + } + + let entity = Entity::new( + world.clone(), + top_middle.to_centered_f64(), + &EntityType::WITHER, + ); + let wither = WitherEntity::make(entity).await; + world.spawn_entity(wither).await; + return; + } + } + } + }) + } +} diff --git a/pumpkin/src/block/registry.rs b/pumpkin/src/block/registry.rs index b4fa62fca..c5e24c279 100644 --- a/pumpkin/src/block/registry.rs +++ b/pumpkin/src/block/registry.rs @@ -76,6 +76,7 @@ use crate::block::blocks::torches::TorchBlock; use crate::block::blocks::trapdoor::TrapDoorBlock; use crate::block::blocks::vine::VineBlock; use crate::block::blocks::walls::WallBlock; +use crate::block::blocks::wither_skull::WitherSkeletonSkullBlock; use crate::block::fluid::lava::FlowingLava; use crate::block::fluid::water::FlowingWater; use crate::block::{ @@ -153,6 +154,7 @@ pub fn default_registry() -> Arc { manager.register(CactusBlock); manager.register(CarpetBlock); manager.register(CarvedPumpkinBlock); + manager.register(WitherSkeletonSkullBlock); manager.register(CampfireBlock); manager.register(MossCarpetBlock); manager.register(PaleMossCarpetBlock); diff --git a/pumpkin/src/entity/boss/mod.rs b/pumpkin/src/entity/boss/mod.rs new file mode 100644 index 000000000..4ad811449 --- /dev/null +++ b/pumpkin/src/entity/boss/mod.rs @@ -0,0 +1 @@ +pub mod wither; diff --git a/pumpkin/src/entity/boss/wither.rs b/pumpkin/src/entity/boss/wither.rs new file mode 100644 index 000000000..01bf35d8f --- /dev/null +++ b/pumpkin/src/entity/boss/wither.rs @@ -0,0 +1,46 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{look_around::LookAroundGoal, look_at_entity::LookAtEntityGoal}, + mob::{Mob, MobEntity}, +}; + +pub struct WitherEntity { + pub mob_entity: MobEntity, +} + +impl WitherEntity { + pub async fn make(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let wither = Self { mob_entity }; + let mob_arc = Arc::new(wither); + let mob_weak: Weak = { + let mob_arc: Arc = mob_arc.clone(); + Arc::downgrade(&mob_arc) + }; + + { + let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; + + // TODO + goal_selector.add_goal( + 8, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(8, Box::new(LookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for WitherEntity {} + +impl Mob for WitherEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index a8abb1357..6463d3b51 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -54,6 +54,7 @@ use tokio::sync::Mutex; use uuid::Uuid; pub mod ai; +pub mod boss; pub mod decoration; pub mod effect; pub mod experience_orb; diff --git a/pumpkin/src/entity/type.rs b/pumpkin/src/entity/type.rs index 87b0b5ebe..d64e21264 100644 --- a/pumpkin/src/entity/type.rs +++ b/pumpkin/src/entity/type.rs @@ -7,6 +7,7 @@ use uuid::Uuid; use crate::{ entity::{ Entity, EntityBase, + boss::wither::WitherEntity, decoration::{ armor_stand::ArmorStandEntity, end_crystal::EndCrystalEntity, painting::PaintingEntity, }, @@ -35,6 +36,7 @@ pub async fn from_type( id if id == EntityType::CREEPER.id => CreeperEntity::make(entity).await, id if id == EntityType::SNOW_GOLEM.id => SnowGolemEntity::make(entity).await, id if id == EntityType::WOLF.id => WolfEntity::make(entity).await, + id if id == EntityType::WITHER.id => WitherEntity::make(entity).await, id if id == EntityType::ARMOR_STAND.id => Arc::new(ArmorStandEntity::new(entity)), id if id == EntityType::PAINTING.id => Arc::new(PaintingEntity::new(entity)), id if id == EntityType::END_CRYSTAL.id => Arc::new(EndCrystalEntity::new(entity)),