Add Clientbound Entity Status

This commit is contained in:
Snowiiii 2024-09-12 15:42:26 +02:00
parent a60980508e
commit f9bf750b65
11 changed files with 99 additions and 23 deletions

View File

@ -0,0 +1,18 @@
use pumpkin_macros::packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(0x1F)]
pub struct CEntityStatus {
entity_id: i32,
entity_status: i8,
}
impl CEntityStatus {
pub fn new(entity_id: i32, entity_status: i8) -> Self {
Self {
entity_id,
entity_status,
}
}
}

View File

@ -8,8 +8,30 @@ pub struct CGameEvent {
value: f32, value: f32,
} }
/// Somewhere you need to implement all the random stuff right?
impl CGameEvent { impl CGameEvent {
pub fn new(event: u8, value: f32) -> Self { pub fn new(event: GameEvent, value: f32) -> Self {
Self { event, value } Self {
event: event as u8,
value,
}
} }
} }
#[repr(u8)]
pub enum GameEvent {
NoRespawnBlockAvailable,
BeginRaining,
EndRaining,
ChangeGameMode,
WinGame,
DemoEvent,
ArrowHitPlayer,
RainLevelChange,
ThunderLevelChange,
PlayPufferfishStringSound,
PlayElderGuardianMobAppearance,
EnabledRespawnScreen,
LimitedCrafting,
StartWaitingChunks,
}

View File

@ -9,6 +9,7 @@ mod c_close_container;
mod c_disguised_chat_message; mod c_disguised_chat_message;
mod c_entity_animation; mod c_entity_animation;
mod c_entity_metadata; mod c_entity_metadata;
mod c_entity_status;
mod c_entity_velocity; mod c_entity_velocity;
mod c_game_event; mod c_game_event;
mod c_head_rot; mod c_head_rot;
@ -51,6 +52,7 @@ pub use c_close_container::*;
pub use c_disguised_chat_message::*; pub use c_disguised_chat_message::*;
pub use c_entity_animation::*; pub use c_entity_animation::*;
pub use c_entity_metadata::*; pub use c_entity_metadata::*;
pub use c_entity_status::*;
pub use c_entity_velocity::*; pub use c_entity_velocity::*;
pub use c_game_event::*; pub use c_game_event::*;
pub use c_head_rot::*; pub use c_head_rot::*;

View File

