From bfd88f7c6070daaa42c99772a0c14ca92bcd9de1 Mon Sep 17 00:00:00 2001 From: DimitriTimoz Date: Mon, 25 Dec 2023 19:24:52 +0100 Subject: [PATCH] Basic implementation of LightManager --- minecraft-server/src/world/light.rs | 92 +++++++++++++++++++++++++++++ minecraft-server/src/world/map.rs | 26 ++++---- minecraft-server/src/world/mod.rs | 4 -- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/minecraft-server/src/world/light.rs b/minecraft-server/src/world/light.rs index 0d238b4e..ecabe66b 100644 --- a/minecraft-server/src/world/light.rs +++ b/minecraft-server/src/world/light.rs @@ -1,3 +1,8 @@ +use std::collections::BinaryHeap; + +use minecraft_protocol::ids::blocks::Block; +use tokio::sync::OwnedRwLockWriteGuard; + use crate::prelude::*; use super::*; @@ -211,3 +216,90 @@ impl Light { self.sky_light.get_level(position).unwrap_or_default() } } + +pub struct LightManager { + world_map: &'static WorldMap, + current_shard_id: Option, + current_shard: Option>>, +} + +impl LightManager { + fn new(world_map: &'static WorldMap) -> Self { + Self { + world_map, + current_shard: None, + current_shard_id: None, + } + } + + pub async fn update_light(world_map: &'static WorldMap, block_position: BlockPosition, block: BlockWithState) { + let mut light_manager = Self::new(world_map); + + light_manager.set_block(block_position, block).await; + } + + async fn ensure_shard(&mut self, shard_id: usize) { + if let Some(current_shard_id) = self.current_shard_id { + if current_shard_id == shard_id { + return; + } + } + self.current_shard = Some(self.world_map.write_shard(shard_id).await); + self.current_shard_id = Some(shard_id); + } + + async fn get_chunk_column(&mut self, chunk_column_position: ChunkColumnPosition) -> Option<&mut ChunkColumn> { + let shard_id = chunk_column_position.shard(self.world_map.get_shard_count()); + + self.ensure_shard(shard_id).await; + + if let Some(shard) = &mut self.current_shard { + // Here, we use a reference to `shard` instead of trying to move it + shard.get_mut(&chunk_column_position) + } else { + unreachable!("ensure shard always sets to current_shard the requested shard") + } + } + + + + async fn set_light_level(&mut self, position: LightPosition, level: u8) { + unimplemented!(); + } + + async fn get_light_level(&mut self, position: LightPosition) -> u8 { + unimplemented!(); + } + + pub async fn set_block(&mut self, block_position: BlockPosition, block: BlockWithState) { + let mut to_explore = BinaryHeap::new(); + let position = LightPosition::from(block_position.clone()); + to_explore.extend(position.get_neighbors(24)); + while let Some(postion) = to_explore.pop() { + + if let Some(column) = self.get_chunk_column(position.clone().into()).await { + let block = Block::from(column.get_block(position.clone().into())); + + if block.is_transparent() { + let highest_block = column.get_highest_block_at(&block_position.in_chunk_column()); + let is_inside = highest_block > postion.clone().y as u16 + 1; + let new_level = if is_inside { postion.clone().y as u8 - block.light_absorption() - 1 } else { MAX_LIGHT_LEVEL }; + let new_position = LightPositionInChunkColumn::from(postion.clone()); + + to_explore.extend(postion.clone().get_neighbors(24)); + } + } + } + + // Clear locked chunks + + } + + + pub async fn init_chunk_column_light(world_map: &'static WorldMap, chunk_column_position: ChunkColumnPosition) { + + // Clear locked chubks + } +} + + diff --git a/minecraft-server/src/world/map.rs b/minecraft-server/src/world/map.rs index b8784189..195582e2 100644 --- a/minecraft-server/src/world/map.rs +++ b/minecraft-server/src/world/map.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, cmp::Ordering}; use minecraft_protocol::{components::chunk::PalettedData, ids::blocks::Block}; -use tokio::sync::RwLock; +use tokio::sync::{RwLock, OwnedRwLockWriteGuard}; use crate::prelude::*; pub struct WorldMap { @@ -432,7 +432,10 @@ impl WorldMap { for _ in 0..shard_count { shards.push(Arc::new(RwLock::new(HashMap::new()))); } - WorldMap { shard_count, shards } + WorldMap { + shard_count, + shards + } } pub async fn get_block(&self, position: BlockPosition) -> BlockWithState { @@ -449,17 +452,6 @@ 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()?; - - 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()) - } pub async fn set_block(&self, position: BlockPosition, block: BlockWithState) { async fn inner_get_block(s: &WorldMap, position: BlockPosition, block: BlockWithState) -> Option<()> { @@ -494,6 +486,14 @@ impl WorldMap { movement.clone() // Would be more logic if it returned validated, but this way we avoid precision errors } + pub fn get_shard_count(&self) -> usize { + self.shard_count + } + + pub(super) async fn write_shard(&self, shard: usize) -> OwnedRwLockWriteGuard> { + self.shards[shard].clone().write_owned().await + } + #[cfg_attr(feature = "trace", instrument(skip(self)))] pub async fn load(&self, position: ChunkColumnPosition) { let chunk = ChunkColumn::flat(); // TODO: load from disk diff --git a/minecraft-server/src/world/mod.rs b/minecraft-server/src/world/mod.rs index c04f3488..1c05fe6d 100644 --- a/minecraft-server/src/world/mod.rs +++ b/minecraft-server/src/world/mod.rs @@ -40,10 +40,6 @@ 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 set_block(&self, position: BlockPosition, block: BlockWithState) { self.map.set_block(position.clone(), block.clone()).await; self.notify(&position.chunk_column(), WorldChange::Block(position, block)).await;