use crate::client::Client; use common::{ comp::{Player, Pos}, msg::ServerMsg, state::TerrainChanges, terrain::TerrainGrid, }; use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; /// This system will handle loading generated chunks and unloading uneeded chunks. /// 1. Inserts newly generated chunks into the TerrainGrid /// 2. Sends new chunks to neaby clients /// 3. Handles the chunk's supplement (e.g. npcs) /// 4. Removes chunks outside the range of players pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( ReadExpect<'a, TerrainGrid>, Read<'a, TerrainChanges>, ReadStorage<'a, Pos>, ReadStorage<'a, Player>, WriteStorage<'a, Client>, ); fn run( &mut self, (terrain, terrain_changes, positions, players, mut clients): Self::SystemData, ) { // Sync changed chunks 'chunk: for chunk_key in &terrain_changes.modified_chunks { for (player, pos, client) in (&players, &positions, &mut clients).join() { if player .view_distance .map(|vd| super::terrain::chunk_in_vd(pos.0, *chunk_key, &terrain, vd)) .unwrap_or(false) { client.notify(ServerMsg::TerrainChunkUpdate { key: *chunk_key, chunk: Ok(Box::new(match terrain.get_key(*chunk_key) { Some(chunk) => chunk.clone(), None => break 'chunk, })), }); } } } // TODO: Don't send all changed blocks to all clients // Sync changed blocks let msg = ServerMsg::TerrainBlockUpdates(terrain_changes.modified_blocks.clone()); for (player, client) in (&players, &mut clients).join() { if player.view_distance.is_some() { client.notify(msg.clone()); } } } }