@ -379,7 +379,7 @@ impl Player {
let config = &ADVANCED_CONFIG.pvp; let config = &ADVANCED_CONFIG.pvp;
if config.enabled { if config.enabled {
let world = &entity.world; let world = &entity.world;
let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId); let attacked_player = world.get_player_by_entityid(entity_id.0 as EntityId);
if let Some(player) = attacked_player { if let Some(player) = attacked_player {
let victem_entity = &player.entity; let victem_entity = &player.entity;
if config.protect_creative if config.protect_creative

View File

@ -1,8 +1,11 @@
use std::sync::Arc;
use crate::commands::dispatcher::InvalidTreeError; use crate::commands::dispatcher::InvalidTreeError;
use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError;
use crate::commands::tree::{ConsumedArgs, RawArgs}; use crate::commands::tree::{ConsumedArgs, RawArgs};
use crate::commands::CommandSender; use crate::commands::CommandSender;
use crate::commands::CommandSender::Player; use crate::commands::CommandSender::Player;
use crate::server::Server;
/// todo: implement (so far only own name + @s/@p is implemented) /// todo: implement (so far only own name + @s/@p is implemented)
pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option<String> { pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option<String> {
@ -29,6 +32,7 @@ pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option<Str
/// todo: implement (so far only own name + @s/@p is implemented) /// todo: implement (so far only own name + @s/@p is implemented)
pub fn parse_arg_player<'a>( pub fn parse_arg_player<'a>(
src: &'a mut CommandSender, src: &'a mut CommandSender,
_server: &Arc<Server>,
arg_name: &str, arg_name: &str,
consumed_args: &ConsumedArgs, consumed_args: &ConsumedArgs,
) -> Result<&'a crate::entity::player::Player, InvalidTreeError> { ) -> Result<&'a crate::entity::player::Player, InvalidTreeError> {

View File

@ -85,9 +85,9 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
}), }),
) )
.with_child(argument(ARG_TARGET, consume_arg_player).execute( .with_child(argument(ARG_TARGET, consume_arg_player).execute(
&|sender, _, args| { &|sender, server, args| {
let gamemode = parse_arg_gamemode(args)?; let gamemode = parse_arg_gamemode(args)?;
let target = parse_arg_player(sender, ARG_TARGET, args)?; let target = parse_arg_player(sender, server, ARG_TARGET, args)?;
if target.gamemode.load() == gamemode { if target.gamemode.load() == gamemode {
target.send_system_message(TextComponent::text(&format!( target.send_system_message(TextComponent::text(&format!(

View File

@ -8,7 +8,7 @@ use pumpkin_core::math::{
}; };
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId};
use pumpkin_protocol::{ use pumpkin_protocol::{
client::play::{CSetEntityMetadata, Metadata}, client::play::{CEntityStatus, CSetEntityMetadata, Metadata},
VarInt, VarInt,
}; };
@ -121,8 +121,21 @@ impl Entity {
self.pitch.store(pitch); self.pitch.store(pitch);
} }
/// Kills the Entity
///
/// This is simliar 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 /// Removes the Entity from their current World
pub async fn remove(&mut self) { pub fn remove(&self) {
self.world.remove_entity(self); self.world.remove_entity(self);
} }

View File

@ -18,7 +18,7 @@ use pumpkin_protocol::{
bytebuf::{packet_id::Packet, DeserializerError}, bytebuf::{packet_id::Packet, DeserializerError},
client::play::{ client::play::{
CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSyncPlayerPosition, CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSyncPlayerPosition,
CSystemChatMessage, PlayerAction, CSystemChatMessage, GameEvent, PlayerAction,
}, },
server::play::{ server::play::{
SChatCommand, SChatMessage, SClickContainer, SClientInformationPlay, SConfirmTeleport, SChatCommand, SChatMessage, SClickContainer, SClientInformationPlay, SConfirmTeleport,
@ -248,8 +248,10 @@ impl Player {
actions: vec![PlayerAction::UpdateGameMode((gamemode as i32).into())], actions: vec![PlayerAction::UpdateGameMode((gamemode as i32).into())],
}], }],
)); ));
self.client self.client.send_packet(&CGameEvent::new(
.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); GameEvent::ChangeGameMode,
gamemode.to_f32().unwrap(),
));
} }
pub fn send_system_message(&self, text: TextComponent) { pub fn send_system_message(&self, text: TextComponent) {

View File

@ -170,10 +170,7 @@ fn main() -> io::Result<()> {
if closed { if closed {
if let Some(player) = players.remove(&token) { if let Some(player) = players.remove(&token) {
player.remove().await; player.remove().await;
dbg!("b");
let connection = &mut player.client.connection.lock(); let connection = &mut player.client.connection.lock();
dbg!("c");
poll.registry().deregister(connection.by_ref())?; poll.registry().deregister(connection.by_ref())?;
} }
} }

View File

@ -158,6 +158,16 @@ impl Server {
} }
} }
/// Searches every world for a player by name
pub fn get_player_by_name(&self, name: &str) -> Option<Arc<Player>> {
for world in self.worlds.iter() {
if let Some(player) = world.get_player_by_name(name) {
return Some(player);
}
}
None
}
/// Generates a new entity id /// Generates a new entity id
/// This should be global /// This should be global
pub fn new_entity_id(&self) -> EntityId { pub fn new_entity_id(&self) -> EntityId {

View File

@ -11,7 +11,7 @@ use pumpkin_entity::{entity_type::EntityType, EntityId};
use pumpkin_protocol::{ use pumpkin_protocol::{
client::play::{ client::play::{
CChunkData, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, CRemoveEntities, CChunkData, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, CRemoveEntities,
CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, Metadata, PlayerAction, CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, GameEvent, Metadata, PlayerAction,
}, },
uuid::UUID, uuid::UUID,
ClientPacket, VarInt, ClientPacket, VarInt,
@ -216,8 +216,10 @@ impl World {
self.broadcast_packet_all(&packet) self.broadcast_packet_all(&packet)
} }
// Start waiting for level chunks // Start waiting for level chunks, Sets the "Loading Terrain" screen
player.client.send_packet(&CGameEvent::new(13, 0.0)); player
.client
.send_packet(&CGameEvent::new(GameEvent::StartWaitingChunks, 0.0));
// Spawn in inital chunks // Spawn in inital chunks
player_chunker::player_join(self, player.clone()).await; player_chunker::player_join(self, player.clone()).await;
@ -258,13 +260,9 @@ impl World {
dbg!("DONE CHUNKS", inst.elapsed()); dbg!("DONE CHUNKS", inst.elapsed());
} }
pub fn get_by_entityid(&self, from: &Player, id: EntityId) -> Option<Arc<Player>> { /// Gets a Player by entity id
for (_, player) in self pub fn get_player_by_entityid(&self, id: EntityId) -> Option<Arc<Player>> {
.current_players for (_, player) in self.current_players.lock().iter() {
.lock()
.iter()
.filter(|c| c.0 != &from.client.token)
{
if player.entity_id() == id { if player.entity_id() == id {
return Some(player.clone()); return Some(player.clone());
} }
@ -272,6 +270,16 @@ impl World {
None None
} }
/// Gets a Player by name
pub fn get_player_by_name(&self, name: &str) -> Option<Arc<Player>> {
for (_, player) in self.current_players.lock().iter() {
if player.gameprofile.name == name {
return Some(player.clone());
}
}
None
}
pub fn add_player(&self, token: Token, player: Arc<Player>) { pub fn add_player(&self, token: Token, player: Arc<Player>) {
self.current_players.lock().insert(token, player); self.current_players.lock().insert(token, player);
} }