Skip to content

Commit

Permalink
Add Living Entity struct
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Oct 11, 2024
1 parent 4076cda commit 9ac4bdb
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 47 deletions.
1 change: 1 addition & 0 deletions pumpkin/src/client/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ impl Player {
// Also refactor out a better method to get individual advanced state ids

let players = self
.living_entity
.entity
.world
.current_players
Expand Down
29 changes: 16 additions & 13 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ impl Player {
if let Some((id, position)) = awaiting_teleport.as_ref() {
if id == &confirm_teleport.teleport_id {
// we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported
self.entity.set_pos(position.x, position.y, position.z);
self.living_entity
.entity
.set_pos(position.x, position.y, position.z);

*awaiting_teleport = None;
} else {
Expand All @@ -76,7 +78,7 @@ impl Player {
self.kick(TextComponent::text("Invalid movement"));
return;
}
let entity = &self.entity;
let entity = &self.living_entity.entity;
entity.set_pos(
Self::clamp_horizontal(position.x),
Self::clamp_vertical(position.feet_y),
Expand Down Expand Up @@ -135,7 +137,7 @@ impl Player {
self.kick(TextComponent::text("Invalid rotation"));
return;
}
let entity = &self.entity;
let entity = &self.living_entity.entity;

entity.set_pos(
Self::clamp_horizontal(position_rotation.x),
Expand Down Expand Up @@ -200,7 +202,7 @@ impl Player {
self.kick(TextComponent::text("Invalid rotation"));
return;
}
let entity = &self.entity;
let entity = &self.living_entity.entity;
entity
.on_ground
.store(rotation.ground, std::sync::atomic::Ordering::Relaxed);
Expand Down Expand Up @@ -228,7 +230,8 @@ impl Player {
}

pub fn handle_player_ground(&self, _server: &Arc<Server>, ground: SSetPlayerGround) {
self.entity
self.living_entity
.entity
.on_ground
.store(ground.on_ground, std::sync::atomic::Ordering::Relaxed);
}
Expand All @@ -239,7 +242,7 @@ impl Player {
}

if let Some(action) = Action::from_i32(command.action.0) {
let entity = &self.entity;
let entity = &self.living_entity.entity;
match action {
pumpkin_protocol::server::play::Action::StartSneaking => {
if !entity.sneaking.load(std::sync::atomic::Ordering::Relaxed) {
Expand Down Expand Up @@ -289,7 +292,7 @@ impl Player {
Hand::Off => Animation::SwingOffhand,
};
let id = self.entity_id();
let world = &self.entity.world;
let world = &self.living_entity.entity.world;
world.broadcast_packet_expect(
&[self.client.token],
&CEntityAnimation::new(id.into(), animation as u8),
Expand All @@ -313,7 +316,7 @@ impl Player {
// TODO: filter message & validation
let gameprofile = &self.gameprofile;

let entity = &self.entity;
let entity = &self.living_entity.entity;
let world = &entity.world;
world.broadcast_packet_all(&CPlayerChatMessage::new(
gameprofile.id,
Expand Down Expand Up @@ -367,7 +370,7 @@ impl Player {

pub async fn handle_interact(&self, _: &Arc<Server>, interact: SInteract) {
let sneaking = interact.sneaking;
let entity = &self.entity;
let entity = &self.living_entity.entity;
if entity.sneaking.load(std::sync::atomic::Ordering::Relaxed) != sneaking {
entity.set_sneaking(sneaking).await;
}
Expand All @@ -381,7 +384,7 @@ impl Player {
let world = &entity.world;
let attacked_player = world.get_player_by_entityid(entity_id.0 as EntityId);
if let Some(player) = attacked_player {
let victem_entity = &player.entity;
let victem_entity = &player.living_entity.entity;
if config.protect_creative
&& player.gamemode.load() == GameMode::Creative
{
Expand Down Expand Up @@ -447,7 +450,7 @@ impl Player {
let location = player_action.location;
// Block break & block break sound
// TODO: currently this is always dirt replace it
let entity = &self.entity;
let entity = &self.living_entity.entity;
let world = &entity.world;
world.broadcast_packet_all(&CWorldEvent::new(2001, &location, 11, false));
// AIR
Expand All @@ -471,7 +474,7 @@ impl Player {
}
// Block break & block break sound
// TODO: currently this is always dirt replace it
let entity = &self.entity;
let entity = &self.living_entity.entity;
let world = &entity.world;
world.broadcast_packet_all(&CWorldEvent::new(2001, &location, 11, false));
// AIR
Expand Down Expand Up @@ -518,7 +521,7 @@ impl Player {
)
.expect("All item ids are in the global registry");
if let Ok(block_state_id) = BlockState::new(minecraft_id, None) {
let entity = &self.entity;
let entity = &self.living_entity.entity;
let world = &entity.world;
world.broadcast_packet_all(&CBlockUpdate::new(
&location,
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/commands/cmd_kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn init_command_tree<'a>() -> CommandTree<'a> {
CommandTree::new(NAMES, DESCRIPTION).with_child(
argument(ARG_TARGET, consume_arg_target).execute(&|sender, server, args| {
let target = parse_arg_player(sender, server, ARG_TARGET, args)?;
target.entity.kill();
target.living_entity.kill();

sender.send_message(
TextComponent::text("Player has been killed.").color_named(NamedColor::Blue),
Expand Down
46 changes: 46 additions & 0 deletions pumpkin/src/entity/living.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crossbeam::atomic::AtomicCell;
use pumpkin_protocol::client::play::{CEntityStatus, CSetEntityMetadata, Metadata};

use super::Entity;

/// Represents a Living Entity (e.g. Player, Zombie, Enderman...)
pub struct LivingEntity {
pub entity: Entity,
/// The entity's current health level.
pub health: AtomicCell<f32>,
}

impl LivingEntity {
pub const fn new(entity: Entity) -> Self {
Self {
entity,
health: AtomicCell::new(20.0),
}
}

pub fn set_health(&self, health: f32) {
self.health.store(health);
// tell everyone entities health changed
self.entity
.world
.broadcast_packet_all(&CSetEntityMetadata::new(
self.entity.entity_id.into(),
Metadata::new(9, 3.into(), health),
));
}

/// Kills the Entity
///
/// This is similar to `kill` but Spawn Particles, Animation and plays death sound
pub fn kill(&self) {
// Spawns death smoke particles
self.entity
.world
.broadcast_packet_all(&CEntityStatus::new(self.entity.entity_id, 60));
// Plays the death sound and death animation
self.entity
.world
.broadcast_packet_all(&CEntityStatus::new(self.entity.entity_id, 3));
self.entity.remove();
}
}
19 changes: 3 additions & 16 deletions pumpkin/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ use pumpkin_core::math::{
};
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId};
use pumpkin_protocol::{
client::play::{CEntityStatus, CSetEntityMetadata, Metadata},
client::play::{CSetEntityMetadata, Metadata},
VarInt,
};

use crate::world::World;

pub mod living;
pub mod player;

/// Represents a not living Entity (e.g. Item, Egg, Snowball...)
pub struct Entity {
/// A unique identifier for the entity
pub entity_id: EntityId,
Expand All @@ -24,7 +26,6 @@ pub struct Entity {
/// The world in which the entity exists.
pub world: Arc<World>,
/// The entity's current health level.
pub health: AtomicCell<f32>,
/// The entity's current position in the world
pub pos: AtomicCell<Vector3<f64>>,
Expand Down Expand Up @@ -75,7 +76,6 @@ impl Entity {
sneaking: AtomicBool::new(false),
world,
// TODO: Load this from previous instance
health: AtomicCell::new(20.0),
sprinting: AtomicBool::new(false),
fall_flying: AtomicBool::new(false),
yaw: AtomicCell::new(0.0),
Expand Down Expand Up @@ -121,19 +121,6 @@ impl Entity {
self.pitch.store(pitch);
}

/// Kills the Entity
///
/// This is similar to `kill` but Spawn Particles, Animation and plays death sound
pub fn kill(&self) {
// Spawns death smoke particles
self.world
.broadcast_packet_all(&CEntityStatus::new(self.entity_id, 60));
// Plays the death sound and death animation
self.world
.broadcast_packet_all(&CEntityStatus::new(self.entity_id, 3));
self.remove();
}

/// Removes the Entity from their current World
pub fn remove(&self) {
self.world.remove_entity(self);
Expand Down
31 changes: 18 additions & 13 deletions pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,14 @@ use crate::{
world::World,
};

use super::Entity;
use super::{living::LivingEntity, Entity};

/// Represents a Minecraft player entity.
///
/// A `Player` is a special type of entity that represents a human player connected to the server.
pub struct Player {
/// The underlying entity object that represents the player.
pub entity: Entity,

/// The underlying living entity object that represents the player.
pub living_entity: LivingEntity,
/// The player's game profile information, including their username and UUID.
pub gameprofile: GameProfile,
/// The client connection associated with the player.
Expand Down Expand Up @@ -110,7 +109,12 @@ impl Player {
);
let config = client.config.lock().clone().unwrap_or_default();
Self {
entity: Entity::new(entity_id, world, EntityType::Player, 1.62),
living_entity: LivingEntity::new(Entity::new(
entity_id,
world,
EntityType::Player,
1.62,
)),
config: Mutex::new(config),
gameprofile,
client,
Expand All @@ -132,11 +136,11 @@ impl Player {

/// Removes the Player out of the current World
pub async fn remove(&self) {
self.entity.world.remove_player(self);
self.living_entity.entity.world.remove_player(self);
}

pub const fn entity_id(&self) -> EntityId {
self.entity.entity_id
self.living_entity.entity.entity_id
}

/// Updates the current abilities the Player has
Expand Down Expand Up @@ -174,7 +178,7 @@ impl Player {
.store(0, std::sync::atomic::Ordering::Relaxed);
}
let teleport_id = i + 1;
let entity = &self.entity;
let entity = &self.living_entity.entity;
entity.set_pos(x, y, z);
entity.set_rotation(yaw, pitch);
*self.awaiting_teleport.lock() = Some((teleport_id.into(), Vector3::new(x, y, z)));
Expand All @@ -200,8 +204,8 @@ impl Player {
pub fn can_interact_with_block_at(&self, pos: &WorldPosition, additional_range: f64) -> bool {
let d = self.block_interaction_range() + additional_range;
let box_pos = BoundingBox::from_block(pos);
let entity_pos = self.entity.pos.load();
let standing_eye_height = self.entity.standing_eye_height;
let entity_pos = self.living_entity.entity.pos.load();
let standing_eye_height = self.living_entity.entity.standing_eye_height;
box_pos.squared_magnitude(Vector3 {
x: entity_pos.x,
y: entity_pos.y + standing_eye_height as f64,
Expand All @@ -228,8 +232,8 @@ impl Player {
self.client.close()
}

pub fn update_health(&self, health: f32, food: i32, food_saturation: f32) {
self.entity.health.store(health);
pub fn set_health(&self, health: f32, food: i32, food_saturation: f32) {
self.living_entity.set_health(health);
self.food.store(food, std::sync::atomic::Ordering::Relaxed);
self.food_saturation.store(food_saturation);
self.client
Expand All @@ -246,7 +250,8 @@ impl Player {
self.gamemode.store(gamemode);
// So a little story time. I actually made an abilties_from_gamemode function. I looked at vanilla and they always send the abilties from the gamemode. But the funny thing actually is. That the client
// does actually use the same method and set the abilties when receiving the CGameEvent gamemode packet. Just Mojang nonsense
self.entity
self.living_entity
.entity
.world
.broadcast_packet_all(&CPlayerInfoUpdate::new(
0x04,
Expand Down
4 changes: 2 additions & 2 deletions pumpkin/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl World {
// spawn players for our client
let token = player.client.token;
for (_, existing_player) in self.current_players.lock().iter().filter(|c| c.0 != &token) {
let entity = &existing_player.entity;
let entity = &existing_player.living_entity.entity;
let pos = entity.pos.load();
let gameprofile = &existing_player.gameprofile;
player.client.send_packet(&CSpawnEntity::new(
Expand Down Expand Up @@ -293,7 +293,7 @@ impl World {
&[player.client.token],
&CRemovePlayerInfo::new(1.into(), &[uuid]),
);
self.remove_entity(&player.entity);
self.remove_entity(&player.living_entity.entity);
}

pub fn remove_entity(&self, entity: &Entity) {
Expand Down
4 changes: 2 additions & 2 deletions pumpkin/src/world/player_chunker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ fn get_view_distance(player: &Player) -> i8 {
}

pub async fn player_join(world: &World, player: Arc<Player>) {
let new_watched = chunk_section_from_pos(&player.entity.block_pos.load());
let new_watched = chunk_section_from_pos(&player.living_entity.entity.block_pos.load());
player.watched_section.store(new_watched);
let watched_section = new_watched;
let chunk_pos = player.entity.chunk_pos.load();
let chunk_pos = player.living_entity.entity.chunk_pos.load();
player.client.send_packet(&CCenterChunk {
chunk_x: chunk_pos.x.into(),
chunk_z: chunk_pos.z.into(),
Expand Down

0 comments on commit 9ac4bdb

Please sign in to comment.