Add Mobs to Login Sequence (#488)

* Added mobs to login sequence

* Fix naming and add inital velocity
This commit is contained in:
Kris
2025-01-26 09:42:55 -05:00
committed by GitHub
parent ac1856db2c
commit 69cb3bb4f0
4 changed files with 51 additions and 21 deletions

View File

@@ -1,6 +1,7 @@
use std::sync::Arc;
use pumpkin_data::entity::EntityType;
use pumpkin_protocol::{client::play::CSpawnEntity, codec::var_int::VarInt};
use pumpkin_util::math::vector3::Vector3;
use tokio::sync::Mutex;
use uuid::Uuid;
@@ -60,4 +61,25 @@ impl MobEntity {
pub async fn goal<T: Goal + 'static>(&self, goal: T) {
self.goals.lock().await.push((Arc::new(goal), false));
}
pub fn create_spawn_entity_packet(&self, uuid: Uuid) -> CSpawnEntity {
let e = &self.living_entity.entity;
let entity_loc = e.pos.load();
let entity_vel = e.velocity.load();
CSpawnEntity::new(
VarInt(e.entity_id),
uuid,
VarInt((e.entity_type) as i32),
entity_loc.x,
entity_loc.y,
entity_loc.z,
e.pitch.load(),
e.yaw.load(),
e.yaw.load(), // todo: head_yaw and yaw are swapped, find out why
0.into(),
entity_vel.x as f32,
entity_vel.y as f32,
entity_vel.z as f32,
)
}
}

View File

@@ -532,6 +532,17 @@ impl Player {
.await;
}
/// Sends the mobs to just the player.
// TODO: This should be optimized for larger servers based on current player chunk
pub async fn send_mobs(&self, world: &World) {
let mobs = world.current_living_mobs.lock().await.clone();
for (uuid, mob) in mobs {
self.client
.send_packet(&mob.create_spawn_entity_packet(uuid))
.await;
}
}
/// Yaw and Pitch in degrees
/// Rarly used, For example when waking up player from bed or first time spawn. Otherwise entity teleport is used
/// Player should respond with the `SConfirmTeleport` packet

View File

@@ -16,7 +16,7 @@ use pumpkin_data::entity::EntityType;
use pumpkin_data::world::CHAT;
use pumpkin_inventory::player::PlayerInventory;
use pumpkin_inventory::InventoryError;
use pumpkin_protocol::client::play::{CSetContainerSlot, CSetHeldItem, CSpawnEntity};
use pumpkin_protocol::client::play::{CSetContainerSlot, CSetHeldItem};
use pumpkin_protocol::codec::slot::Slot;
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::server::play::SCookieResponse as SPCookieResponse;
@@ -1092,8 +1092,10 @@ impl Player {
f64::from(world_pos.0.y),
f64::from(world_pos.0.z) + 0.5,
);
// create rotation like Vanilla
let yaw = wrap_degrees(rand::random::<f32>() * 360.0) % 360.0;
// TODO: this should not be hardcoded
// create new mob and uuid based on spawn egg id
let (mob, uuid) = mob::from_type(
EntityType::from_raw(*spawn_item_id).unwrap(),
server,
@@ -1101,25 +1103,13 @@ impl Player {
self.world(),
)
.await;
let yaw = wrap_degrees(rand::random::<f32>() * 360.0) % 360.0;
// set the rotation
mob.living_entity.entity.set_rotation(yaw, 0.0);
// broadcast new mob to all players
server
.broadcast_packet_all(&CSpawnEntity::new(
VarInt(mob.living_entity.entity.entity_id),
uuid,
VarInt((*spawn_item_id).into()),
pos.x,
pos.y,
pos.z,
0.0,
yaw,
yaw,
0.into(),
0.0,
0.0,
0.0,
))
.broadcast_packet_all(&mob.create_spawn_entity_packet(uuid))
.await;
// TODO: send/configure additional commands/data based on type of entity (horse, slime, etc)

View File

@@ -462,6 +462,8 @@ impl World {
// player.send_bossbar(bossbar).await;
// }
// }
player.send_mobs(self).await;
}
pub async fn respawn_player(&self, player: &Arc<Player>, alive: bool) {
@@ -865,13 +867,18 @@ impl World {
}
pub async fn remove_mob_entity(self: Arc<Self>, living_entity: Arc<LivingEntity>) {
let mut current_living_entities = self.current_living_mobs.lock().await.clone();
current_living_entities.remove(&living_entity.entity.entity_uuid);
let mut current_living_entities = self.current_living_mobs.lock().await;
current_living_entities
.remove(&living_entity.entity.entity_uuid)
.unwrap();
// TODO: does this work with collisions?
living_entity.entity.set_pose(EntityPose::Dying).await;
let world = self.clone();
tokio::spawn(async move {
tokio::time::sleep(tokio::time::Duration::from_millis(2000)).await;
self.remove_entity(&living_entity.entity).await;
world.remove_entity(&living_entity.entity).await;
});
}