From 6f2c3cd5e37a3c39e1e5f27c1300d31bd97fe936 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Tue, 28 Apr 2026 21:29:27 +0200 Subject: [PATCH] feat: implement all missing entities --- pumpkin-world/src/chunk/format/mod.rs | 59 ++-- pumpkin/src/entity/mob/blaze.rs | 9 +- pumpkin/src/entity/mob/breeze.rs | 56 ++++ pumpkin/src/entity/mob/cave_spider.rs | 26 ++ pumpkin/src/entity/mob/creaking.rs | 58 ++++ pumpkin/src/entity/mob/elder_guardian.rs | 56 ++++ pumpkin/src/entity/mob/endermite.rs | 58 ++++ pumpkin/src/entity/mob/evoker.rs | 65 +++++ pumpkin/src/entity/mob/ghast.rs | 50 ++++ pumpkin/src/entity/mob/giant.rs | 49 ++++ pumpkin/src/entity/mob/guardian.rs | 68 +++++ pumpkin/src/entity/mob/hoglin.rs | 58 ++++ pumpkin/src/entity/mob/illusioner.rs | 64 +++++ pumpkin/src/entity/mob/magma_cube.rs | 25 ++ pumpkin/src/entity/mob/mod.rs | 25 ++ pumpkin/src/entity/mob/phantom.rs | 50 ++++ pumpkin/src/entity/mob/piglin.rs | 71 +++++ pumpkin/src/entity/mob/piglin_brute.rs | 70 +++++ pumpkin/src/entity/mob/pillager.rs | 67 +++++ pumpkin/src/entity/mob/ravager.rs | 66 +++++ pumpkin/src/entity/mob/silverfish.rs | 27 +- pumpkin/src/entity/mob/skeleton/mod.rs | 11 +- pumpkin/src/entity/mob/slime.rs | 41 ++- pumpkin/src/entity/mob/spider.rs | 64 +++++ pumpkin/src/entity/mob/vex.rs | 58 ++++ pumpkin/src/entity/mob/vindicator.rs | 66 +++++ pumpkin/src/entity/mob/warden.rs | 58 ++++ pumpkin/src/entity/mob/witch.rs | 59 ++++ pumpkin/src/entity/mob/zoglin.rs | 58 ++++ pumpkin/src/entity/mob/zombie/husk.rs | 21 +- pumpkin/src/entity/mob/zombie/mod.rs | 8 +- pumpkin/src/entity/mob/zombified_piglin.rs | 57 ++++ pumpkin/src/entity/passive/allay.rs | 53 ++++ pumpkin/src/entity/passive/armadillo.rs | 53 ++++ pumpkin/src/entity/passive/axolotl.rs | 53 ++++ pumpkin/src/entity/passive/bee.rs | 53 ++++ pumpkin/src/entity/passive/camel.rs | 53 ++++ pumpkin/src/entity/passive/cat.rs | 11 +- pumpkin/src/entity/passive/chicken.rs | 52 +++- pumpkin/src/entity/passive/cod.rs | 53 ++++ pumpkin/src/entity/passive/cow.rs | 55 +++- pumpkin/src/entity/passive/dolphin.rs | 53 ++++ pumpkin/src/entity/passive/donkey.rs | 53 ++++ pumpkin/src/entity/passive/fox.rs | 60 +++++ pumpkin/src/entity/passive/frog.rs | 53 ++++ pumpkin/src/entity/passive/glow_squid.rs | 53 ++++ pumpkin/src/entity/passive/goat.rs | 53 ++++ pumpkin/src/entity/passive/horse.rs | 53 ++++ pumpkin/src/entity/passive/iron_golem.rs | 27 +- pumpkin/src/entity/passive/llama.rs | 53 ++++ pumpkin/src/entity/passive/mod.rs | 34 +++ pumpkin/src/entity/passive/mooshroom.rs | 53 ++++ pumpkin/src/entity/passive/mule.rs | 53 ++++ pumpkin/src/entity/passive/ocelot.rs | 53 ++++ pumpkin/src/entity/passive/panda.rs | 53 ++++ pumpkin/src/entity/passive/parrot.rs | 53 ++++ pumpkin/src/entity/passive/pig.rs | 66 ++++- pumpkin/src/entity/passive/polar_bear.rs | 60 +++++ pumpkin/src/entity/passive/pufferfish.rs | 53 ++++ pumpkin/src/entity/passive/rabbit.rs | 57 ++++ pumpkin/src/entity/passive/salmon.rs | 50 ++++ pumpkin/src/entity/passive/sheep.rs | 54 +++- pumpkin/src/entity/passive/skeleton_horse.rs | 50 ++++ pumpkin/src/entity/passive/sniffer.rs | 50 ++++ pumpkin/src/entity/passive/snow_golem.rs | 24 +- pumpkin/src/entity/passive/squid.rs | 52 ++++ pumpkin/src/entity/passive/strider.rs | 50 ++++ pumpkin/src/entity/passive/tadpole.rs | 50 ++++ pumpkin/src/entity/passive/trader_llama.rs | 50 ++++ pumpkin/src/entity/passive/tropical_fish.rs | 50 ++++ pumpkin/src/entity/passive/turtle.rs | 54 ++++ pumpkin/src/entity/passive/villager.rs | 55 ++++ .../src/entity/passive/wandering_trader.rs | 50 ++++ pumpkin/src/entity/passive/wolf.rs | 19 +- pumpkin/src/entity/passive/zombie_horse.rs | 50 ++++ pumpkin/src/entity/type.rs | 254 +++++++++++++++--- 76 files changed, 3838 insertions(+), 131 deletions(-) create mode 100644 pumpkin/src/entity/mob/breeze.rs create mode 100644 pumpkin/src/entity/mob/cave_spider.rs create mode 100644 pumpkin/src/entity/mob/creaking.rs create mode 100644 pumpkin/src/entity/mob/elder_guardian.rs create mode 100644 pumpkin/src/entity/mob/endermite.rs create mode 100644 pumpkin/src/entity/mob/evoker.rs create mode 100644 pumpkin/src/entity/mob/ghast.rs create mode 100644 pumpkin/src/entity/mob/giant.rs create mode 100644 pumpkin/src/entity/mob/guardian.rs create mode 100644 pumpkin/src/entity/mob/hoglin.rs create mode 100644 pumpkin/src/entity/mob/illusioner.rs create mode 100644 pumpkin/src/entity/mob/magma_cube.rs create mode 100644 pumpkin/src/entity/mob/phantom.rs create mode 100644 pumpkin/src/entity/mob/piglin.rs create mode 100644 pumpkin/src/entity/mob/piglin_brute.rs create mode 100644 pumpkin/src/entity/mob/pillager.rs create mode 100644 pumpkin/src/entity/mob/ravager.rs create mode 100644 pumpkin/src/entity/mob/spider.rs create mode 100644 pumpkin/src/entity/mob/vex.rs create mode 100644 pumpkin/src/entity/mob/vindicator.rs create mode 100644 pumpkin/src/entity/mob/warden.rs create mode 100644 pumpkin/src/entity/mob/witch.rs create mode 100644 pumpkin/src/entity/mob/zoglin.rs create mode 100644 pumpkin/src/entity/mob/zombified_piglin.rs create mode 100644 pumpkin/src/entity/passive/allay.rs create mode 100644 pumpkin/src/entity/passive/armadillo.rs create mode 100644 pumpkin/src/entity/passive/axolotl.rs create mode 100644 pumpkin/src/entity/passive/bee.rs create mode 100644 pumpkin/src/entity/passive/camel.rs create mode 100644 pumpkin/src/entity/passive/cod.rs create mode 100644 pumpkin/src/entity/passive/dolphin.rs create mode 100644 pumpkin/src/entity/passive/donkey.rs create mode 100644 pumpkin/src/entity/passive/fox.rs create mode 100644 pumpkin/src/entity/passive/frog.rs create mode 100644 pumpkin/src/entity/passive/glow_squid.rs create mode 100644 pumpkin/src/entity/passive/goat.rs create mode 100644 pumpkin/src/entity/passive/horse.rs create mode 100644 pumpkin/src/entity/passive/llama.rs create mode 100644 pumpkin/src/entity/passive/mooshroom.rs create mode 100644 pumpkin/src/entity/passive/mule.rs create mode 100644 pumpkin/src/entity/passive/ocelot.rs create mode 100644 pumpkin/src/entity/passive/panda.rs create mode 100644 pumpkin/src/entity/passive/parrot.rs create mode 100644 pumpkin/src/entity/passive/polar_bear.rs create mode 100644 pumpkin/src/entity/passive/pufferfish.rs create mode 100644 pumpkin/src/entity/passive/rabbit.rs create mode 100644 pumpkin/src/entity/passive/salmon.rs create mode 100644 pumpkin/src/entity/passive/skeleton_horse.rs create mode 100644 pumpkin/src/entity/passive/sniffer.rs create mode 100644 pumpkin/src/entity/passive/squid.rs create mode 100644 pumpkin/src/entity/passive/strider.rs create mode 100644 pumpkin/src/entity/passive/tadpole.rs create mode 100644 pumpkin/src/entity/passive/trader_llama.rs create mode 100644 pumpkin/src/entity/passive/tropical_fish.rs create mode 100644 pumpkin/src/entity/passive/turtle.rs create mode 100644 pumpkin/src/entity/passive/villager.rs create mode 100644 pumpkin/src/entity/passive/wandering_trader.rs create mode 100644 pumpkin/src/entity/passive/zombie_horse.rs diff --git a/pumpkin-world/src/chunk/format/mod.rs b/pumpkin-world/src/chunk/format/mod.rs index 2c6ac3b89..c8303be42 100644 --- a/pumpkin-world/src/chunk/format/mod.rs +++ b/pumpkin-world/src/chunk/format/mod.rs @@ -113,38 +113,43 @@ impl ChunkData { position.x, position.y, chunk_data.x_pos, chunk_data.z_pos, ))); } - let section_count = chunk_data.sections.len(); - let mut block_lights = Vec::with_capacity(section_count); - let mut sky_lights = Vec::with_capacity(section_count); - let mut block_palettes = Vec::with_capacity(section_count); - let mut biome_palettes = Vec::with_capacity(section_count); + let min_y_section = chunk_data.min_y_section; + let max_y_section = chunk_data + .sections + .iter() + .map(|s| s.y) + .max() + .unwrap_or(min_y_section as i8); + + let section_count = (max_y_section as i32 - min_y_section + 1).max(0) as usize; + let mut block_lights = vec![LightContainer::Empty(0); section_count]; + let mut sky_lights = vec![LightContainer::Empty(0); section_count]; + let mut block_palettes = vec![BlockPalette::default(); section_count]; + let mut biome_palettes = vec![BiomePalette::default(); section_count]; for section in chunk_data.sections { + let index = (section.y as i32 - min_y_section) as usize; + if index >= section_count { + continue; + } + // When loading light data, missing data should default to 0 (no light) - block_lights.push( - section - .block_light - .map_or(LightContainer::Empty(0), LightContainer::Full), - ); - sky_lights.push( - section - .sky_light - .map_or(LightContainer::Empty(0), LightContainer::Full), - ); + block_lights[index] = section + .block_light + .map_or(LightContainer::Empty(0), LightContainer::Full); + sky_lights[index] = section + .sky_light + .map_or(LightContainer::Empty(0), LightContainer::Full); // Convert NBT to Palettes - block_palettes.push( - section - .block_states - .map(BlockPalette::from_disk_nbt) - .unwrap_or_default(), - ); - biome_palettes.push( - section - .biomes - .map(BiomePalette::from_disk_nbt) - .unwrap_or_default(), - ); + block_palettes[index] = section + .block_states + .map(BlockPalette::from_disk_nbt) + .unwrap_or_default(); + biome_palettes[index] = section + .biomes + .map(BiomePalette::from_disk_nbt) + .unwrap_or_default(); } // Assemble the LightEngine diff --git a/pumpkin/src/entity/mob/blaze.rs b/pumpkin/src/entity/mob/blaze.rs index 5edb4c895..a734379a2 100644 --- a/pumpkin/src/entity/mob/blaze.rs +++ b/pumpkin/src/entity/mob/blaze.rs @@ -6,7 +6,8 @@ use crate::entity::{ Entity, NBTStorage, ai::goal::{ active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, - look_at_entity::LookAtEntityGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, }; @@ -28,12 +29,16 @@ impl BlazeEntity { let mut goal_selector = mob_arc.entity.goals_selector.lock().await; let mut target_selector = mob_arc.entity.target_selector.lock().await; - // TODO + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // TODO: BlazeShootFireballGoal + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, false))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( 8, LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), ); goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); + target_selector.add_goal( 2, ActiveTargetGoal::with_default(&mob_arc.entity, &EntityType::PLAYER, true), diff --git a/pumpkin/src/entity/mob/breeze.rs b/pumpkin/src/entity/mob/breeze.rs new file mode 100644 index 000000000..8938e3ac4 --- /dev/null +++ b/pumpkin/src/entity/mob/breeze.rs @@ -0,0 +1,56 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct BreezeEntity { + pub mob_entity: MobEntity, +} + +impl BreezeEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let breeze = Self { mob_entity }; + let mob_arc = Arc::new(breeze); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for BreezeEntity {} + +impl Mob for BreezeEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/cave_spider.rs b/pumpkin/src/entity/mob/cave_spider.rs new file mode 100644 index 000000000..7a5a5dbb4 --- /dev/null +++ b/pumpkin/src/entity/mob/cave_spider.rs @@ -0,0 +1,26 @@ +use std::sync::Arc; + +use crate::entity::{ + Entity, NBTStorage, + mob::{Mob, MobEntity, spider::SpiderEntity}, +}; + +pub struct CaveSpiderEntity { + pub spider: Arc, +} + +impl CaveSpiderEntity { + pub async fn new(entity: Entity) -> Arc { + let spider = SpiderEntity::new(entity).await; + Arc::new(Self { spider }) + } +} + +impl NBTStorage for CaveSpiderEntity {} + +impl Mob for CaveSpiderEntity { + fn get_mob_entity(&self) -> &MobEntity { + self.spider.get_mob_entity() + } + // TODO: Poison effect on attack +} diff --git a/pumpkin/src/entity/mob/creaking.rs b/pumpkin/src/entity/mob/creaking.rs new file mode 100644 index 000000000..66f36d4d9 --- /dev/null +++ b/pumpkin/src/entity/mob/creaking.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct CreakingEntity { + pub mob_entity: MobEntity, +} + +impl CreakingEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let creaking = Self { mob_entity }; + let mob_arc = Arc::new(creaking); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for CreakingEntity {} + +impl Mob for CreakingEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/elder_guardian.rs b/pumpkin/src/entity/mob/elder_guardian.rs new file mode 100644 index 000000000..48f90cb3b --- /dev/null +++ b/pumpkin/src/entity/mob/elder_guardian.rs @@ -0,0 +1,56 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct ElderGuardianEntity { + pub mob_entity: MobEntity, +} + +impl ElderGuardianEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let guardian = Self { mob_entity }; + let mob_arc = Arc::new(guardian); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 5, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for ElderGuardianEntity {} + +impl Mob for ElderGuardianEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/endermite.rs b/pumpkin/src/entity/mob/endermite.rs new file mode 100644 index 000000000..68aac38fa --- /dev/null +++ b/pumpkin/src/entity/mob/endermite.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct EndermiteEntity { + pub mob_entity: MobEntity, +} + +impl EndermiteEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let endermite = Self { mob_entity }; + let mob_arc = Arc::new(endermite); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for EndermiteEntity {} + +impl Mob for EndermiteEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/evoker.rs b/pumpkin/src/entity/mob/evoker.rs new file mode 100644 index 000000000..3d8d9a3c9 --- /dev/null +++ b/pumpkin/src/entity/mob/evoker.rs @@ -0,0 +1,65 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct EvokerEntity { + pub mob_entity: MobEntity, +} + +impl EvokerEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let evoker = Self { mob_entity }; + let mob_arc = Arc::new(evoker); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // Evokers have complex spell AI, but for now basic movement + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::VILLAGER, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::IRON_GOLEM, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for EvokerEntity {} + +impl Mob for EvokerEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/ghast.rs b/pumpkin/src/entity/mob/ghast.rs new file mode 100644 index 000000000..01e6f1492 --- /dev/null +++ b/pumpkin/src/entity/mob/ghast.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal}, + mob::{Mob, MobEntity}, +}; + +pub struct GhastEntity { + pub mob_entity: MobEntity, +} + +impl GhastEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let ghast = Self { mob_entity }; + let mob_arc = Arc::new(ghast); + 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: GhastFlyGoal, GhastLookGoal, GhastAttackGoal + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for GhastEntity {} + +impl Mob for GhastEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } + + fn get_mob_gravity(&self) -> f64 { + 0.0 + } +} diff --git a/pumpkin/src/entity/mob/giant.rs b/pumpkin/src/entity/mob/giant.rs new file mode 100644 index 000000000..52e5a427f --- /dev/null +++ b/pumpkin/src/entity/mob/giant.rs @@ -0,0 +1,49 @@ +use std::sync::Arc; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + melee_attack::MeleeAttackGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct GiantEntity { + pub mob_entity: MobEntity, +} + +impl GiantEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let giant = Self { mob_entity }; + let mob_arc = Arc::new(giant); + + { + let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for GiantEntity {} + +impl Mob for GiantEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/guardian.rs b/pumpkin/src/entity/mob/guardian.rs new file mode 100644 index 000000000..ba867d038 --- /dev/null +++ b/pumpkin/src/entity/mob/guardian.rs @@ -0,0 +1,68 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct GuardianEntity { + pub mob_entity: MobEntity, +} + +impl GuardianEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let guardian = Self { mob_entity }; + let mob_arc = Arc::new(guardian); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 5, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::SQUID, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::GLOW_SQUID, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::AXOLOTL, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for GuardianEntity {} + +impl Mob for GuardianEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/hoglin.rs b/pumpkin/src/entity/mob/hoglin.rs new file mode 100644 index 000000000..bfb48b58f --- /dev/null +++ b/pumpkin/src/entity/mob/hoglin.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct HoglinEntity { + pub mob_entity: MobEntity, +} + +impl HoglinEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let hoglin = Self { mob_entity }; + let mob_arc = Arc::new(hoglin); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for HoglinEntity {} + +impl Mob for HoglinEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/illusioner.rs b/pumpkin/src/entity/mob/illusioner.rs new file mode 100644 index 000000000..79a49c535 --- /dev/null +++ b/pumpkin/src/entity/mob/illusioner.rs @@ -0,0 +1,64 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct IllusionerEntity { + pub mob_entity: MobEntity, +} + +impl IllusionerEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let illusioner = Self { mob_entity }; + let mob_arc = Arc::new(illusioner); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::VILLAGER, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::IRON_GOLEM, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for IllusionerEntity {} + +impl Mob for IllusionerEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/magma_cube.rs b/pumpkin/src/entity/mob/magma_cube.rs new file mode 100644 index 000000000..106bf2216 --- /dev/null +++ b/pumpkin/src/entity/mob/magma_cube.rs @@ -0,0 +1,25 @@ +use std::sync::Arc; + +use crate::entity::{ + Entity, NBTStorage, + mob::{Mob, MobEntity, slime::SlimeEntity}, +}; + +pub struct MagmaCubeEntity { + pub slime: Arc, +} + +impl MagmaCubeEntity { + pub async fn new(entity: Entity) -> Arc { + let slime = SlimeEntity::new(entity).await; + Arc::new(Self { slime }) + } +} + +impl NBTStorage for MagmaCubeEntity {} + +impl Mob for MagmaCubeEntity { + fn get_mob_entity(&self) -> &MobEntity { + self.slime.get_mob_entity() + } +} diff --git a/pumpkin/src/entity/mob/mod.rs b/pumpkin/src/entity/mob/mod.rs index 5a3ac9d8e..c7d083795 100644 --- a/pumpkin/src/entity/mob/mod.rs +++ b/pumpkin/src/entity/mob/mod.rs @@ -27,13 +27,37 @@ use uuid::Uuid; pub mod bat; pub mod blaze; +pub mod breeze; +pub mod cave_spider; +pub mod creaking; pub mod creeper; +pub mod elder_guardian; pub mod enderman; +pub mod endermite; +pub mod evoker; +pub mod ghast; +pub mod giant; +pub mod guardian; +pub mod hoglin; +pub mod illusioner; +pub mod magma_cube; +pub mod phantom; +pub mod piglin; +pub mod piglin_brute; +pub mod pillager; +pub mod ravager; pub mod shulker; pub mod silverfish; pub mod skeleton; pub mod slime; +pub mod spider; +pub mod vex; +pub mod vindicator; +pub mod warden; +pub mod witch; +pub mod zoglin; pub mod zombie; +pub mod zombified_piglin; pub struct MobEntity { pub living_entity: LivingEntity, @@ -78,6 +102,7 @@ impl MobEntity { last_sent_head_yaw: AtomicU8::new(0), } } + pub fn is_in_position_target_range(&self) -> bool { self.is_in_position_target_range_pos(&self.living_entity.entity.block_pos.load()) } diff --git a/pumpkin/src/entity/mob/phantom.rs b/pumpkin/src/entity/mob/phantom.rs new file mode 100644 index 000000000..463ab18b0 --- /dev/null +++ b/pumpkin/src/entity/mob/phantom.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal}, + mob::{Mob, MobEntity}, +}; + +pub struct PhantomEntity { + pub mob_entity: MobEntity, +} + +impl PhantomEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let phantom = Self { mob_entity }; + let mob_arc = Arc::new(phantom); + 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: PhantomCircleAroundAnchorGoal, PhantomSweepAttackGoal + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for PhantomEntity {} + +impl Mob for PhantomEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } + + fn get_mob_gravity(&self) -> f64 { + 0.0 + } +} diff --git a/pumpkin/src/entity/mob/piglin.rs b/pumpkin/src/entity/mob/piglin.rs new file mode 100644 index 000000000..a7f2c69b0 --- /dev/null +++ b/pumpkin/src/entity/mob/piglin.rs @@ -0,0 +1,71 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct PiglinEntity { + pub mob_entity: MobEntity, +} + +impl PiglinEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let piglin = Self { mob_entity }; + let mob_arc = Arc::new(piglin); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // Piglins use crossbows or swords, but for now we give them melee + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default( + &mob_arc.mob_entity, + &EntityType::WITHER_SKELETON, + true, + ), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::WITHER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for PiglinEntity {} + +impl Mob for PiglinEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/piglin_brute.rs b/pumpkin/src/entity/mob/piglin_brute.rs new file mode 100644 index 000000000..efa3b3078 --- /dev/null +++ b/pumpkin/src/entity/mob/piglin_brute.rs @@ -0,0 +1,70 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct PiglinBruteEntity { + pub mob_entity: MobEntity, +} + +impl PiglinBruteEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let piglin = Self { mob_entity }; + let mob_arc = Arc::new(piglin); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default( + &mob_arc.mob_entity, + &EntityType::WITHER_SKELETON, + true, + ), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::WITHER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for PiglinBruteEntity {} + +impl Mob for PiglinBruteEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/pillager.rs b/pumpkin/src/entity/mob/pillager.rs new file mode 100644 index 000000000..aa4dca959 --- /dev/null +++ b/pumpkin/src/entity/mob/pillager.rs @@ -0,0 +1,67 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct PillagerEntity { + pub mob_entity: MobEntity, +} + +impl PillagerEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let pillager = Self { mob_entity }; + let mob_arc = Arc::new(pillager); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // Pillagers use crossbows, but for now we give them melee + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::VILLAGER, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::IRON_GOLEM, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for PillagerEntity {} + +impl Mob for PillagerEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/ravager.rs b/pumpkin/src/entity/mob/ravager.rs new file mode 100644 index 000000000..8bdc99c46 --- /dev/null +++ b/pumpkin/src/entity/mob/ravager.rs @@ -0,0 +1,66 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct RavagerEntity { + pub mob_entity: MobEntity, +} + +impl RavagerEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let ravager = Self { mob_entity }; + let mob_arc = Arc::new(ravager); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::VILLAGER, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::IRON_GOLEM, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for RavagerEntity {} + +impl Mob for RavagerEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/silverfish.rs b/pumpkin/src/entity/mob/silverfish.rs index 629f4e5e7..bb0c9923e 100644 --- a/pumpkin/src/entity/mob/silverfish.rs +++ b/pumpkin/src/entity/mob/silverfish.rs @@ -1,10 +1,14 @@ -use std::sync::Arc; +use std::sync::{Arc, Weak}; use pumpkin_data::entity::EntityType; use crate::entity::{ Entity, NBTStorage, - ai::goal::active_target::ActiveTargetGoal, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, mob::{Mob, MobEntity}, }; @@ -15,13 +19,26 @@ pub struct SilverfishEntity { impl SilverfishEntity { pub async fn new(entity: Entity) -> Arc { let entity = Arc::new(MobEntity::new(entity)); - let zombie = Self { entity }; - let mob_arc = Arc::new(zombie); + let silverfish = Self { entity }; + let mob_arc = Arc::new(silverfish); + let mob_weak: Weak = { + let mob_arc: Arc = mob_arc.clone(); + Arc::downgrade(&mob_arc) + }; { + let mut goal_selector = mob_arc.entity.goals_selector.lock().await; let mut target_selector = mob_arc.entity.target_selector.lock().await; - // TODO + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, false))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 8, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); + target_selector.add_goal( 2, ActiveTargetGoal::with_default(&mob_arc.entity, &EntityType::PLAYER, true), diff --git a/pumpkin/src/entity/mob/skeleton/mod.rs b/pumpkin/src/entity/mob/skeleton/mod.rs index 55389c3ea..c4d10b698 100644 --- a/pumpkin/src/entity/mob/skeleton/mod.rs +++ b/pumpkin/src/entity/mob/skeleton/mod.rs @@ -6,7 +6,8 @@ use crate::entity::{ Entity, NBTStorage, ai::goal::{ active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, - look_at_entity::LookAtEntityGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, revenge::RevengeGoal, + swim::SwimGoal, wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, }; @@ -35,12 +36,16 @@ impl SkeletonEntityBase { let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.2, false))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( - 8, + 6, LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), ); - goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + target_selector.add_goal(1, Box::new(RevengeGoal::new(true))); target_selector.add_goal( 2, ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), diff --git a/pumpkin/src/entity/mob/slime.rs b/pumpkin/src/entity/mob/slime.rs index 0ef0f59b7..b630b1f3f 100644 --- a/pumpkin/src/entity/mob/slime.rs +++ b/pumpkin/src/entity/mob/slime.rs @@ -1,10 +1,15 @@ -use std::sync::Arc; use std::sync::atomic::Ordering::Relaxed; +use std::sync::{Arc, Weak}; +use pumpkin_data::entity::EntityType; use pumpkin_data::sound::Sound; use crate::entity::{ Entity, NBTStorage, NbtFuture, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, mob::{Mob, MobEntity}, }; @@ -13,10 +18,36 @@ pub struct SlimeEntity { } impl SlimeEntity { - pub fn new(entity: Entity) -> Arc { - Arc::new(Self { - entity: Arc::new(MobEntity::new(entity)), - }) + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let slime = Self { + entity: Arc::new(mob_entity), + }; + let mob_arc = Arc::new(slime); + let mob_weak: Weak = { + let mob_arc: Arc = mob_arc.clone(); + Arc::downgrade(&mob_arc) + }; + + { + let mut goal_selector = mob_arc.entity.goals_selector.lock().await; + let mut target_selector = mob_arc.entity.target_selector.lock().await; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc } pub(crate) const fn hurt_sound_for_size(size: i32) -> Sound { diff --git a/pumpkin/src/entity/mob/spider.rs b/pumpkin/src/entity/mob/spider.rs new file mode 100644 index 000000000..0e7092073 --- /dev/null +++ b/pumpkin/src/entity/mob/spider.rs @@ -0,0 +1,64 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, revenge::RevengeGoal, + swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct SpiderEntity { + pub mob_entity: MobEntity, +} + +impl SpiderEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let spider = Self { mob_entity }; + let mob_arc = Arc::new(spider); + 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; + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + + goal_selector.add_goal(1, Box::new(SwimGoal::default())); + // TODO: SpiderAttackGoal for jumping + goal_selector.add_goal(3, Box::new(MeleeAttackGoal::new(1.0, false))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(0.8))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + + target_selector.add_goal(1, Box::new(RevengeGoal::new(true))); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::IRON_GOLEM, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for SpiderEntity {} + +impl Mob for SpiderEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/vex.rs b/pumpkin/src/entity/mob/vex.rs new file mode 100644 index 000000000..f62fdb95c --- /dev/null +++ b/pumpkin/src/entity/mob/vex.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct VexEntity { + pub mob_entity: MobEntity, +} + +impl VexEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let vex = Self { mob_entity }; + let mob_arc = Arc::new(vex); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for VexEntity {} + +impl Mob for VexEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/vindicator.rs b/pumpkin/src/entity/mob/vindicator.rs new file mode 100644 index 000000000..b575f8a9d --- /dev/null +++ b/pumpkin/src/entity/mob/vindicator.rs @@ -0,0 +1,66 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct VindicatorEntity { + pub mob_entity: MobEntity, +} + +impl VindicatorEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let vindicator = Self { mob_entity }; + let mob_arc = Arc::new(vindicator); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::VILLAGER, true), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::IRON_GOLEM, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for VindicatorEntity {} + +impl Mob for VindicatorEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/warden.rs b/pumpkin/src/entity/mob/warden.rs new file mode 100644 index 000000000..0b7e2fbf4 --- /dev/null +++ b/pumpkin/src/entity/mob/warden.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct WardenEntity { + pub mob_entity: MobEntity, +} + +impl WardenEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let warden = Self { mob_entity }; + let mob_arc = Arc::new(warden); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(0.5))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for WardenEntity {} + +impl Mob for WardenEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/witch.rs b/pumpkin/src/entity/mob/witch.rs new file mode 100644 index 000000000..643b3a85d --- /dev/null +++ b/pumpkin/src/entity/mob/witch.rs @@ -0,0 +1,59 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, revenge::RevengeGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct WitchEntity { + pub mob_entity: MobEntity, +} + +impl WitchEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let witch = Self { mob_entity }; + let mob_arc = Arc::new(witch); + 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; + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + + goal_selector.add_goal(1, Box::new(SwimGoal::default())); + // TODO: WitchAttackGoal (potions) + goal_selector.add_goal(2, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 3, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + + target_selector.add_goal(1, Box::new(RevengeGoal::new(true))); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for WitchEntity {} + +impl Mob for WitchEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/zoglin.rs b/pumpkin/src/entity/mob/zoglin.rs new file mode 100644 index 000000000..510746fd1 --- /dev/null +++ b/pumpkin/src/entity/mob/zoglin.rs @@ -0,0 +1,58 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct ZoglinEntity { + pub mob_entity: MobEntity, +} + +impl ZoglinEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let zoglin = Self { mob_entity }; + let mob_arc = Arc::new(zoglin); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(4, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for ZoglinEntity {} + +impl Mob for ZoglinEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/mob/zombie/husk.rs b/pumpkin/src/entity/mob/zombie/husk.rs index 761b01c7b..bc6b94d10 100644 --- a/pumpkin/src/entity/mob/zombie/husk.rs +++ b/pumpkin/src/entity/mob/zombie/husk.rs @@ -1,11 +1,8 @@ use std::sync::Arc; -use pumpkin_data::entity::EntityType; - use crate::entity::mob::zombie::ZombieEntityBase; use crate::entity::{ Entity, NBTStorage, - ai::goal::active_target::ActiveTargetGoal, mob::{Mob, MobEntity}, }; @@ -17,23 +14,7 @@ impl HuskEntity { pub async fn new(entity: Entity) -> Arc { let entity = ZombieEntityBase::new(entity).await; let zombie = Self { entity }; - let mob_arc = Arc::new(zombie); - - { - let mut target_selector = mob_arc.entity.mob_entity.target_selector.lock().await; - - // TODO - target_selector.add_goal( - 2, - ActiveTargetGoal::with_default( - &mob_arc.entity.mob_entity, - &EntityType::PLAYER, - true, - ), - ); - }; - - mob_arc + Arc::new(zombie) } } diff --git a/pumpkin/src/entity/mob/zombie/mod.rs b/pumpkin/src/entity/mob/zombie/mod.rs index d18202b24..689d83585 100644 --- a/pumpkin/src/entity/mob/zombie/mod.rs +++ b/pumpkin/src/entity/mob/zombie/mod.rs @@ -1,6 +1,9 @@ use super::{Mob, MobEntity}; use crate::entity::ai::goal::destroy_egg::DestroyEggGoal; use crate::entity::ai::goal::look_around::RandomLookAroundGoal; +use crate::entity::ai::goal::revenge::RevengeGoal; +use crate::entity::ai::goal::swim::SwimGoal; +use crate::entity::ai::goal::wander_around::WanderAroundGoal; use crate::entity::ai::goal::zombie_attack::ZombieAttackGoal; use crate::entity::{ Entity, NBTStorage, @@ -33,14 +36,17 @@ impl ZombieEntityBase { let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, ZombieAttackGoal::new(1.0, false)); goal_selector.add_goal(4, DestroyEggGoal::new(1.0, 3)); + goal_selector.add_goal(7, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( 8, LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), ); goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); - goal_selector.add_goal(3, ZombieAttackGoal::new(1.0, false)); + target_selector.add_goal(1, Box::new(RevengeGoal::new(true))); target_selector.add_goal( 2, ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, true), diff --git a/pumpkin/src/entity/mob/zombified_piglin.rs b/pumpkin/src/entity/mob/zombified_piglin.rs new file mode 100644 index 000000000..cd9e72a73 --- /dev/null +++ b/pumpkin/src/entity/mob/zombified_piglin.rs @@ -0,0 +1,57 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, + melee_attack::MeleeAttackGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct ZombifiedPiglinEntity { + pub mob_entity: MobEntity, +} + +impl ZombifiedPiglinEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let piglin = Self { mob_entity }; + let mob_arc = Arc::new(piglin); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + + let _target_selector = mob_arc.mob_entity.target_selector.lock().await; + // Zombified piglins are neutral by default (only attack if hit), + // but for now we give it ActiveTargetGoal for players to make them hostile + // (or we can leave it empty for neutral behavior). + // Let's make them neutral for now (no ActiveTargetGoal). + }; + + mob_arc + } +} + +impl NBTStorage for ZombifiedPiglinEntity {} + +impl Mob for ZombifiedPiglinEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/allay.rs b/pumpkin/src/entity/passive/allay.rs new file mode 100644 index 000000000..8b5cff350 --- /dev/null +++ b/pumpkin/src/entity/passive/allay.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents an Allay, a passive, flying entity that can collect items for the player. +/// +/// Wiki: +pub struct AllayEntity { + pub mob_entity: MobEntity, +} + +impl AllayEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let allay = Self { mob_entity }; + let mob_arc = Arc::new(allay); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for AllayEntity {} + +impl Mob for AllayEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/armadillo.rs b/pumpkin/src/entity/passive/armadillo.rs new file mode 100644 index 000000000..a3f30048a --- /dev/null +++ b/pumpkin/src/entity/passive/armadillo.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents an Armadillo, a passive entity that can roll into a ball when threatened. +/// +/// Wiki: +pub struct ArmadilloEntity { + pub mob_entity: MobEntity, +} + +impl ArmadilloEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let armadillo = Self { mob_entity }; + let mob_arc = Arc::new(armadillo); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for ArmadilloEntity {} + +impl Mob for ArmadilloEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/axolotl.rs b/pumpkin/src/entity/passive/axolotl.rs new file mode 100644 index 000000000..897301d18 --- /dev/null +++ b/pumpkin/src/entity/passive/axolotl.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents an Axolotl, a passive aquatic mob that can play dead to regenerate health. +/// +/// Wiki: +pub struct AxolotlEntity { + pub mob_entity: MobEntity, +} + +impl AxolotlEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let axolotl = Self { mob_entity }; + let mob_arc = Arc::new(axolotl); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for AxolotlEntity {} + +impl Mob for AxolotlEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/bee.rs b/pumpkin/src/entity/passive/bee.rs new file mode 100644 index 000000000..ef20a4f64 --- /dev/null +++ b/pumpkin/src/entity/passive/bee.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Bee, a neutral flying mob that can pollinate crops and sting attackers. +/// +/// Wiki: +pub struct BeeEntity { + pub mob_entity: MobEntity, +} + +impl BeeEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let bee = Self { mob_entity }; + let mob_arc = Arc::new(bee); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for BeeEntity {} + +impl Mob for BeeEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/camel.rs b/pumpkin/src/entity/passive/camel.rs new file mode 100644 index 000000000..da63bbe71 --- /dev/null +++ b/pumpkin/src/entity/passive/camel.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Camel, a passive mount that can carry two players and dash. +/// +/// Wiki: +pub struct CamelEntity { + pub mob_entity: MobEntity, +} + +impl CamelEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let camel = Self { mob_entity }; + let mob_arc = Arc::new(camel); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for CamelEntity {} + +impl Mob for CamelEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/cat.rs b/pumpkin/src/entity/passive/cat.rs index 1838e693d..96ccd9567 100644 --- a/pumpkin/src/entity/passive/cat.rs +++ b/pumpkin/src/entity/passive/cat.rs @@ -5,7 +5,8 @@ use pumpkin_data::{entity::EntityType, item::Item}; use crate::entity::{ Entity, NBTStorage, ai::goal::{ - escape_danger::EscapeDangerGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal, + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, tempt::TemptGoal, wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, @@ -13,6 +14,9 @@ use crate::entity::{ const TEMPT_ITEMS: &[&Item] = &[&Item::COD, &Item::SALMON]; +/// Represents a Cat, a passive mob that can be tamed and scares away creepers. +/// +/// Wiki: pub struct CatEntity { pub mob_entity: MobEntity, } @@ -32,12 +36,17 @@ impl CatEntity { goal_selector.add_goal(1, Box::new(SwimGoal::default())); goal_selector.add_goal(1, EscapeDangerGoal::new(1.5)); + // goal_selector.add_goal(2, SitGoal::new(mob_arc.clone())); goal_selector.add_goal(4, Box::new(TemptGoal::new(0.6, TEMPT_ITEMS))); + goal_selector.add_goal(5, BreedGoal::new(0.8)); + // goal_selector.add_goal(7, FollowOwnerGoal::new(1.0, 10.0, 5.0, false)); + goal_selector.add_goal(9, Box::new(FollowParentGoal::new(0.8))); goal_selector.add_goal(11, Box::new(WanderAroundGoal::new(0.8))); goal_selector.add_goal( 12, LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 10.0), ); + goal_selector.add_goal(12, Box::new(RandomLookAroundGoal::default())); }; mob_arc diff --git a/pumpkin/src/entity/passive/chicken.rs b/pumpkin/src/entity/passive/chicken.rs index e4933d15a..7c6a505a3 100644 --- a/pumpkin/src/entity/passive/chicken.rs +++ b/pumpkin/src/entity/passive/chicken.rs @@ -4,17 +4,21 @@ use std::sync::{ }; use pumpkin_data::item_stack::ItemStack; +use pumpkin_data::particle::Particle; +use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::{entity::EntityType, item::Item}; +use pumpkin_util::math::vector3::Vector3; use rand::RngExt; use crate::entity::{ Entity, EntityBase, EntityBaseFuture, NBTStorage, ai::goal::{ - escape_danger::EscapeDangerGoal, look_around::RandomLookAroundGoal, - look_at_entity::LookAtEntityGoal, swim::SwimGoal, tempt::TemptGoal, - wander_around::WanderAroundGoal, + breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal, + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + tempt::TemptGoal, wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, + player::Player, }; const TEMPT_ITEMS: &[&Item] = &[ @@ -26,6 +30,9 @@ const TEMPT_ITEMS: &[&Item] = &[ &Item::PITCHER_POD, ]; +/// Represents a Chicken, a passive mob that lays eggs and is immune to fall damage. +/// +/// Wiki: pub struct ChickenEntity { pub mob_entity: MobEntity, egg_lay_time: AtomicI32, @@ -50,7 +57,9 @@ impl ChickenEntity { goal_selector.add_goal(0, Box::new(SwimGoal::default())); goal_selector.add_goal(1, EscapeDangerGoal::new(1.4)); + goal_selector.add_goal(2, BreedGoal::new(1.0)); goal_selector.add_goal(3, Box::new(TemptGoal::new(1.0, TEMPT_ITEMS))); + goal_selector.add_goal(4, Box::new(FollowParentGoal::new(1.1))); goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( 6, @@ -85,4 +94,41 @@ impl Mob for ChickenEntity { } }) } + + fn mob_interact<'a>( + &'a self, + player: &'a Player, + item_stack: &'a mut ItemStack, + ) -> EntityBaseFuture<'a, bool> { + Box::pin(async move { + let is_food = TEMPT_ITEMS.iter().any(|i| i.id == item_stack.item.id); + if is_food && self.is_breeding_ready() && !self.is_in_love() { + item_stack.decrement_unless_creative(player.gamemode.load(), 1); + + self.mob_entity.set_love_ticks(600); + let entity = &self.mob_entity.living_entity.entity; + let world = entity.world.load(); + let pos = entity.pos.load(); + + world + .spawn_particle( + pos + Vector3::new(0.0, f64::from(entity.height()), 0.0), + Vector3::new(0.5, 0.5, 0.5), + 1.0, + 7, + Particle::Heart, + ) + .await; + world + .play_sound( + Sound::EntityChickenAmbient, + SoundCategory::Neutral, + &entity.pos.load(), + ) + .await; + return true; + } + false + }) + } } diff --git a/pumpkin/src/entity/passive/cod.rs b/pumpkin/src/entity/passive/cod.rs new file mode 100644 index 000000000..db85f1d20 --- /dev/null +++ b/pumpkin/src/entity/passive/cod.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Cod, a common passive aquatic mob. +/// +/// Wiki: +pub struct CodEntity { + pub mob_entity: MobEntity, +} + +impl CodEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let cod = Self { mob_entity }; + let mob_arc = Arc::new(cod); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for CodEntity {} + +impl Mob for CodEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/cow.rs b/pumpkin/src/entity/passive/cow.rs index 0ff25d4a4..eb2b0bd60 100644 --- a/pumpkin/src/entity/passive/cow.rs +++ b/pumpkin/src/entity/passive/cow.rs @@ -1,19 +1,27 @@ use std::sync::{Arc, Weak}; +use pumpkin_data::item_stack::ItemStack; +use pumpkin_data::particle::Particle; +use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::{entity::EntityType, item::Item}; +use pumpkin_util::math::vector3::Vector3; use crate::entity::{ - Entity, NBTStorage, + Entity, EntityBase, EntityBaseFuture, NBTStorage, ai::goal::{ - escape_danger::EscapeDangerGoal, look_around::RandomLookAroundGoal, - look_at_entity::LookAtEntityGoal, swim::SwimGoal, tempt::TemptGoal, - wander_around::WanderAroundGoal, + breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal, + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + tempt::TemptGoal, wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, + player::Player, }; const TEMPT_ITEMS: &[&Item] = &[&Item::WHEAT]; +/// Represents a Cow, a common passive mob that provides milk, leather, and beef. +/// +/// Wiki: pub struct CowEntity { pub mob_entity: MobEntity, } @@ -33,7 +41,9 @@ impl CowEntity { goal_selector.add_goal(0, Box::new(SwimGoal::default())); goal_selector.add_goal(1, EscapeDangerGoal::new(2.0)); + goal_selector.add_goal(2, BreedGoal::new(1.0)); goal_selector.add_goal(3, Box::new(TemptGoal::new(1.25, TEMPT_ITEMS))); + goal_selector.add_goal(4, Box::new(FollowParentGoal::new(1.25))); goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( 6, @@ -52,4 +62,41 @@ impl Mob for CowEntity { fn get_mob_entity(&self) -> &MobEntity { &self.mob_entity } + + fn mob_interact<'a>( + &'a self, + player: &'a Player, + item_stack: &'a mut ItemStack, + ) -> EntityBaseFuture<'a, bool> { + Box::pin(async move { + let is_food = TEMPT_ITEMS.iter().any(|i| i.id == item_stack.item.id); + if is_food && self.is_breeding_ready() && !self.is_in_love() { + item_stack.decrement_unless_creative(player.gamemode.load(), 1); + + self.mob_entity.set_love_ticks(600); + let entity = &self.mob_entity.living_entity.entity; + let world = entity.world.load(); + let pos = entity.pos.load(); + + world + .spawn_particle( + pos + Vector3::new(0.0, f64::from(entity.height()), 0.0), + Vector3::new(0.5, 0.5, 0.5), + 1.0, + 7, + Particle::Heart, + ) + .await; + world + .play_sound( + Sound::EntityCowAmbient, + SoundCategory::Neutral, + &entity.pos.load(), + ) + .await; + return true; + } + false + }) + } } diff --git a/pumpkin/src/entity/passive/dolphin.rs b/pumpkin/src/entity/passive/dolphin.rs new file mode 100644 index 000000000..4f95e3019 --- /dev/null +++ b/pumpkin/src/entity/passive/dolphin.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Dolphin, a neutral aquatic mob that can give players the Dolphin's Grace effect. +/// +/// Wiki: +pub struct DolphinEntity { + pub mob_entity: MobEntity, +} + +impl DolphinEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let dolphin = Self { mob_entity }; + let mob_arc = Arc::new(dolphin); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for DolphinEntity {} + +impl Mob for DolphinEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/donkey.rs b/pumpkin/src/entity/passive/donkey.rs new file mode 100644 index 000000000..68ab1e610 --- /dev/null +++ b/pumpkin/src/entity/passive/donkey.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Donkey, a passive mob that can be tamed and equipped with chests. +/// +/// Wiki: +pub struct DonkeyEntity { + pub mob_entity: MobEntity, +} + +impl DonkeyEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let donkey = Self { mob_entity }; + let mob_arc = Arc::new(donkey); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for DonkeyEntity {} + +impl Mob for DonkeyEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/fox.rs b/pumpkin/src/entity/passive/fox.rs new file mode 100644 index 000000000..7bf84c234 --- /dev/null +++ b/pumpkin/src/entity/passive/fox.rs @@ -0,0 +1,60 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::{entity::EntityType, item::Item}; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal, + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + tempt::TemptGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +const TEMPT_ITEMS: &[&Item] = &[&Item::SWEET_BERRIES, &Item::GLOW_BERRIES]; + +/// Represents a Fox, a passive nocturnal mob. +/// +/// Wiki: +pub struct FoxEntity { + pub mob_entity: MobEntity, +} + +impl FoxEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let fox = Self { mob_entity }; + let mob_arc = Arc::new(fox); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, EscapeDangerGoal::new(1.5)); + goal_selector.add_goal(2, BreedGoal::new(1.0)); + goal_selector.add_goal(3, Box::new(TemptGoal::new(1.2, TEMPT_ITEMS))); + goal_selector.add_goal(4, Box::new(FollowParentGoal::new(1.1))); + goal_selector.add_goal(6, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 7, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for FoxEntity {} + +impl Mob for FoxEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/frog.rs b/pumpkin/src/entity/passive/frog.rs new file mode 100644 index 000000000..49667147e --- /dev/null +++ b/pumpkin/src/entity/passive/frog.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Frog, a passive mob that can eat small slimes and magma cubes. +/// +/// Wiki: +pub struct FrogEntity { + pub mob_entity: MobEntity, +} + +impl FrogEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let frog = Self { mob_entity }; + let mob_arc = Arc::new(frog); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for FrogEntity {} + +impl Mob for FrogEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/glow_squid.rs b/pumpkin/src/entity/passive/glow_squid.rs new file mode 100644 index 000000000..c071e2549 --- /dev/null +++ b/pumpkin/src/entity/passive/glow_squid.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Glow Squid, a passive aquatic mob that emits a glowing particle effect. +/// +/// Wiki: +pub struct GlowSquidEntity { + pub mob_entity: MobEntity, +} + +impl GlowSquidEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let glow_squid = Self { mob_entity }; + let mob_arc = Arc::new(glow_squid); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for GlowSquidEntity {} + +impl Mob for GlowSquidEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/goat.rs b/pumpkin/src/entity/passive/goat.rs new file mode 100644 index 000000000..00c3da39f --- /dev/null +++ b/pumpkin/src/entity/passive/goat.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Goat, a neutral mob that can jump high and ram players or other mobs. +/// +/// Wiki: +pub struct GoatEntity { + pub mob_entity: MobEntity, +} + +impl GoatEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let goat = Self { mob_entity }; + let mob_arc = Arc::new(goat); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for GoatEntity {} + +impl Mob for GoatEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/horse.rs b/pumpkin/src/entity/passive/horse.rs new file mode 100644 index 000000000..8c50a4757 --- /dev/null +++ b/pumpkin/src/entity/passive/horse.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Horse, a passive mob that can be tamed and ridden. +/// +/// Wiki: +pub struct HorseEntity { + pub mob_entity: MobEntity, +} + +impl HorseEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let horse = Self { mob_entity }; + let mob_arc = Arc::new(horse); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for HorseEntity {} + +impl Mob for HorseEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/iron_golem.rs b/pumpkin/src/entity/passive/iron_golem.rs index d68cdaa94..5a3bca63e 100644 --- a/pumpkin/src/entity/passive/iron_golem.rs +++ b/pumpkin/src/entity/passive/iron_golem.rs @@ -4,10 +4,17 @@ use pumpkin_data::entity::EntityType; use crate::entity::{ Entity, NBTStorage, - ai::goal::{look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal}, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, melee_attack::MeleeAttackGoal, revenge::RevengeGoal, + wander_around::WanderAroundGoal, + }, mob::{Mob, MobEntity}, }; +/// Represents an Iron Golem, a powerful neutral mob that protects villagers and players. +/// +/// Wiki: pub struct IronGolemEntity { pub mob_entity: MobEntity, } @@ -24,13 +31,25 @@ impl IronGolemEntity { { let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; - // TODO + goal_selector.add_goal(1, Box::new(MeleeAttackGoal::new(1.0, true))); + goal_selector.add_goal(6, Box::new(WanderAroundGoal::new(0.6))); goal_selector.add_goal( - 8, - LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + 7, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), ); goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); + + target_selector.add_goal(1, Box::new(RevengeGoal::new(true))); + target_selector.add_goal( + 2, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::PLAYER, false), + ); + target_selector.add_goal( + 3, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::ZOMBIE, true), + ); }; mob_arc diff --git a/pumpkin/src/entity/passive/llama.rs b/pumpkin/src/entity/passive/llama.rs new file mode 100644 index 000000000..30faa1e32 --- /dev/null +++ b/pumpkin/src/entity/passive/llama.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Llama, a neutral mob that can be used for carrying items and spits at enemies. +/// +/// Wiki: +pub struct LlamaEntity { + pub mob_entity: MobEntity, +} + +impl LlamaEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let llama = Self { mob_entity }; + let mob_arc = Arc::new(llama); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for LlamaEntity {} + +impl Mob for LlamaEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/mod.rs b/pumpkin/src/entity/passive/mod.rs index 7a25c0dcc..f25536a6b 100644 --- a/pumpkin/src/entity/passive/mod.rs +++ b/pumpkin/src/entity/passive/mod.rs @@ -1,8 +1,42 @@ +pub mod allay; +pub mod armadillo; +pub mod axolotl; +pub mod bee; +pub mod camel; pub mod cat; pub mod chicken; +pub mod cod; pub mod cow; +pub mod dolphin; +pub mod donkey; +pub mod fox; +pub mod frog; +pub mod glow_squid; +pub mod goat; +pub mod horse; pub mod iron_golem; +pub mod llama; +pub mod mooshroom; +pub mod mule; +pub mod ocelot; +pub mod panda; +pub mod parrot; pub mod pig; +pub mod polar_bear; +pub mod pufferfish; +pub mod rabbit; +pub mod salmon; pub mod sheep; +pub mod skeleton_horse; +pub mod sniffer; pub mod snow_golem; +pub mod squid; +pub mod strider; +pub mod tadpole; +pub mod trader_llama; +pub mod tropical_fish; +pub mod turtle; +pub mod villager; +pub mod wandering_trader; pub mod wolf; +pub mod zombie_horse; diff --git a/pumpkin/src/entity/passive/mooshroom.rs b/pumpkin/src/entity/passive/mooshroom.rs new file mode 100644 index 000000000..f5b769c0d --- /dev/null +++ b/pumpkin/src/entity/passive/mooshroom.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Mooshroom, a fungal variant of cows that can be milked for mushroom stew. +/// +/// Wiki: +pub struct MooshroomEntity { + pub mob_entity: MobEntity, +} + +impl MooshroomEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let mooshroom = Self { mob_entity }; + let mob_arc = Arc::new(mooshroom); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for MooshroomEntity {} + +impl Mob for MooshroomEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/mule.rs b/pumpkin/src/entity/passive/mule.rs new file mode 100644 index 000000000..db0f745bb --- /dev/null +++ b/pumpkin/src/entity/passive/mule.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Mule, a passive mob created by breeding a horse and a donkey. +/// +/// Wiki: +pub struct MuleEntity { + pub mob_entity: MobEntity, +} + +impl MuleEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let mule = Self { mob_entity }; + let mob_arc = Arc::new(mule); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for MuleEntity {} + +impl Mob for MuleEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/ocelot.rs b/pumpkin/src/entity/passive/ocelot.rs new file mode 100644 index 000000000..808ef095c --- /dev/null +++ b/pumpkin/src/entity/passive/ocelot.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents an Ocelot, a shy passive mob found in jungles. +/// +/// Wiki: +pub struct OcelotEntity { + pub mob_entity: MobEntity, +} + +impl OcelotEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let ocelot = Self { mob_entity }; + let mob_arc = Arc::new(ocelot); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for OcelotEntity {} + +impl Mob for OcelotEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/panda.rs b/pumpkin/src/entity/passive/panda.rs new file mode 100644 index 000000000..f9c15d308 --- /dev/null +++ b/pumpkin/src/entity/passive/panda.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Panda, a rare passive mob with various personalities. +/// +/// Wiki: +pub struct PandaEntity { + pub mob_entity: MobEntity, +} + +impl PandaEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let panda = Self { mob_entity }; + let mob_arc = Arc::new(panda); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for PandaEntity {} + +impl Mob for PandaEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/parrot.rs b/pumpkin/src/entity/passive/parrot.rs new file mode 100644 index 000000000..a0ad27342 --- /dev/null +++ b/pumpkin/src/entity/passive/parrot.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Parrot, a passive flying mob that can mimic nearby mob sounds. +/// +/// Wiki: +pub struct ParrotEntity { + pub mob_entity: MobEntity, +} + +impl ParrotEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let parrot = Self { mob_entity }; + let mob_arc = Arc::new(parrot); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for ParrotEntity {} + +impl Mob for ParrotEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/pig.rs b/pumpkin/src/entity/passive/pig.rs index 998905094..9d80e55ff 100644 --- a/pumpkin/src/entity/passive/pig.rs +++ b/pumpkin/src/entity/passive/pig.rs @@ -1,16 +1,20 @@ use std::sync::{Arc, Weak}; -use pumpkin_data::entity::EntityType; -use pumpkin_data::item::Item; +use pumpkin_data::item_stack::ItemStack; +use pumpkin_data::particle::Particle; +use pumpkin_data::sound::{Sound, SoundCategory}; +use pumpkin_data::{entity::EntityType, item::Item}; +use pumpkin_util::math::vector3::Vector3; use crate::entity::{ - Entity, NBTStorage, + Entity, EntityBase, EntityBaseFuture, NBTStorage, ai::goal::{ - escape_danger::EscapeDangerGoal, look_around::RandomLookAroundGoal, - look_at_entity::LookAtEntityGoal, swim::SwimGoal, tempt::TemptGoal, - wander_around::WanderAroundGoal, + breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal, + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + tempt::TemptGoal, wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, + player::Player, }; const PIG_FOOD: &[&Item] = &[ @@ -20,6 +24,9 @@ const PIG_FOOD: &[&Item] = &[ &Item::CARROT_ON_A_STICK, ]; +/// Represents a Pig, a common passive mob that provides porkchops. +/// +/// Wiki: pub struct PigEntity { pub mob_entity: MobEntity, } @@ -39,13 +46,15 @@ impl PigEntity { goal_selector.add_goal(0, Box::new(SwimGoal::default())); goal_selector.add_goal(1, EscapeDangerGoal::new(1.25)); - goal_selector.add_goal(4, Box::new(TemptGoal::new(1.2, PIG_FOOD))); - goal_selector.add_goal(6, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal(2, BreedGoal::new(1.0)); + goal_selector.add_goal(3, Box::new(TemptGoal::new(1.2, PIG_FOOD))); + goal_selector.add_goal(4, Box::new(FollowParentGoal::new(1.1))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( - 7, + 6, LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), ); - goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); }; mob_arc @@ -58,4 +67,41 @@ impl Mob for PigEntity { fn get_mob_entity(&self) -> &MobEntity { &self.mob_entity } + + fn mob_interact<'a>( + &'a self, + player: &'a Player, + item_stack: &'a mut ItemStack, + ) -> EntityBaseFuture<'a, bool> { + Box::pin(async move { + let is_food = PIG_FOOD.iter().any(|i| i.id == item_stack.item.id); + if is_food && self.is_breeding_ready() && !self.is_in_love() { + item_stack.decrement_unless_creative(player.gamemode.load(), 1); + + self.mob_entity.set_love_ticks(600); + let entity = &self.mob_entity.living_entity.entity; + let world = entity.world.load(); + let pos = entity.pos.load(); + + world + .spawn_particle( + pos + Vector3::new(0.0, f64::from(entity.height()), 0.0), + Vector3::new(0.5, 0.5, 0.5), + 1.0, + 7, + Particle::Heart, + ) + .await; + world + .play_sound( + Sound::EntityPigAmbient, + SoundCategory::Neutral, + &entity.pos.load(), + ) + .await; + return true; + } + false + }) + } } diff --git a/pumpkin/src/entity/passive/polar_bear.rs b/pumpkin/src/entity/passive/polar_bear.rs new file mode 100644 index 000000000..76a6d4b66 --- /dev/null +++ b/pumpkin/src/entity/passive/polar_bear.rs @@ -0,0 +1,60 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Polar Bear, a neutral mob found in cold biomes. +/// +/// Wiki: +pub struct PolarBearEntity { + pub mob_entity: MobEntity, +} + +impl PolarBearEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let polar_bear = Self { mob_entity }; + let mob_arc = Arc::new(polar_bear); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; + // Polar bears are neutral but aggressive towards foxes + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::FOX, true), + ); + }; + + mob_arc + } +} + +impl NBTStorage for PolarBearEntity {} + +impl Mob for PolarBearEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/pufferfish.rs b/pumpkin/src/entity/passive/pufferfish.rs new file mode 100644 index 000000000..56b12930f --- /dev/null +++ b/pumpkin/src/entity/passive/pufferfish.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +/// Represents a Pufferfish, a passive aquatic mob that can inflate when threatened. +/// +/// Wiki: +pub struct PufferfishEntity { + pub mob_entity: MobEntity, +} + +impl PufferfishEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let pufferfish = Self { mob_entity }; + let mob_arc = Arc::new(pufferfish); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for PufferfishEntity {} + +impl Mob for PufferfishEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/rabbit.rs b/pumpkin/src/entity/passive/rabbit.rs new file mode 100644 index 000000000..af3682743 --- /dev/null +++ b/pumpkin/src/entity/passive/rabbit.rs @@ -0,0 +1,57 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::{entity::EntityType, item::Item}; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal, + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + tempt::TemptGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +const TEMPT_ITEMS: &[&Item] = &[&Item::CARROT, &Item::GOLDEN_CARROT, &Item::DANDELION]; + +pub struct RabbitEntity { + pub mob_entity: MobEntity, +} + +impl RabbitEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let rabbit = Self { mob_entity }; + let mob_arc = Arc::new(rabbit); + 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; + + goal_selector.add_goal(1, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, EscapeDangerGoal::new(2.2)); + goal_selector.add_goal(2, BreedGoal::new(0.8)); + goal_selector.add_goal(3, Box::new(TemptGoal::new(1.0, TEMPT_ITEMS))); + goal_selector.add_goal(4, Box::new(FollowParentGoal::new(0.8))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(0.6))); + goal_selector.add_goal( + 11, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 10.0), + ); + goal_selector.add_goal(11, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for RabbitEntity {} + +impl Mob for RabbitEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/salmon.rs b/pumpkin/src/entity/passive/salmon.rs new file mode 100644 index 000000000..db0f9f00e --- /dev/null +++ b/pumpkin/src/entity/passive/salmon.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct SalmonEntity { + pub mob_entity: MobEntity, +} + +impl SalmonEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let salmon = Self { mob_entity }; + let mob_arc = Arc::new(salmon); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for SalmonEntity {} + +impl Mob for SalmonEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/sheep.rs b/pumpkin/src/entity/passive/sheep.rs index a5f5d435a..07b92cae6 100644 --- a/pumpkin/src/entity/passive/sheep.rs +++ b/pumpkin/src/entity/passive/sheep.rs @@ -9,15 +9,22 @@ use pumpkin_data::{ use pumpkin_protocol::java::client::play::Metadata; use crate::entity::{ - Entity, EntityBaseFuture, NBTStorage, NbtFuture, + Entity, EntityBase, EntityBaseFuture, NBTStorage, NbtFuture, ai::goal::{ - eat_grass::EatGrassGoal, escape_danger::EscapeDangerGoal, - look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, - tempt::TemptGoal, wander_around::WanderAroundGoal, + breed::BreedGoal, eat_grass::EatGrassGoal, escape_danger::EscapeDangerGoal, + follow_parent::FollowParentGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, tempt::TemptGoal, + wander_around::WanderAroundGoal, }, mob::{Mob, MobEntity}, + player::Player, }; +use pumpkin_data::item_stack::ItemStack; +use pumpkin_data::particle::Particle; +use pumpkin_data::sound::{Sound, SoundCategory}; +use pumpkin_util::math::vector3::Vector3; + const TEMPT_ITEMS: &[&Item] = &[&Item::WHEAT]; pub struct SheepEntity { @@ -43,7 +50,9 @@ impl SheepEntity { goal_selector.add_goal(0, Box::new(SwimGoal::default())); goal_selector.add_goal(1, EscapeDangerGoal::new(1.25)); + goal_selector.add_goal(2, BreedGoal::new(1.0)); goal_selector.add_goal(3, Box::new(TemptGoal::new(1.1, TEMPT_ITEMS))); + goal_selector.add_goal(4, Box::new(FollowParentGoal::new(1.1))); goal_selector.add_goal(5, Box::new(EatGrassGoal::default())); goal_selector.add_goal(6, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( @@ -132,4 +141,41 @@ impl Mob for SheepEntity { self.set_sheared(false).await; }) } + + fn mob_interact<'a>( + &'a self, + player: &'a Player, + item_stack: &'a mut ItemStack, + ) -> EntityBaseFuture<'a, bool> { + Box::pin(async move { + let is_food = TEMPT_ITEMS.iter().any(|i| i.id == item_stack.item.id); + if is_food && self.is_breeding_ready() && !self.is_in_love() { + item_stack.decrement_unless_creative(player.gamemode.load(), 1); + + self.mob_entity.set_love_ticks(600); + let entity = &self.mob_entity.living_entity.entity; + let world = entity.world.load(); + let pos = entity.pos.load(); + + world + .spawn_particle( + pos + Vector3::new(0.0, f64::from(entity.height()), 0.0), + Vector3::new(0.5, 0.5, 0.5), + 1.0, + 7, + Particle::Heart, + ) + .await; + world + .play_sound( + Sound::EntitySheepAmbient, + SoundCategory::Neutral, + &entity.pos.load(), + ) + .await; + return true; + } + false + }) + } } diff --git a/pumpkin/src/entity/passive/skeleton_horse.rs b/pumpkin/src/entity/passive/skeleton_horse.rs new file mode 100644 index 000000000..2c4a79f64 --- /dev/null +++ b/pumpkin/src/entity/passive/skeleton_horse.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct SkeletonHorseEntity { + pub mob_entity: MobEntity, +} + +impl SkeletonHorseEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let horse = Self { mob_entity }; + let mob_arc = Arc::new(horse); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for SkeletonHorseEntity {} + +impl Mob for SkeletonHorseEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/sniffer.rs b/pumpkin/src/entity/passive/sniffer.rs new file mode 100644 index 000000000..26e6b2ca4 --- /dev/null +++ b/pumpkin/src/entity/passive/sniffer.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct SnifferEntity { + pub mob_entity: MobEntity, +} + +impl SnifferEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let sniffer = Self { mob_entity }; + let mob_arc = Arc::new(sniffer); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for SnifferEntity {} + +impl Mob for SnifferEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/snow_golem.rs b/pumpkin/src/entity/passive/snow_golem.rs index b4bb4489e..d7ef87a04 100644 --- a/pumpkin/src/entity/passive/snow_golem.rs +++ b/pumpkin/src/entity/passive/snow_golem.rs @@ -4,7 +4,10 @@ use pumpkin_data::entity::EntityType; use crate::entity::{ Entity, NBTStorage, - ai::goal::{look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal}, + ai::goal::{ + active_target::ActiveTargetGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, wander_around::WanderAroundGoal, + }, mob::{Mob, MobEntity}, }; @@ -15,8 +18,8 @@ pub struct SnowGolemEntity { impl SnowGolemEntity { pub async fn new(entity: Entity) -> Arc { let mob_entity = MobEntity::new(entity); - let wolf = Self { mob_entity }; - let mob_arc = Arc::new(wolf); + let snow_golem = Self { mob_entity }; + let mob_arc = Arc::new(snow_golem); let mob_weak: Weak = { let mob_arc: Arc = mob_arc.clone(); Arc::downgrade(&mob_arc) @@ -24,13 +27,20 @@ impl SnowGolemEntity { { let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; + let mut target_selector = mob_arc.mob_entity.target_selector.lock().await; - // TODO + // TODO: SnowballAttackGoal + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); goal_selector.add_goal( - 8, - LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + 6, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(6, Box::new(RandomLookAroundGoal::default())); + + target_selector.add_goal( + 1, + ActiveTargetGoal::with_default(&mob_arc.mob_entity, &EntityType::ZOMBIE, true), ); - goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); }; mob_arc diff --git a/pumpkin/src/entity/passive/squid.rs b/pumpkin/src/entity/passive/squid.rs new file mode 100644 index 000000000..10bdf1562 --- /dev/null +++ b/pumpkin/src/entity/passive/squid.rs @@ -0,0 +1,52 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct SquidEntity { + pub mob_entity: MobEntity, +} + +impl SquidEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let squid = Self { mob_entity }; + let mob_arc = Arc::new(squid); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // Squids don't have WanderAroundGoal in vanilla (they use custom movement), + // but for now we give it to them. + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.6))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for SquidEntity {} + +impl Mob for SquidEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/strider.rs b/pumpkin/src/entity/passive/strider.rs new file mode 100644 index 000000000..ccb58fe9f --- /dev/null +++ b/pumpkin/src/entity/passive/strider.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct StriderEntity { + pub mob_entity: MobEntity, +} + +impl StriderEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let strider = Self { mob_entity }; + let mob_arc = Arc::new(strider); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for StriderEntity {} + +impl Mob for StriderEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/tadpole.rs b/pumpkin/src/entity/passive/tadpole.rs new file mode 100644 index 000000000..0bc087b22 --- /dev/null +++ b/pumpkin/src/entity/passive/tadpole.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct TadpoleEntity { + pub mob_entity: MobEntity, +} + +impl TadpoleEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let tadpole = Self { mob_entity }; + let mob_arc = Arc::new(tadpole); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for TadpoleEntity {} + +impl Mob for TadpoleEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/trader_llama.rs b/pumpkin/src/entity/passive/trader_llama.rs new file mode 100644 index 000000000..57980d13c --- /dev/null +++ b/pumpkin/src/entity/passive/trader_llama.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct TraderLlamaEntity { + pub mob_entity: MobEntity, +} + +impl TraderLlamaEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let llama = Self { mob_entity }; + let mob_arc = Arc::new(llama); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for TraderLlamaEntity {} + +impl Mob for TraderLlamaEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/tropical_fish.rs b/pumpkin/src/entity/passive/tropical_fish.rs new file mode 100644 index 000000000..91f956153 --- /dev/null +++ b/pumpkin/src/entity/passive/tropical_fish.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct TropicalFishEntity { + pub mob_entity: MobEntity, +} + +impl TropicalFishEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let tropical_fish = Self { mob_entity }; + let mob_arc = Arc::new(tropical_fish); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for TropicalFishEntity {} + +impl Mob for TropicalFishEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/turtle.rs b/pumpkin/src/entity/passive/turtle.rs new file mode 100644 index 000000000..93987018c --- /dev/null +++ b/pumpkin/src/entity/passive/turtle.rs @@ -0,0 +1,54 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::{entity::EntityType, item::Item}; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + breed::BreedGoal, look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, + swim::SwimGoal, tempt::TemptGoal, wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +const TEMPT_ITEMS: &[&Item] = &[&Item::SEAGRASS]; + +pub struct TurtleEntity { + pub mob_entity: MobEntity, +} + +impl TurtleEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let turtle = Self { mob_entity }; + let mob_arc = Arc::new(turtle); + 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; + + goal_selector.add_goal(1, Box::new(SwimGoal::default())); + goal_selector.add_goal(2, BreedGoal::new(1.0)); + goal_selector.add_goal(3, Box::new(TemptGoal::new(1.1, TEMPT_ITEMS))); + goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0))); + goal_selector.add_goal( + 6, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for TurtleEntity {} + +impl Mob for TurtleEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/villager.rs b/pumpkin/src/entity/passive/villager.rs new file mode 100644 index 000000000..a3e5836ce --- /dev/null +++ b/pumpkin/src/entity/passive/villager.rs @@ -0,0 +1,55 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct VillagerEntity { + pub mob_entity: MobEntity, +} + +impl VillagerEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let villager = Self { mob_entity }; + let mob_arc = Arc::new(villager); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + // Villagers have complex AI, but for now we give them basic movement + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.6))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak.clone(), &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal( + 3, + LookAtEntityGoal::with_default(mob_weak, &EntityType::VILLAGER, 8.0), + ); + goal_selector.add_goal(4, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for VillagerEntity {} + +impl Mob for VillagerEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/wandering_trader.rs b/pumpkin/src/entity/passive/wandering_trader.rs new file mode 100644 index 000000000..2fd3ef78f --- /dev/null +++ b/pumpkin/src/entity/passive/wandering_trader.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct WanderingTraderEntity { + pub mob_entity: MobEntity, +} + +impl WanderingTraderEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let trader = Self { mob_entity }; + let mob_arc = Arc::new(trader); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.6))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for WanderingTraderEntity {} + +impl Mob for WanderingTraderEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/passive/wolf.rs b/pumpkin/src/entity/passive/wolf.rs index cc2b0bf36..b0c3b73ec 100644 --- a/pumpkin/src/entity/passive/wolf.rs +++ b/pumpkin/src/entity/passive/wolf.rs @@ -5,7 +5,11 @@ use pumpkin_data::item::Item; use crate::entity::{ Entity, NBTStorage, - ai::goal::{beg::BegGoal, look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal}, + ai::goal::{ + beg::BegGoal, breed::BreedGoal, escape_danger::EscapeDangerGoal, + follow_parent::FollowParentGoal, look_around::RandomLookAroundGoal, + look_at_entity::LookAtEntityGoal, swim::SwimGoal, wander_around::WanderAroundGoal, + }, mob::{Mob, MobEntity}, }; @@ -26,12 +30,19 @@ impl WolfEntity { { let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await; + goal_selector.add_goal(1, Box::new(SwimGoal::default())); + // goal_selector.add_goal(2, SitGoal::new(mob_arc.clone())); + goal_selector.add_goal(4, EscapeDangerGoal::new(1.5)); + goal_selector.add_goal(5, BreedGoal::new(1.0)); + // goal_selector.add_goal(6, FollowOwnerGoal::new(1.0, 10.0, 2.0, false)); + goal_selector.add_goal(8, Box::new(FollowParentGoal::new(1.1))); + goal_selector.add_goal(9, BegGoal::new(8.0, &[&Item::BONE])); goal_selector.add_goal( - 8, + 10, LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 8.0), ); - goal_selector.add_goal(8, Box::new(RandomLookAroundGoal::default())); - goal_selector.add_goal(9, BegGoal::new(8.0, &[&Item::BONE])); + goal_selector.add_goal(10, Box::new(RandomLookAroundGoal::default())); + goal_selector.add_goal(12, Box::new(WanderAroundGoal::new(1.0))); }; mob_arc diff --git a/pumpkin/src/entity/passive/zombie_horse.rs b/pumpkin/src/entity/passive/zombie_horse.rs new file mode 100644 index 000000000..4c64bdd2d --- /dev/null +++ b/pumpkin/src/entity/passive/zombie_horse.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, Weak}; + +use pumpkin_data::entity::EntityType; + +use crate::entity::{ + Entity, NBTStorage, + ai::goal::{ + look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal, + wander_around::WanderAroundGoal, + }, + mob::{Mob, MobEntity}, +}; + +pub struct ZombieHorseEntity { + pub mob_entity: MobEntity, +} + +impl ZombieHorseEntity { + pub async fn new(entity: Entity) -> Arc { + let mob_entity = MobEntity::new(entity); + let horse = Self { mob_entity }; + let mob_arc = Arc::new(horse); + 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; + + goal_selector.add_goal(0, Box::new(SwimGoal::default())); + goal_selector.add_goal(1, Box::new(WanderAroundGoal::new(0.7))); + goal_selector.add_goal( + 2, + LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0), + ); + goal_selector.add_goal(3, Box::new(RandomLookAroundGoal::default())); + }; + + mob_arc + } +} + +impl NBTStorage for ZombieHorseEntity {} + +impl Mob for ZombieHorseEntity { + fn get_mob_entity(&self) -> &MobEntity { + &self.mob_entity + } +} diff --git a/pumpkin/src/entity/type.rs b/pumpkin/src/entity/type.rs index cd0830c70..c39ae7834 100644 --- a/pumpkin/src/entity/type.rs +++ b/pumpkin/src/entity/type.rs @@ -5,41 +5,114 @@ use pumpkin_util::math::vector3::Vector3; use uuid::Uuid; use crate::entity::boss::ender_dragon::EnderDragonEntity; +use crate::entity::boss::wither::WitherEntity; +use crate::entity::decoration::{ + armor_stand::ArmorStandEntity, end_crystal::EndCrystalEntity, painting::PaintingEntity, +}; +use crate::entity::experience_orb::ExperienceOrbEntity; +use crate::entity::falling::FallingEntity; +use crate::entity::item::ItemEntity; +use crate::entity::living::LivingEntity; +use crate::entity::mob::bat::BatEntity; use crate::entity::mob::blaze::BlazeEntity; +use crate::entity::mob::breeze::BreezeEntity; +use crate::entity::mob::cave_spider::CaveSpiderEntity; +use crate::entity::mob::creaking::CreakingEntity; +use crate::entity::mob::creeper::CreeperEntity; +use crate::entity::mob::elder_guardian::ElderGuardianEntity; +use crate::entity::mob::enderman::EndermanEntity; +use crate::entity::mob::endermite::EndermiteEntity; +use crate::entity::mob::evoker::EvokerEntity; +use crate::entity::mob::ghast::GhastEntity; +use crate::entity::mob::giant::GiantEntity; +use crate::entity::mob::guardian::GuardianEntity; +use crate::entity::mob::hoglin::HoglinEntity; +use crate::entity::mob::illusioner::IllusionerEntity; +use crate::entity::mob::magma_cube::MagmaCubeEntity; +use crate::entity::mob::phantom::PhantomEntity; +use crate::entity::mob::piglin::PiglinEntity; +use crate::entity::mob::piglin_brute::PiglinBruteEntity; +use crate::entity::mob::pillager::PillagerEntity; +use crate::entity::mob::ravager::RavagerEntity; use crate::entity::mob::shulker::ShulkerEntity; +use crate::entity::mob::silverfish::SilverfishEntity; +use crate::entity::mob::skeleton::{ + bogged::BoggedSkeletonEntity, parched::ParchedSkeletonEntity, skeleton::SkeletonEntity, + stray::StraySkeletonEntity, wither::WitherSkeletonEntity, +}; +use crate::entity::mob::slime::SlimeEntity; +use crate::entity::mob::spider::SpiderEntity; +use crate::entity::mob::vex::VexEntity; +use crate::entity::mob::vindicator::VindicatorEntity; +use crate::entity::mob::warden::WardenEntity; +use crate::entity::mob::witch::WitchEntity; +use crate::entity::mob::zoglin::ZoglinEntity; use crate::entity::mob::zombie::zombie_villager::ZombieVillagerEntity; +use crate::entity::mob::zombie::{drowned::DrownedEntity, husk::HuskEntity, zombie::ZombieEntity}; +use crate::entity::mob::zombified_piglin::ZombifiedPiglinEntity; +use crate::entity::passive::allay::AllayEntity; +use crate::entity::passive::armadillo::ArmadilloEntity; +use crate::entity::passive::axolotl::AxolotlEntity; +use crate::entity::passive::bee::BeeEntity; +use crate::entity::passive::camel::CamelEntity; +use crate::entity::passive::cat::CatEntity; +use crate::entity::passive::chicken::ChickenEntity; +use crate::entity::passive::cod::CodEntity; +use crate::entity::passive::cow::CowEntity; +use crate::entity::passive::dolphin::DolphinEntity; +use crate::entity::passive::donkey::DonkeyEntity; +use crate::entity::passive::fox::FoxEntity; +use crate::entity::passive::frog::FrogEntity; +use crate::entity::passive::glow_squid::GlowSquidEntity; +use crate::entity::passive::goat::GoatEntity; +use crate::entity::passive::horse::HorseEntity; +use crate::entity::passive::iron_golem::IronGolemEntity; +use crate::entity::passive::llama::LlamaEntity; +use crate::entity::passive::mooshroom::MooshroomEntity; +use crate::entity::passive::mule::MuleEntity; +use crate::entity::passive::ocelot::OcelotEntity; +use crate::entity::passive::panda::PandaEntity; +use crate::entity::passive::parrot::ParrotEntity; +use crate::entity::passive::pig::PigEntity; +use crate::entity::passive::polar_bear::PolarBearEntity; +use crate::entity::passive::pufferfish::PufferfishEntity; +use crate::entity::passive::rabbit::RabbitEntity; +use crate::entity::passive::salmon::SalmonEntity; +use crate::entity::passive::sheep::SheepEntity; +use crate::entity::passive::skeleton_horse::SkeletonHorseEntity; +use crate::entity::passive::sniffer::SnifferEntity; +use crate::entity::passive::snow_golem::SnowGolemEntity; +use crate::entity::passive::squid::SquidEntity; +use crate::entity::passive::strider::StriderEntity; +use crate::entity::passive::tadpole::TadpoleEntity; +use crate::entity::passive::trader_llama::TraderLlamaEntity; +use crate::entity::passive::tropical_fish::TropicalFishEntity; +use crate::entity::passive::turtle::TurtleEntity; +use crate::entity::passive::villager::VillagerEntity; +use crate::entity::passive::wandering_trader::WanderingTraderEntity; +use crate::entity::passive::wolf::WolfEntity; +use crate::entity::passive::zombie_horse::ZombieHorseEntity; +use crate::entity::projectile::ThrownItemEntity; +use crate::entity::projectile::arrow::ArrowEntity; use crate::entity::projectile::egg::EggEntity; use crate::entity::projectile::ender_pearl::EnderPearlEntity; +use crate::entity::projectile::eye_of_ender::EyeOfEnder; +use crate::entity::projectile::firework_rocket::FireworkRocketEntity; +use crate::entity::projectile::lingering_potion::LingeringPotionEntity; use crate::entity::projectile::shulker_bullet::ShulkerBulletEntity; use crate::entity::projectile::snowball::SnowballEntity; -use crate::{ - entity::{ - Entity, EntityBase, - boss::wither::WitherEntity, - decoration::{ - armor_stand::ArmorStandEntity, end_crystal::EndCrystalEntity, painting::PaintingEntity, - }, - living::LivingEntity, - mob::{ - bat::BatEntity, - creeper::CreeperEntity, - enderman::EndermanEntity, - silverfish::SilverfishEntity, - skeleton::{ - bogged::BoggedSkeletonEntity, parched::ParchedSkeletonEntity, - skeleton::SkeletonEntity, stray::StraySkeletonEntity, wither::WitherSkeletonEntity, - }, - slime::SlimeEntity, - zombie::{drowned::DrownedEntity, husk::HuskEntity, zombie::ZombieEntity}, - }, - passive::{ - cat::CatEntity, chicken::ChickenEntity, cow::CowEntity, iron_golem::IronGolemEntity, - pig::PigEntity, sheep::SheepEntity, snow_golem::SnowGolemEntity, wolf::WolfEntity, - }, - }, - world::World, -}; +use crate::entity::projectile::splash_potion::SplashPotionEntity; +use crate::entity::projectile::wind_charge::WindChargeEntity; +use crate::entity::tnt::TNTEntity; +use crate::entity::vehicle::boat::BoatEntity; +use crate::entity::{Entity, EntityBase}; +use crate::world::World; +use pumpkin_data::Block; +use pumpkin_data::item::Item; +use pumpkin_data::item_stack::ItemStack; +use std::sync::atomic::AtomicBool; +#[expect(clippy::too_many_lines)] pub async fn from_type( entity_type: &'static EntityType, position: Vector3, @@ -54,8 +127,9 @@ pub async fn from_type( id if id == EntityType::DROWNED.id => DrownedEntity::new(entity).await, id if id == EntityType::HUSK.id => HuskEntity::new(entity).await, id if id == EntityType::ZOMBIE_VILLAGER.id => ZombieVillagerEntity::new(entity).await, + id if id == EntityType::ZOMBIFIED_PIGLIN.id => ZombifiedPiglinEntity::new(entity).await, - // Sekelton + // Skeleton id if id == EntityType::SKELETON.id => SkeletonEntity::new(entity).await, id if id == EntityType::BOGGED.id => BoggedSkeletonEntity::new(entity).await, id if id == EntityType::PARCHED.id => ParchedSkeletonEntity::new(entity).await, @@ -67,14 +141,73 @@ pub async fn from_type( id if id == EntityType::ENDERMAN.id => EndermanEntity::new(entity).await, id if id == EntityType::BLAZE.id => BlazeEntity::new(entity).await, + id if id == EntityType::SPIDER.id => SpiderEntity::new(entity).await, + id if id == EntityType::CAVE_SPIDER.id => CaveSpiderEntity::new(entity).await, + id if id == EntityType::GHAST.id => GhastEntity::new(entity).await, + id if id == EntityType::MAGMA_CUBE.id => MagmaCubeEntity::new(entity).await, + id if id == EntityType::PHANTOM.id => PhantomEntity::new(entity).await, + id if id == EntityType::WITCH.id => WitchEntity::new(entity).await, + id if id == EntityType::PIGLIN.id => PiglinEntity::new(entity).await, + id if id == EntityType::PIGLIN_BRUTE.id => PiglinBruteEntity::new(entity).await, + id if id == EntityType::PILLAGER.id => PillagerEntity::new(entity).await, + id if id == EntityType::VINDICATOR.id => VindicatorEntity::new(entity).await, + id if id == EntityType::EVOKER.id => EvokerEntity::new(entity).await, + id if id == EntityType::RAVAGER.id => RavagerEntity::new(entity).await, + id if id == EntityType::GUARDIAN.id => GuardianEntity::new(entity).await, + id if id == EntityType::ELDER_GUARDIAN.id => ElderGuardianEntity::new(entity).await, + id if id == EntityType::WARDEN.id => WardenEntity::new(entity).await, + id if id == EntityType::HOGLIN.id => HoglinEntity::new(entity).await, + id if id == EntityType::ZOGLIN.id => ZoglinEntity::new(entity).await, + id if id == EntityType::BREEZE.id => BreezeEntity::new(entity).await, + id if id == EntityType::CREAKING.id => CreakingEntity::new(entity).await, + id if id == EntityType::ILLUSIONER.id => IllusionerEntity::new(entity).await, + id if id == EntityType::VEX.id => VexEntity::new(entity).await, + id if id == EntityType::ENDERMITE.id => EndermiteEntity::new(entity).await, + id if id == EntityType::GIANT.id => GiantEntity::new(entity).await, + id if id == EntityType::CAT.id => CatEntity::new(entity).await, id if id == EntityType::CHICKEN.id => ChickenEntity::new(entity).await, id if id == EntityType::COW.id => CowEntity::new(entity).await, id if id == EntityType::PIG.id => PigEntity::new(entity).await, - id if id == EntityType::SNOW_GOLEM.id => SnowGolemEntity::new(entity).await, - id if id == EntityType::IRON_GOLEM.id => IronGolemEntity::new(entity).await, id if id == EntityType::SHEEP.id => SheepEntity::new(entity).await, id if id == EntityType::WOLF.id => WolfEntity::new(entity).await, + id if id == EntityType::FOX.id => FoxEntity::new(entity).await, + id if id == EntityType::RABBIT.id => RabbitEntity::new(entity).await, + id if id == EntityType::TURTLE.id => TurtleEntity::new(entity).await, + id if id == EntityType::VILLAGER.id => VillagerEntity::new(entity).await, + id if id == EntityType::SQUID.id => SquidEntity::new(entity).await, + id if id == EntityType::HORSE.id => HorseEntity::new(entity).await, + id if id == EntityType::DONKEY.id => DonkeyEntity::new(entity).await, + id if id == EntityType::MULE.id => MuleEntity::new(entity).await, + id if id == EntityType::ZOMBIE_HORSE.id => ZombieHorseEntity::new(entity).await, + id if id == EntityType::SKELETON_HORSE.id => SkeletonHorseEntity::new(entity).await, + id if id == EntityType::LLAMA.id => LlamaEntity::new(entity).await, + id if id == EntityType::TRADER_LLAMA.id => TraderLlamaEntity::new(entity).await, + id if id == EntityType::WANDERING_TRADER.id => WanderingTraderEntity::new(entity).await, + id if id == EntityType::ALLAY.id => AllayEntity::new(entity).await, + id if id == EntityType::ARMADILLO.id => ArmadilloEntity::new(entity).await, + id if id == EntityType::AXOLOTL.id => AxolotlEntity::new(entity).await, + id if id == EntityType::BEE.id => BeeEntity::new(entity).await, + id if id == EntityType::CAMEL.id => CamelEntity::new(entity).await, + id if id == EntityType::FROG.id => FrogEntity::new(entity).await, + id if id == EntityType::GOAT.id => GoatEntity::new(entity).await, + id if id == EntityType::MOOSHROOM.id => MooshroomEntity::new(entity).await, + id if id == EntityType::OCELOT.id => OcelotEntity::new(entity).await, + id if id == EntityType::PANDA.id => PandaEntity::new(entity).await, + id if id == EntityType::PARROT.id => ParrotEntity::new(entity).await, + id if id == EntityType::POLAR_BEAR.id => PolarBearEntity::new(entity).await, + id if id == EntityType::SNIFFER.id => SnifferEntity::new(entity).await, + id if id == EntityType::STRIDER.id => StriderEntity::new(entity).await, + id if id == EntityType::GLOW_SQUID.id => GlowSquidEntity::new(entity).await, + id if id == EntityType::COD.id => CodEntity::new(entity).await, + id if id == EntityType::SALMON.id => SalmonEntity::new(entity).await, + id if id == EntityType::PUFFERFISH.id => PufferfishEntity::new(entity).await, + id if id == EntityType::TROPICAL_FISH.id => TropicalFishEntity::new(entity).await, + id if id == EntityType::TADPOLE.id => TadpoleEntity::new(entity).await, + id if id == EntityType::DOLPHIN.id => DolphinEntity::new(entity).await, + + id if id == EntityType::SNOW_GOLEM.id => SnowGolemEntity::new(entity).await, + id if id == EntityType::IRON_GOLEM.id => IronGolemEntity::new(entity).await, id if id == EntityType::WITHER.id => WitherEntity::new(entity).await, id if id == EntityType::ENDER_DRAGON.id => EnderDragonEntity::new(entity).await, @@ -89,13 +222,72 @@ pub async fn from_type( id if id == EntityType::SNOWBALL.id => Arc::new(SnowballEntity::new(entity).await), id if id == EntityType::EGG.id => Arc::new(EggEntity::new(entity).await), id if id == EntityType::SILVERFISH.id => SilverfishEntity::new(entity).await, - id if id == EntityType::SLIME.id => SlimeEntity::new(entity), + id if id == EntityType::SLIME.id => SlimeEntity::new(entity).await, id if id == EntityType::SHULKER.id => ShulkerEntity::new(entity).await, id if id == EntityType::SHULKER_BULLET.id => { // Shulker bullets are normally spawned by ShulkerEntity directly; // when loaded from the world we create a no-target bullet at the given position. Arc::new(ShulkerBulletEntity::orphan(entity)) } + id if id == EntityType::FALLING_BLOCK.id => { + Arc::new(FallingEntity::new(entity, Block::SAND.default_state.id)) + } + id if id == EntityType::EXPERIENCE_ORB.id => Arc::new(ExperienceOrbEntity::new(entity, 1)), + id if id == EntityType::TNT.id => Arc::new(TNTEntity::new(entity, 4.0, 80)), + id if id == EntityType::ITEM.id => { + Arc::new(ItemEntity::new(entity, ItemStack::new(1, &Item::AIR)).await) + } + id if id == EntityType::ARROW.id => Arc::new(ArrowEntity::new(entity, None)), + id if id == EntityType::SPECTRAL_ARROW.id => Arc::new(ArrowEntity::new(entity, None)), + id if id == EntityType::WIND_CHARGE.id => { + let thrown = ThrownItemEntity { + entity, + owner_id: None, + collides_with_projectiles: false, + has_hit: AtomicBool::new(false), + }; + Arc::new(WindChargeEntity::new(thrown)) + } + id if id == EntityType::BREEZE_WIND_CHARGE.id => { + let thrown = ThrownItemEntity { + entity, + owner_id: None, + collides_with_projectiles: false, + has_hit: AtomicBool::new(false), + }; + Arc::new(WindChargeEntity::new(thrown)) + } + id if id == EntityType::FIREWORK_ROCKET.id => { + Arc::new(FireworkRocketEntity::new(entity).await) + } + id if id == EntityType::SPLASH_POTION.id => Arc::new(SplashPotionEntity::new(entity).await), + id if id == EntityType::LINGERING_POTION.id => { + Arc::new(LingeringPotionEntity::new(entity).await) + } + id if id == EntityType::EYE_OF_ENDER.id => Arc::new(EyeOfEnder::new(entity)), + id if id == EntityType::ACACIA_BOAT.id + || id == EntityType::ACACIA_CHEST_BOAT.id + || id == EntityType::BIRCH_BOAT.id + || id == EntityType::BIRCH_CHEST_BOAT.id + || id == EntityType::DARK_OAK_BOAT.id + || id == EntityType::DARK_OAK_CHEST_BOAT.id + || id == EntityType::JUNGLE_BOAT.id + || id == EntityType::JUNGLE_CHEST_BOAT.id + || id == EntityType::MANGROVE_BOAT.id + || id == EntityType::MANGROVE_CHEST_BOAT.id + || id == EntityType::OAK_BOAT.id + || id == EntityType::OAK_CHEST_BOAT.id + || id == EntityType::PALE_OAK_BOAT.id + || id == EntityType::PALE_OAK_CHEST_BOAT.id + || id == EntityType::SPRUCE_BOAT.id + || id == EntityType::SPRUCE_CHEST_BOAT.id + || id == EntityType::BAMBOO_RAFT.id + || id == EntityType::BAMBOO_CHEST_RAFT.id + || id == EntityType::CHERRY_BOAT.id + || id == EntityType::CHERRY_CHEST_BOAT.id => + { + Arc::new(BoatEntity::new(entity)) + } // Fallback Entity _ => { if entity_type.attributes.is_empty() {