Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
Automatically load necessary chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
Mubelotix committed Nov 21, 2023
1 parent e326c56 commit 800c3a5
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 35 deletions.
4 changes: 1 addition & 3 deletions minecraft-server/src/entities/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl Handler<Player> {
}).await.flatten() else { return };

// Tell the world about the changes
self.world.update_loaded_columns(self.eid, &loaded_columns).await;
self.world.update_loaded_columns(self.eid, loaded_columns).await;

// Unload chunks
for unloaded_column in unloaded_columns {
Expand All @@ -137,8 +137,6 @@ impl Handler<Player> {
for newly_loaded_column in newly_loaded_columns {
if self.world.is_column_loaded(&newly_loaded_column).await {
self.send_chunk(newly_loaded_column).await;
} else {
self.world.queue_loading(newly_loaded_column).await;
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions minecraft-server/src/player_handler/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,7 @@ pub async fn handshake(stream: &mut TcpStream, logged_in_player_info: LoggedInPl
for cz in -3..=3 {
let column_pos = ChunkColumnPosition { cx, cz };
if !world.is_column_loaded(&column_pos).await {
world.queue_loading(column_pos).await;
remaining_to_load += 1;
remaining_to_load += 1; // FIXME: what happens when chunks are loaded before that block but after we listen for them?
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions minecraft-server/src/server_behavior.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ pub struct ServerBehavior {
impl ServerBehavior {
pub async fn init() -> ServerBehavior {
let listener = TcpListener::bind("127.0.0.1:25567").await.expect("Failed to listen");
let (world, receiver) = World::new();
let world = Box::leak(Box::new(world));
world.init(receiver);
let world = World::new();

// Send ticks to player handlers
let world2: &World = world;
Expand Down
26 changes: 24 additions & 2 deletions minecraft-server/src/world/change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,30 @@ impl WorldObserverManager {
self.notify_entity_change(eid, position, None, change).await;
}

pub async fn update_loaded_columns(&self, eid: Eid, loaded_chunks: &HashSet<ChunkColumnPosition>) {
// TODO
pub async fn update_loaded_columns(&self, eid: Eid, loaded_chunks: HashSet<ChunkColumnPosition>) {
let mut entities = self.trackers.write().await;
let Some(observer) = entities.get_mut(&eid) else {return};
let unloaded_chunks = observer.blocks.difference(&loaded_chunks);
let newly_loaded_chunks = loaded_chunks.difference(&observer.blocks);

let mut blocks = self.blocks.write().await;
let mut entities = self.entities.write().await;
for column in unloaded_chunks {
blocks.get_mut(column).map(|map| map.remove(&eid));
entities.get_mut(column).map(|map| map.remove(&eid));
}
for column in newly_loaded_chunks {
blocks.entry(column.clone()).or_default().insert(eid, observer.sender.clone());
entities.entry(column.clone()).or_default().insert(eid, observer.sender.clone());
}
observer.blocks = loaded_chunks.clone();
}

pub async fn get_all_needed_columns(&self) -> HashSet<ChunkColumnPosition> {
let blocks = self.blocks.read().await;
let mut all_needed_chunks = HashSet::new();
all_needed_chunks.extend(blocks.keys().cloned());
all_needed_chunks
}

pub async fn remove_subscriber(&self, eid: Eid) {
Expand Down
44 changes: 19 additions & 25 deletions minecraft-server/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,31 @@ pub struct World {
entities: Entities,

world_observer_manager: WorldObserverManager,
loading_task_sender: MpscSender<ChunkColumnPosition>
}

impl World {
pub fn new() -> (World, MpscReceiver<ChunkColumnPosition>) {
let (loading_task_sender, loading_task_receiver) = mpsc_channel(200);

(World {
pub fn new() -> &'static World {
let world: &'static World = Box::leak(Box::new(World {
map: WorldMap::new(4),
entities: Entities::new(),
world_observer_manager: WorldObserverManager::new(),
loading_task_sender,
}, loading_task_receiver)
}

pub fn init(&'static self, mut loading_task_receiver: MpscReceiver<ChunkColumnPosition>) {
}));

let world2 = world;
tokio::spawn(async move {
while let Some(position) = loading_task_receiver.recv().await {
self.map.load(position.clone()).await;
self.world_observer_manager.notify_column_loaded(position).await;
let mut previously_loaded_columns = HashSet::new();
loop {
let new_needed_chunks = world2.world_observer_manager.get_all_needed_columns().await;
for column_pos in new_needed_chunks.difference(&previously_loaded_columns) {
world2.map.load(column_pos.to_owned()).await;
world2.world_observer_manager.notify_column_loaded(column_pos.to_owned()).await;
}
previously_loaded_columns = new_needed_chunks;
tokio::time::sleep(Duration::from_millis(50)).await;
}
});

world
}

pub async fn get_block(&self, position: BlockPosition) -> Option<BlockWithState> {
Expand All @@ -49,13 +52,6 @@ impl World {
self.map.is_column_loaded(position).await
}

pub async fn queue_loading(&'static self, position: ChunkColumnPosition) {
// TODO: propagate errors
if let Err(e) = self.loading_task_sender.send(position).await {
error!("Failed to queue loading task: {}", e);
}
}

pub async fn get_network_chunk(&self, position: ChunkPosition) -> Option<NetworkChunk> {
self.map.get_network_chunk(position).await
}
Expand All @@ -73,8 +69,8 @@ impl World {
WorldObserverBuilder::new(eid, &self.world_observer_manager)
}

pub async fn update_loaded_columns(&self, eid: Eid, loaded_columns: &HashSet<ChunkColumnPosition>) {
self.world_observer_manager.update_loaded_columns(eid, loaded_columns).await
pub async fn update_loaded_columns(&self, eid: Eid, loaded_columns: HashSet<ChunkColumnPosition>) {
self.world_observer_manager.update_loaded_columns(eid, loaded_columns).await;
}

pub async fn tick(&self, tick_id: usize) {
Expand Down Expand Up @@ -151,9 +147,7 @@ mod tests {

#[tokio::test]
async fn test_world_notifications() {
let (world, receiver) = World::new();
let world = Box::leak(Box::new(world));
world.init(receiver);
let world = World::new();

let mut receiver1 = WorldObserverBuilder::new(1, &world.world_observer_manager).with_blocks_in_chunk(ChunkColumnPosition{cx: 0, cz: 0}).build().await;
let mut receiver2 = WorldObserverBuilder::new(1, &world.world_observer_manager).with_blocks_in_chunk(ChunkColumnPosition{cx: 1, cz: 1}).build().await;
Expand Down

0 comments on commit 800c3a5

Please sign in to comment.