diff --git a/pumpkin-core/src/math/position.rs b/pumpkin-core/src/math/position.rs index cd1f7ce26..7c51dff45 100644 --- a/pumpkin-core/src/math/position.rs +++ b/pumpkin-core/src/math/position.rs @@ -1,13 +1,33 @@ +use super::vector3::Vector3; use std::fmt; +use crate::math::vector2::Vector2; +use num_traits::Euclid; use serde::{Deserialize, Serialize}; -use super::vector3::Vector3; - #[derive(Clone, Copy)] /// Aka Block Position pub struct WorldPosition(pub Vector3); +impl WorldPosition { + pub fn chunk_and_chunk_relative_position(&self) -> (Vector2, Vector3) { + let (z_chunk, z_rem) = self.0.z.div_rem_euclid(&16); + let (x_chunk, x_rem) = self.0.x.div_rem_euclid(&16); + let chunk_coordinate = Vector2 { + x: x_chunk, + z: z_chunk, + }; + + // Since we divide by 16 remnant can never exceed u8 + let relative = Vector3 { + x: x_rem, + z: z_rem, + + y: self.0.y, + }; + (chunk_coordinate, relative) + } +} impl Serialize for WorldPosition { fn serialize(&self, serializer: S) -> Result where diff --git a/pumpkin-world/src/coordinates.rs b/pumpkin-world/src/coordinates.rs index fed4a49c4..f35c11453 100644 --- a/pumpkin-world/src/coordinates.rs +++ b/pumpkin-world/src/coordinates.rs @@ -1,12 +1,12 @@ use std::ops::Deref; +use crate::{WORLD_LOWEST_Y, WORLD_MAX_Y}; use derive_more::derive::{AsMut, AsRef, Display, Into}; use num_traits::{PrimInt, Signed, Unsigned}; use pumpkin_core::math::vector2::Vector2; +use pumpkin_core::math::vector3::Vector3; use serde::{Deserialize, Serialize}; -use crate::{WORLD_LOWEST_Y, WORLD_MAX_Y}; - #[derive( Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, AsRef, AsMut, Into, Display, )] @@ -130,3 +130,13 @@ impl ChunkRelativeXZBlockCoordinates { } } } + +impl From> for ChunkRelativeBlockCoordinates { + fn from(value: Vector3) -> Self { + Self { + x: (value.x as u8).into(), + z: (value.z as u8).into(), + y: value.y.into(), + } + } +} diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 2d303deda..8f5f74f62 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -6,7 +6,7 @@ use crate::{ client::Client, entity::{player::Player, Entity}, }; -use num_traits::{Euclid, ToPrimitive}; +use num_traits::ToPrimitive; use pumpkin_config::BasicConfiguration; use pumpkin_core::math::position::WorldPosition; use pumpkin_core::math::vector2::Vector2; @@ -20,11 +20,12 @@ use pumpkin_protocol::{ ClientPacket, VarInt, }; use pumpkin_world::block::BlockId; +use pumpkin_world::chunk::ChunkData; use pumpkin_world::coordinates::ChunkRelativeBlockCoordinates; use pumpkin_world::level::Level; use scoreboard::Scoreboard; -use tokio::sync::mpsc; use tokio::sync::Mutex; +use tokio::sync::{mpsc, RwLock}; pub mod scoreboard; @@ -285,7 +286,7 @@ impl World { level.mark_chunk_as_newly_watched(chunks).await; } - fn spawn_world_chunks(&self, client: Arc, chunks: Vec>, distance: i32) { + async fn spawn_world_chunks(&self, client: Arc, chunks: Vec>) { if client.closed.load(std::sync::atomic::Ordering::Relaxed) { log::info!( "The connection with {} has closed before world chunks were spawned", @@ -294,21 +295,10 @@ impl World { return; } let inst = std::time::Instant::now(); - let (sender, mut chunk_receiver) = mpsc::channel(distance as usize); - let client_id = client.id; - - { - let level = self.level.clone(); - tokio::spawn(async move { - log::debug!("Spawned chunk fetcher for {}", client_id); - let level = level.lock().await; - level.fetch_chunks(&chunks, sender); - }); - } + let chunks = self.get_chunks(chunks).await; tokio::spawn(async move { - log::debug!("Spawned chunk sender for {}", client_id); - while let Some(chunk_data) = chunk_receiver.recv().await { + for chunk_data in chunks { let chunk_data = chunk_data.read().await; let packet = CChunkData(&chunk_data); #[cfg(debug_assertions)] @@ -381,32 +371,32 @@ impl World { .await; } pub async fn set_block(&self, position: WorldPosition, block_id: BlockId) { - let (z_chunk, z_rem) = position.0.z.div_rem_euclid(&16); - let (x_chunk, x_rem) = position.0.x.div_rem_euclid(&16); - let chunk_coordinate = Vector2 { - x: x_chunk, - z: z_chunk, - }; + let (chunk_coordinate, relative_coordinates) = position.chunk_and_chunk_relative_position(); // Since we divide by 16 remnant can never exceed u8 - let relative = ChunkRelativeBlockCoordinates { - x: (x_rem as u8).into(), - z: (z_rem as u8).into(), - y: position.0.y.into(), - }; + let relative = ChunkRelativeBlockCoordinates::from(relative_coordinates); + let chunk = self.get_chunks(vec![chunk_coordinate]).await[0].clone(); + chunk.write().await.blocks.set_block(relative, block_id); + + self.broadcast_packet_all(&CBlockUpdate::new( + &position, + i32::from(block_id.data).into(), + )) + .await; + } + + pub async fn get_chunks(&self, chunks: Vec>) -> Vec>> { let (sender, mut receive) = mpsc::channel(1024); { let level = self.level.clone(); - tokio::spawn( - async move { level.lock().await.fetch_chunks(&[chunk_coordinate], sender) }, - ); + tokio::spawn(async move { level.lock().await.fetch_chunks(&chunks, sender) }); } - if let Some(data) = receive.recv().await { - data.write().await.blocks.set_block(relative, block_id); - self.broadcast_packet_all(&CBlockUpdate::new(&position, (block_id.data as i32).into())) - .await; + let mut received = vec![]; + while let Some(chunk) = receive.recv().await { + received.push(chunk); } + received } pub async fn break_block(&self, position: WorldPosition) { diff --git a/pumpkin/src/world/player_chunker.rs b/pumpkin/src/world/player_chunker.rs index 3965ba560..7842245f9 100644 --- a/pumpkin/src/world/player_chunker.rs +++ b/pumpkin/src/world/player_chunker.rs @@ -74,7 +74,9 @@ pub async fn player_join(world: &World, player: Arc) { if !loading_chunks.is_empty() { world.mark_chunks_as_watched(&loading_chunks).await; - world.spawn_world_chunks(player.client.clone(), loading_chunks, view_distance); + world + .spawn_world_chunks(player.client.clone(), loading_chunks) + .await; } if !unloading_chunks.is_empty() { @@ -134,7 +136,8 @@ pub async fn update_position(player: &Player) { entity.world.mark_chunks_as_watched(&loading_chunks).await; entity .world - .spawn_world_chunks(player.client.clone(), loading_chunks, view_distance); + .spawn_world_chunks(player.client.clone(), loading_chunks) + .await; } if !unloading_chunks.is_empty() {