From ddbe987317a7fbb87a43418468ba77a38bae2fd0 Mon Sep 17 00:00:00 2001 From: DimitriTimoz Date: Tue, 14 Nov 2023 00:27:08 +0100 Subject: [PATCH] Refactor chunk loading and sending code --- .../src/player_handler/handshake.rs | 39 +++--------------- minecraft-server/src/player_handler/play.rs | 40 ++++--------------- minecraft-server/src/prelude.rs | 2 +- minecraft-server/src/world/map.rs | 34 +++++++++++----- minecraft-server/src/world/mod.rs | 4 +- 5 files changed, 41 insertions(+), 78 deletions(-) diff --git a/minecraft-server/src/player_handler/handshake.rs b/minecraft-server/src/player_handler/handshake.rs index 086869a6..1ec59b07 100644 --- a/minecraft-server/src/player_handler/handshake.rs +++ b/minecraft-server/src/player_handler/handshake.rs @@ -314,42 +314,15 @@ pub async fn handshake(stream: &mut TcpStream, logged_in_player_info: LoggedInPl } } world.update_loaded_chunks(logged_in_player_info.uuid, loaded_chunks).await; - - let mut heightmaps = HashMap::new(); - heightmaps.insert(String::from("MOTION_BLOCKING"), NbtTag::LongArray(vec![0; 37])); - let heightmaps = NbtTag::Compound(heightmaps); for cx in -3..=3 { for cz in -3..=3 { - let mut column = Vec::new(); - for cy in -4..20 { - let chunk = world.get_network_chunk(ChunkPosition { cx, cy, cz }).await.unwrap_or_else(|| { - error!("Chunk not loaded: {cx} {cy} {cz}"); - NetworkChunk { // TODO hard error - block_count: 0, - blocks: PalettedData::Single { value: 0 }, - biomes: PalettedData::Single { value: 4 }, - } - }); - column.push(chunk); - } - let serialized: Vec = NetworkChunk::into_data(column).unwrap(); - let chunk_data = PlayClientbound::ChunkData { - value: ChunkData { - chunk_x: cx, - chunk_z: cz, - heightmaps: heightmaps.clone(), - data: Array::from(serialized.clone()), - block_entities: Array::default(), - sky_light_mask: Array::default(), - block_light_mask: Array::default(), - empty_sky_light_mask: Array::default(), - empty_block_light_mask: Array::default(), - sky_light: Array::default(), - block_light: Array::default(), - } - }; - send_packet(stream, chunk_data).await; + let chunk_column = world.get_network_chunk_column_data(ChunkColumnPosition { cx, cz }).await.unwrap_or_else(|| { + error!("Chunk not loaded: {cx} {cz}"); + panic!("Chunk not loaded: {cx} {cz}"); + }); + + send_packet_raw(stream, &chunk_column).await; } } debug!("ChunkData sent"); diff --git a/minecraft-server/src/player_handler/play.rs b/minecraft-server/src/player_handler/play.rs index dce0f678..459addf9 100644 --- a/minecraft-server/src/player_handler/play.rs +++ b/minecraft-server/src/player_handler/play.rs @@ -21,6 +21,10 @@ impl PlayerHandler { self.packet_sender.send(packet).await.unwrap(); } + async fn send_packet_raw(&mut self, packet: &[u8]) { + self.packet_sender.send(packet.to_vec()).await.unwrap(); + } + async fn on_server_message(&mut self, message: ServerMessage) { use ServerMessage::*; match message { @@ -72,40 +76,12 @@ impl PlayerHandler { // Send the chunks to the client for newly_loaded_chunk in newly_loaded_chunks { - let mut column = Vec::new(); - let heightmaps = self.world.get_network_heightmap(newly_loaded_chunk.clone()).await.unwrap_or_else(|| { + let chunk_column_data = self.world.get_network_chunk_column_data(newly_loaded_chunk.clone()).await.unwrap_or_else(|| { error!("Chunk not loaded: {newly_loaded_chunk:?}"); - NbtTag::Compound(HashMap::new()) // TODO hard error + panic!("Chunk not loaded: {newly_loaded_chunk:?}"); }); - - for cy in -4..20 { - let chunk = self.world.get_network_chunk(newly_loaded_chunk.chunk(cy)).await.unwrap_or_else(|| { - error!("Chunk not loaded: {newly_loaded_chunk:?}"); - NetworkChunk { // TODO hard error - block_count: 0, - blocks: PalettedData::Single { value: 0 }, - biomes: PalettedData::Single { value: 4 }, - } - }); - column.push(chunk); - } - let serialized: Vec = NetworkChunk::into_data(column).unwrap(); - let chunk_data = PlayClientbound::ChunkData { - value: ChunkData { - chunk_x: newly_loaded_chunk.cx, - chunk_z: newly_loaded_chunk.cz, - heightmaps, - data: Array::from(serialized.clone()), - block_entities: Array::default(), - sky_light_mask: Array::default(), - block_light_mask: Array::default(), - empty_sky_light_mask: Array::default(), - empty_block_light_mask: Array::default(), - sky_light: Array::default(), - block_light: Array::default(), - } - }; - self.send_packet(chunk_data).await; + + self.send_packet_raw(&chunk_column_data).await; } // Tell the client to unload chunks diff --git a/minecraft-server/src/prelude.rs b/minecraft-server/src/prelude.rs index 12714819..24fe879e 100644 --- a/minecraft-server/src/prelude.rs +++ b/minecraft-server/src/prelude.rs @@ -4,7 +4,7 @@ pub use log::{debug, error, info, trace, warn}; pub use minecraft_protocol::{ components::{ chat::ChatMode, - chunk::{Chunk as NetworkChunk, ChunkData, PalettedData}, + chunk::{Chunk as NetworkChunk, ChunkData as NetworkChunkColumnData, PalettedData}, difficulty::Difficulty, entity::{EntityAttribute, EntityMetadata, EntityMetadataValue}, gamemode::{Gamemode, PreviousGamemode}, diff --git a/minecraft-server/src/world/map.rs b/minecraft-server/src/world/map.rs index 92bec881..92ef3a3d 100644 --- a/minecraft-server/src/world/map.rs +++ b/minecraft-server/src/world/map.rs @@ -1,5 +1,5 @@ use std::{collections::HashMap, cmp::Ordering}; -use minecraft_protocol::{components::chunk::{PalettedData, self}, ids::blocks::Block}; +use minecraft_protocol::{components::chunk::PalettedData, ids::blocks::Block}; use tokio::sync::RwLock; use crate::prelude::*; use super::light::Light; @@ -456,16 +456,30 @@ impl WorldMap { inner_get_block(self, position).await.unwrap_or(BlockWithState::Air) } - pub async fn get_network_chunk(&self, position: ChunkPosition) -> Option { - let chunk_column_position = position.chunk_column(); - let shard = chunk_column_position.shard(self.shard_count); - let cy_in_vec: usize = position.cy.saturating_add(4).try_into().ok()?; - + pub async fn get_network_chunk_column_data(&self, position: ChunkColumnPosition) -> Option> { + let shard = position.shard(self.shard_count); let shard = self.shards[shard].read().await; - let chunk_column = shard.get(&chunk_column_position)?; - let chunk = chunk_column.chunks.get(cy_in_vec)?; - - Some(chunk.as_network_chunk().clone()) + let chunk_column = shard.get(&position)?; + + let serialized = NetworkChunk::into_data(chunk_column.chunks.iter().map(|c| c.data.clone()).collect()).unwrap(); + let chunk_data = PlayClientbound::ChunkData { value: NetworkChunkColumnData { + chunk_x: position.cx, + chunk_z: position.cz, + heightmaps: chunk_column.heightmap.to_tag(), + data: Array::from(serialized.clone()), + block_entities: Array::default(), + sky_light_mask: Array::default(), + block_light_mask: Array::default(), + empty_sky_light_mask: Array::default(), + empty_block_light_mask: Array::default(), + sky_light: Array::default(), + block_light: Array::default(), + }}; + + let chunk_data = chunk_data.serialize_minecraft_packet().map_err(|e| { + error!("Failed to serialize chunk column data: {:?}", e); + }).ok()?; + Some(chunk_data) } pub async fn get_network_heightmap(&self, position: ChunkColumnPosition) -> Option { diff --git a/minecraft-server/src/world/mod.rs b/minecraft-server/src/world/mod.rs index b9767772..4a97612b 100644 --- a/minecraft-server/src/world/mod.rs +++ b/minecraft-server/src/world/mod.rs @@ -33,8 +33,8 @@ impl World { Some(self.map.get_block(position).await) } - pub async fn get_network_chunk(&self, position: ChunkPosition) -> Option { - self.map.get_network_chunk(position).await + pub async fn get_network_chunk_column_data(&self, position: ChunkColumnPosition) -> Option> { + self.map.get_network_chunk_column_data(position).await } pub async fn get_network_heightmap(&self, position: ChunkColumnPosition) -> Option {