From 2ee9710f939dd2e8d6ed7cd2bec6fa1b1e7ae4d2 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 7 Sep 2024 19:33:01 +0200 Subject: [PATCH] Refactor Entity --- Cargo.lock | 3 - pumpkin-entity/Cargo.toml | 1 - pumpkin-entity/src/lib.rs | 59 ------ .../src/client/play/c_play_disconnect.rs | 4 +- pumpkin/src/client/mod.rs | 2 +- pumpkin/src/client/player_packet.rs | 96 ++++++--- pumpkin/src/entity/mod.rs | 194 ++++++++++++++++++ pumpkin/src/entity/player.rs | 114 ++-------- pumpkin/src/world/mod.rs | 11 +- 9 files changed, 289 insertions(+), 195 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1d3c4a2d..14caa4d65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1916,9 +1916,6 @@ dependencies = [ [[package]] name = "pumpkin-entity" version = "0.1.0" -dependencies = [ - "pumpkin-core", -] [[package]] name = "pumpkin-inventory" diff --git a/pumpkin-entity/Cargo.toml b/pumpkin-entity/Cargo.toml index 60d12a21e..df71af011 100644 --- a/pumpkin-entity/Cargo.toml +++ b/pumpkin-entity/Cargo.toml @@ -4,4 +4,3 @@ version.workspace = true edition.workspace = true [dependencies] -pumpkin-core = { path = "../pumpkin-core"} \ No newline at end of file diff --git a/pumpkin-entity/src/lib.rs b/pumpkin-entity/src/lib.rs index bf7e91c00..b820b1009 100644 --- a/pumpkin-entity/src/lib.rs +++ b/pumpkin-entity/src/lib.rs @@ -1,63 +1,4 @@ -use entity_type::EntityType; -use pose::EntityPose; -use pumpkin_core::math::{ - get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3, -}; - pub mod entity_type; pub mod pose; pub type EntityId = i32; - -pub struct Entity { - pub entity_id: EntityId, - pub entity_type: EntityType, - pub pos: Vector3, - pub block_pos: WorldPosition, - pub chunk_pos: Vector2, - - pub yaw: f32, - pub head_yaw: f32, - pub pitch: f32, - // TODO: Change this in diffrent poses - pub standing_eye_height: f32, - pub pose: EntityPose, -} - -impl Entity { - pub fn new(entity_id: EntityId, entity_type: EntityType, standing_eye_height: f32) -> Self { - Self { - entity_id, - entity_type, - pos: Vector3::new(0.0, 0.0, 0.0), - block_pos: WorldPosition(Vector3::new(0, 0, 0)), - chunk_pos: Vector2::new(0, 0), - yaw: 0.0, - head_yaw: 0.0, - pitch: 0.0, - standing_eye_height, - pose: EntityPose::Standing, - } - } - - pub fn set_pos(&mut self, x: f64, y: f64, z: f64) { - if self.pos.x != x || self.pos.y != y || self.pos.z != z { - self.pos = Vector3::new(x, y, z); - let i = x.floor() as i32; - let j = y.floor() as i32; - let k = z.floor() as i32; - - let block_pos = self.block_pos.0; - if i != block_pos.x || j != block_pos.y || k != block_pos.z { - self.block_pos = WorldPosition(Vector3::new(i, j, k)); - - if get_section_cord(i) != self.chunk_pos.x - || get_section_cord(k) != self.chunk_pos.z - { - self.chunk_pos = - Vector2::new(get_section_cord(block_pos.x), get_section_cord(block_pos.z)); - } - } - } - } -} diff --git a/pumpkin-protocol/src/client/play/c_play_disconnect.rs b/pumpkin-protocol/src/client/play/c_play_disconnect.rs index 7140e3f63..50683b037 100644 --- a/pumpkin-protocol/src/client/play/c_play_disconnect.rs +++ b/pumpkin-protocol/src/client/play/c_play_disconnect.rs @@ -5,11 +5,11 @@ use serde::Serialize; #[derive(Serialize)] #[packet(0x1D)] pub struct CPlayDisconnect<'a> { - reason: TextComponent<'a>, + reason: &'a TextComponent<'a>, } impl<'a> CPlayDisconnect<'a> { - pub fn new(reason: TextComponent<'a>) -> Self { + pub fn new(reason: &'a TextComponent<'a>) -> Self { Self { reason } } } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index c100dae3f..a43486089 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -323,7 +323,7 @@ impl Client { } // So we can also kick on errors, but generally should use Player::kick ConnectionState::Play => { - self.try_send_packet(&CPlayDisconnect::new(TextComponent::text(reason))) + self.try_send_packet(&CPlayDisconnect::new(&TextComponent::text(reason))) .unwrap_or_else(|_| self.close()); } _ => { diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 3d38f7b71..bc7936b88 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -82,15 +82,27 @@ impl Player { Self::clamp_vertical(position.feet_y), Self::clamp_horizontal(position.z), ); - // TODO: teleport when moving > 8 block - - // send new position to all other players - let on_ground = self.on_ground; + entity.on_ground = position.ground; + let on_ground = entity.on_ground; let entity_id = entity.entity_id; let (x, y, z) = entity.pos.into(); let (lastx, lasty, lastz) = self.last_position.into(); let world = self.world.clone(); let world = world.lock().await; + + // let delta = Vector3::new(x - lastx, y - lasty, z - lastz); + // let velocity = self.velocity; + + // // Player is falling down fast, we should account for that + // let max_speed = if self.fall_flying { 300.0 } else { 100.0 }; + + // teleport when more than 8 blocks (i guess 8 blocks) + // TODO: REPLACE * 2.0 by movement packets. see vanilla for details + // if delta.length_squared() - velocity.length_squared() > max_speed * 2.0 { + // self.teleport(x, y, z, self.entity.yaw, self.entity.pitch); + // return; + // } + // send new position to all other players world.broadcast_packet( &[self.client.token], &CUpdateEntityPos::new( @@ -128,11 +140,11 @@ impl Player { Self::clamp_vertical(position_rotation.feet_y), Self::clamp_horizontal(position_rotation.z), ); + entity.on_ground = position_rotation.ground; entity.yaw = wrap_degrees(position_rotation.yaw) % 360.0; entity.pitch = wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0; - // send new position to all other players - let on_ground = self.on_ground; + let on_ground = entity.on_ground; let entity_id = entity.entity_id; let (x, y, z) = entity.pos.into(); let (lastx, lasty, lastz) = self.last_position.into(); @@ -142,6 +154,20 @@ impl Player { let world = self.world.clone(); let world = world.lock().await; + // let delta = Vector3::new(x - lastx, y - lasty, z - lastz); + // let velocity = self.velocity; + + // // Player is falling down fast, we should account for that + // let max_speed = if self.fall_flying { 300.0 } else { 100.0 }; + + // // teleport when more than 8 blocks (i guess 8 blocks) + // // TODO: REPLACE * 2.0 by movement packets. see vanilla for details + // if delta.length_squared() - velocity.length_squared() > max_speed * 2.0 { + // self.teleport(x, y, z, yaw, pitch); + // return; + // } + // send new position to all other players + world.broadcast_packet( &[self.client.token], &CUpdateEntityPosRot::new( @@ -168,10 +194,11 @@ impl Player { return; } let entity = &mut self.entity; + entity.on_ground = rotation.ground; entity.yaw = wrap_degrees(rotation.yaw) % 360.0; entity.pitch = wrap_degrees(rotation.pitch).clamp(-90.0, 90.0) % 360.0; // send new position to all other players - let on_ground = self.on_ground; + let on_ground = entity.on_ground; let entity_id = entity.entity_id; let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0); let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0); @@ -191,7 +218,7 @@ impl Player { } pub fn handle_player_ground(&mut self, _server: &mut Server, ground: SSetPlayerGround) { - self.on_ground = ground.on_ground; + self.entity.on_ground = ground.on_ground; } pub async fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) { @@ -202,30 +229,45 @@ impl Player { if let Some(action) = Action::from_i32(command.action.0) { match action { pumpkin_protocol::server::play::Action::StartSneaking => { - if !self.sneaking { - self.set_sneaking(true).await + if !self.entity.sneaking { + self.entity + .set_sneaking(&mut self.client, self.world.clone(), true) + .await } } pumpkin_protocol::server::play::Action::StopSneaking => { - if self.sneaking { - self.set_sneaking(false).await + if self.entity.sneaking { + self.entity + .set_sneaking(&mut self.client, self.world.clone(), false) + .await } } pumpkin_protocol::server::play::Action::LeaveBed => todo!(), pumpkin_protocol::server::play::Action::StartSprinting => { - if !self.sprinting { - self.set_sprinting(true).await + if !self.entity.sprinting { + self.entity + .set_sprinting(&mut self.client, self.world.clone(), true) + .await } } pumpkin_protocol::server::play::Action::StopSprinting => { - if self.sprinting { - self.set_sprinting(false).await + if self.entity.sprinting { + self.entity + .set_sprinting(&mut self.client, self.world.clone(), false) + .await } } pumpkin_protocol::server::play::Action::StartHorseJump => todo!(), pumpkin_protocol::server::play::Action::StopHorseJump => todo!(), pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(), - pumpkin_protocol::server::play::Action::StartFlyingElytra => {} // TODO + pumpkin_protocol::server::play::Action::StartFlyingElytra => { + let fall_flying = self.entity.check_fall_flying(); + if self.entity.fall_flying != fall_flying { + self.entity + .set_fall_flying(&mut self.client, self.world.clone(), fall_flying) + .await; + } + } // TODO } } else { self.kick(TextComponent::text("Invalid player command")) @@ -320,8 +362,10 @@ impl Player { pub async fn handle_interact(&mut self, _: &mut Server, interact: SInteract) { let sneaking = interact.sneaking; - if self.sneaking != sneaking { - self.set_sneaking(sneaking).await; + if self.entity.sneaking != sneaking { + self.entity + .set_sneaking(&mut self.client, self.world.clone(), sneaking) + .await; } match ActionType::from_i32(interact.typ.0) { Some(action) => match action { @@ -335,27 +379,27 @@ impl Player { let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId); if let Some(mut player) = attacked_player { let token = player.client.token; - let velo = player.velocity; + let velo = player.entity.velocity; if config.protect_creative && player.gamemode == GameMode::Creative { return; } if config.knockback { let yaw = self.entity.yaw; let strength = 1.0; - player.knockback( + player.entity.knockback( strength * 0.5, (yaw * (PI / 180.0)).sin() as f64, -(yaw * (PI / 180.0)).cos() as f64, ); let packet = &CEntityVelocity::new( &entity_id, - player.velocity.x as f32, - player.velocity.y as f32, - player.velocity.z as f32, + velo.x as f32, + velo.y as f32, + velo.z as f32, ); - self.velocity = self.velocity.multiply(0.6, 1.0, 0.6); + self.entity.velocity = self.entity.velocity.multiply(0.6, 1.0, 0.6); - player.velocity = velo; + player.entity.velocity = velo; player.client.send_packet(packet); } if config.hurt_animation { diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index f28d7c205..1e07a66ad 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -1 +1,195 @@ +use std::sync::Arc; + +use pumpkin_core::math::{ + get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3, +}; +use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; +use pumpkin_protocol::{ + client::play::{CSetEntityMetadata, Metadata}, + VarInt, +}; + +use crate::{client::Client, world::World}; + pub mod player; + +pub struct Entity { + pub entity_id: EntityId, + pub entity_type: EntityType, + pub pos: Vector3, + pub block_pos: WorldPosition, + pub chunk_pos: Vector2, + + pub sneaking: bool, + pub sprinting: bool, + pub fall_flying: bool, + pub velocity: Vector3, + + // Should be not trusted + pub on_ground: bool, + + pub yaw: f32, + pub head_yaw: f32, + pub pitch: f32, + // TODO: Change this in diffrent poses + pub standing_eye_height: f32, + pub pose: EntityPose, +} + +// TODO: Remove client: &mut Client, world: Arc> bs +impl Entity { + pub fn new(entity_id: EntityId, entity_type: EntityType, standing_eye_height: f32) -> Self { + Self { + entity_id, + entity_type, + on_ground: false, + pos: Vector3::new(0.0, 0.0, 0.0), + block_pos: WorldPosition(Vector3::new(0, 0, 0)), + chunk_pos: Vector2::new(0, 0), + sneaking: false, + sprinting: false, + fall_flying: false, + yaw: 0.0, + head_yaw: 0.0, + pitch: 0.0, + velocity: Vector3::new(0.0, 0.0, 0.0), + standing_eye_height, + pose: EntityPose::Standing, + } + } + + pub fn set_pos(&mut self, x: f64, y: f64, z: f64) { + if self.pos.x != x || self.pos.y != y || self.pos.z != z { + self.pos = Vector3::new(x, y, z); + let i = x.floor() as i32; + let j = y.floor() as i32; + let k = z.floor() as i32; + + let block_pos = self.block_pos.0; + if i != block_pos.x || j != block_pos.y || k != block_pos.z { + self.block_pos = WorldPosition(Vector3::new(i, j, k)); + + if get_section_cord(i) != self.chunk_pos.x + || get_section_cord(k) != self.chunk_pos.z + { + self.chunk_pos = + Vector2::new(get_section_cord(block_pos.x), get_section_cord(block_pos.z)); + } + } + } + } + + pub fn knockback(&mut self, strength: f64, x: f64, z: f64) { + // This has some vanilla magic + let mut x = x; + let mut z = z; + while x * x + z * z < 1.0E-5 { + x = (rand::random::() - rand::random::()) * 0.01; + z = (rand::random::() - rand::random::()) * 0.01; + } + + let var8 = Vector3::new(x, 0.0, z).normalize() * strength; + let var7 = self.velocity; + self.velocity = Vector3::new( + var7.x / 2.0 - var8.x, + if self.on_ground { + (var7.y / 2.0 + strength).min(0.4) + } else { + var7.y + }, + var7.z / 2.0 - var8.z, + ); + } + + pub async fn set_sneaking( + &mut self, + client: &mut Client, + world: Arc>, + sneaking: bool, + ) { + assert!(self.sneaking != sneaking); + self.sneaking = sneaking; + self.set_flag(client, world, Self::SNEAKING_FLAG_INDEX, sneaking) + .await; + // if sneaking { + // self.set_pose(EntityPose::Crouching).await; + // } else { + // self.set_pose(EntityPose::Standing).await; + // } + } + + pub async fn set_sprinting( + &mut self, + client: &mut Client, + world: Arc>, + sprinting: bool, + ) { + assert!(self.sprinting != sprinting); + self.sprinting = sprinting; + self.set_flag(client, world, Self::SPRINTING_FLAG_INDEX, sprinting) + .await; + } + + pub fn check_fall_flying(&self) -> bool { + !self.on_ground + } + + pub async fn set_fall_flying( + &mut self, + client: &mut Client, + world: Arc>, + fall_flying: bool, + ) { + assert!(self.fall_flying != fall_flying); + self.fall_flying = fall_flying; + self.set_flag(client, world, Self::FALL_FLYING_FLAG_INDEX, fall_flying) + .await; + } + + pub const ON_FIRE_FLAG_INDEX: u32 = 0; + pub const SNEAKING_FLAG_INDEX: u32 = 1; + pub const SPRINTING_FLAG_INDEX: u32 = 3; + pub const SWIMMING_FLAG_INDEX: u32 = 4; + pub const INVISIBLE_FLAG_INDEX: u32 = 5; + pub const GLOWING_FLAG_INDEX: u32 = 6; + pub const FALL_FLYING_FLAG_INDEX: u32 = 7; + async fn set_flag( + &mut self, + client: &mut Client, + world: Arc>, + index: u32, + value: bool, + ) { + let mut b = 0i8; + if value { + b |= 1 << index; + } else { + b &= !(1 << index); + } + let packet = CSetEntityMetadata::new(self.entity_id.into(), Metadata::new(0, 0.into(), b)); + client.send_packet(&packet); + world + .lock() + .await + .broadcast_packet(&[client.token], &packet); + } + + pub async fn set_pose( + &mut self, + client: &mut Client, + world: Arc>, + pose: EntityPose, + ) { + self.pose = pose; + let pose = self.pose as i32; + let packet = CSetEntityMetadata::::new( + self.entity_id.into(), + Metadata::new(6, 20.into(), (pose).into()), + ); + client.send_packet(&packet); + world + .lock() + .await + .broadcast_packet(&[client.token], &packet) + } +} diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 35b9b46b8..2689b5e79 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -7,13 +7,13 @@ use pumpkin_core::{ text::TextComponent, GameMode, }; -use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, Entity, EntityId}; +use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_inventory::player::PlayerInventory; use pumpkin_protocol::{ bytebuf::{packet_id::Packet, DeserializerError}, client::play::{ - CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSetEntityMetadata, - CSyncPlayerPosition, CSystemChatMessage, Metadata, PlayerAction, + CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSyncPlayerPosition, + CSystemChatMessage, PlayerAction, }, server::play::{ SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, @@ -30,6 +30,8 @@ use crate::{ world::World, }; +use super::Entity; + pub struct PlayerAbilities { pub invulnerable: bool, pub flying: bool, @@ -53,9 +55,10 @@ impl Default for PlayerAbilities { } pub struct Player { + pub entity: Entity, + pub gameprofile: GameProfile, pub client: Client, - pub entity: Entity, pub config: PlayerConfig, // TODO: Put this into entity pub world: Arc>, @@ -68,20 +71,11 @@ pub struct Player { pub inventory: PlayerInventory, /// send `send_abilties_update` when changed pub abilities: PlayerAbilities, - pub last_position: Vector3, - // Client side value, Should be not trusted - pub on_ground: bool, - - pub sneaking: bool, - pub sprinting: bool, // TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done pub current_block_destroy_stage: u8, - // TODO: prbly should put this into an Living Entitiy or something - pub velocity: Vector3, - pub teleport_id_count: i32, // Current awaiting teleport id and location, None if did not teleport pub awaiting_teleport: Option<(VarInt, Vector3)>, @@ -110,21 +104,17 @@ impl Player { }; let config = client.config.clone().unwrap_or_default(); Self { + entity: Entity::new(entity_id, EntityType::Player, 1.62), config, gameprofile, client, - entity: Entity::new(entity_id, EntityType::Player, 1.62), world, - on_ground: false, awaiting_teleport: None, - sneaking: false, - sprinting: false, // TODO: Load this from previous instance health: 20.0, food: 20, food_saturation: 20.0, current_block_destroy_stage: 0, - velocity: Vector3::new(0.0, 0.0, 0.0), inventory: PlayerInventory::new(), teleport_id_count: 0, abilities: PlayerAbilities::default(), @@ -144,28 +134,6 @@ impl Player { self.entity.entity_id } - pub fn knockback(&mut self, strength: f64, x: f64, z: f64) { - // This has some vanilla magic - let mut x = x; - let mut z = z; - while x * x + z * z < 1.0E-5 { - x = (rand::random::() - rand::random::()) * 0.01; - z = (rand::random::() - rand::random::()) * 0.01; - } - - let var8 = Vector3::new(x, 0.0, z).normalize() * strength; - let var7 = self.velocity; - self.velocity = Vector3::new( - var7.x / 2.0 - var8.x, - if self.on_ground { - (var7.y / 2.0 + strength).min(0.4) - } else { - var7.y - }, - var7.z / 2.0 - var8.z, - ); - } - pub fn send_abilties_update(&mut self) { let mut b = 0i8; let abilities = &self.abilities; @@ -189,60 +157,6 @@ impl Player { )); } - pub async fn set_sneaking(&mut self, sneaking: bool) { - assert!(self.sneaking != sneaking); - self.sneaking = sneaking; - self.set_flag(Self::SNEAKING_FLAG_INDEX, sneaking).await; - // if sneaking { - // self.set_pose(EntityPose::Crouching).await; - // } else { - // self.set_pose(EntityPose::Standing).await; - // } - } - - pub async fn set_sprinting(&mut self, sprinting: bool) { - assert!(self.sprinting != sprinting); - self.sprinting = sprinting; - self.set_flag(Self::SPRINTING_FLAG_INDEX, sprinting).await; - } - - pub const ON_FIRE_FLAG_INDEX: u32 = 0; - pub const SNEAKING_FLAG_INDEX: u32 = 1; - pub const SPRINTING_FLAG_INDEX: u32 = 3; - pub const SWIMMING_FLAG_INDEX: u32 = 4; - pub const INVISIBLE_FLAG_INDEX: u32 = 5; - pub const GLOWING_FLAG_INDEX: u32 = 6; - pub const FALL_FLYING_FLAG_INDEX: u32 = 7; - async fn set_flag(&mut self, index: u32, value: bool) { - let mut b = 0i8; - if value { - b |= 1 << index; - } else { - b &= !(1 << index); - } - let packet = - CSetEntityMetadata::new(self.entity_id().into(), Metadata::new(0, 0.into(), b)); - self.client.send_packet(&packet); - self.world - .lock() - .await - .broadcast_packet(&[self.client.token], &packet); - } - - pub async fn set_pose(&mut self, pose: EntityPose) { - self.entity.pose = pose; - let pose = self.entity.pose as i32; - let packet = CSetEntityMetadata::::new( - self.entity_id().into(), - Metadata::new(6, 20.into(), (pose).into()), - ); - self.client.send_packet(&packet); - self.world - .lock() - .await - .broadcast_packet(&[self.client.token], &packet) - } - pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { // this is the ultra special magic code used to create the teleport id self.teleport_id_count += 1; @@ -251,7 +165,6 @@ impl Player { } let entity = &mut self.entity; entity.set_pos(x, y, z); - self.last_position = entity.pos; entity.yaw = yaw; entity.pitch = pitch; self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z))); @@ -287,11 +200,16 @@ impl Player { /// Kicks the Client with a reason depending on the connection state pub fn kick(&mut self, reason: TextComponent) { assert!(self.client.connection_state == ConnectionState::Play); - dbg!(&reason); + assert!(!self.client.closed); + self.client - .try_send_packet(&CPlayDisconnect::new(reason)) + .try_send_packet(&CPlayDisconnect::new(&reason)) .unwrap_or_else(|_| self.client.close()); - + log::info!( + "Kicked {} for {}", + self.gameprofile.name, + reason.to_pretty_console() + ); self.client.close() } diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index fbca46437..590763585 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -158,9 +158,6 @@ impl World { .client .send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries)); - // Start waiting for level chunks - player.client.send_packet(&CGameEvent::new(13, 0.0)); - let gameprofile = &player.gameprofile; // spawn player for every client @@ -216,6 +213,9 @@ impl World { self.broadcast_packet(&[player.client.token], &packet) } + // Start waiting for level chunks + player.client.send_packet(&CGameEvent::new(13, 0.0)); + // Spawn in inital chunks player_chunker::player_join(self, player).await; } @@ -231,8 +231,9 @@ impl World { let level = self.level.clone(); let closed = client.closed; - tokio::spawn(async move { - level.lock().unwrap().fetch_chunks(&chunks, sender, closed); + let chunks = Arc::new(chunks); + tokio::task::spawn_blocking(move || { + level.lock().unwrap().fetch_chunks(&chunks, sender, closed) }); while let Some(chunk_data) = chunk_receiver.recv().await {