diff --git a/examples/terrain.rs b/examples/terrain.rs index 4cb9221..dd222da 100644 --- a/examples/terrain.rs +++ b/examples/terrain.rs @@ -170,7 +170,7 @@ impl Config for Game { // Generate chunk data for chunks created this tick. world.chunks.par_iter_mut().for_each(|(pos, chunk)| { - if chunk.created_tick() != server.shared.current_tick() { + if !chunk.created_this_tick() { return; } diff --git a/src/chunk.rs b/src/chunk.rs index 49521b1..8198c9a 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -22,7 +22,6 @@ use crate::protocol_inner::packets::s2c::play::{ }; use crate::protocol_inner::{Encode, Nbt, VarInt, VarLong}; use crate::server::SharedServer; -use crate::Ticks; /// A container for all [`Chunks`]s in a [`World`](crate::world::World). pub struct Chunks { @@ -32,10 +31,7 @@ pub struct Chunks { } impl Chunks { - pub(crate) fn new( - shared: SharedServer, - dimension: DimensionId, - ) -> Self { + pub(crate) fn new(shared: SharedServer, dimension: DimensionId) -> Self { Self { chunks: HashMap::new(), shared, @@ -56,12 +52,7 @@ impl Chunks { pub fn insert(&mut self, pos: impl Into, state: C::ChunkState) -> &mut Chunk { let section_count = (self.shared.dimension(self.dimension).height / 16) as u32; let biome_registry_len = self.shared.biomes().len(); - let chunk = Chunk::new( - section_count, - self.shared.current_tick(), - biome_registry_len, - state, - ); + let chunk = Chunk::new(section_count, biome_registry_len, state); match self.chunks.entry(pos.into()) { Entry::Occupied(mut oe) => { @@ -194,6 +185,27 @@ impl Chunks { false } + + /// Apply chunk modifications to only the chunks that were created this + /// tick. + pub(crate) fn update_created_this_tick(&mut self) { + let biome_registry_len = self.shared.biomes().len(); + self.chunks.par_iter_mut().for_each(|(_, chunk)| { + if chunk.created_this_tick() { + chunk.apply_modifications(biome_registry_len); + } + }); + } + + /// Apply chunk modifications to all chunks and clear the created_this_tick + /// flag. + pub(crate) fn update(&mut self) { + let biome_registry_len = self.shared.biomes().len(); + self.chunks.par_iter_mut().for_each(|(_, chunk)| { + chunk.apply_modifications(biome_registry_len); + chunk.created_this_tick = false; + }); + } } /// A chunk is a 16x16-block segment of a world with a height determined by the @@ -208,16 +220,11 @@ pub struct Chunk { // TODO block_entities: HashMap, /// The MOTION_BLOCKING heightmap heightmap: Vec, - created_tick: Ticks, + created_this_tick: bool, } impl Chunk { - pub(crate) fn new( - section_count: u32, - current_tick: Ticks, - biome_registry_len: usize, - data: C::ChunkState, - ) -> Self { + fn new(section_count: u32, biome_registry_len: usize, data: C::ChunkState) -> Self { let sect = ChunkSection { blocks: [BlockState::AIR.to_raw(); 4096], modified_count: 1, // Must be >0 so the chunk is initialized. @@ -229,15 +236,15 @@ impl Chunk { state: data, sections: vec![sect; section_count as usize].into(), heightmap: Vec::new(), - created_tick: current_tick, + created_this_tick: true, }; chunk.apply_modifications(biome_registry_len); chunk } - pub fn created_tick(&self) -> Ticks { - self.created_tick + pub fn created_this_tick(&self) -> bool { + self.created_this_tick } pub fn height(&self) -> usize { @@ -327,7 +334,7 @@ impl Chunk { &self, pos: ChunkPos, min_y: i32, - mut packet: impl FnMut(BlockChangePacket), + mut push_packet: impl FnMut(BlockChangePacket), ) { for (sect_y, sect) in self.sections.iter().enumerate() { if sect.modified_count == 1 { @@ -342,7 +349,7 @@ impl Chunk { let global_y = sect_y as i32 * 16 + (idx / (16 * 16)) as i32 + min_y; let global_z = pos.z * 16 + (idx / 16 % 16) as i32; - packet(BlockChangePacket::Single(BlockUpdate { + push_packet(BlockChangePacket::Single(BlockUpdate { location: BlockPos::new(global_x, global_y, global_z), block_id: VarInt((block & BLOCK_STATE_MASK).into()), })); @@ -368,7 +375,7 @@ impl Chunk { | (pos.z as i64 & 0x3fffff) << 20 | (sect_y as i64 + min_y.div_euclid(16) as i64) & 0xfffff; - packet(BlockChangePacket::Multi(ChunkSectionUpdate { + push_packet(BlockChangePacket::Multi(ChunkSectionUpdate { chunk_section_position, invert_trust_edges: false, blocks, @@ -377,7 +384,7 @@ impl Chunk { } } - pub(crate) fn apply_modifications(&mut self, biome_registry_len: usize) { + fn apply_modifications(&mut self, biome_registry_len: usize) { let mut any_modified = false; for sect in self.sections.iter_mut() { diff --git a/src/client.rs b/src/client.rs index 0ce4430..12d0b57 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1064,8 +1064,6 @@ impl Client { } } - let view_dist = self.view_distance(); - let center = ChunkPos::at(self.position.x, self.position.z); // Send the update view position packet if the client changes the chunk section @@ -1092,8 +1090,8 @@ impl Client { let cache = 2; if let Some(chunk) = world.chunks.get(pos) { - if is_chunk_in_view_distance(center, pos, view_dist + cache) - && chunk.created_tick() != current_tick + if is_chunk_in_view_distance(center, pos, self.view_distance + cache) + && !chunk.created_this_tick() { chunk.block_change_packets(pos, dimension.min_y, |pkt| { send_packet(&mut self.send, pkt) @@ -1113,7 +1111,7 @@ impl Client { }); // Load new chunks within the view distance - for pos in chunks_in_view_distance(center, view_dist) { + for pos in chunks_in_view_distance(center, self.view_distance) { if let Some(chunk) = world.chunks.get(pos) { if self.loaded_chunks.insert(pos) { self.send_packet(chunk.chunk_data_packet(pos)); @@ -1188,7 +1186,7 @@ impl Client { self.loaded_entities.retain(|&id| { if let Some(entity) = entities.get(id) { debug_assert!(entity.kind() != EntityKind::Marker); - if self.position.distance(entity.position()) <= view_dist as f64 * 16.0 { + if self.position.distance(entity.position()) <= self.view_distance as f64 * 16.0 { if let Some(meta) = entity.updated_tracked_data_packet(id) { send_packet(&mut self.send, meta); } @@ -1300,6 +1298,7 @@ impl Client { // Spawn new entities within the view distance. let pos = self.position(); + let view_dist = self.view_distance; world.spatial_index.query::<_, _, ()>( |bb| bb.projected_point(pos).distance(pos) <= view_dist as f64 * 16.0, |id, _| { diff --git a/src/server.rs b/src/server.rs index 047d57f..0273285 100644 --- a/src/server.rs +++ b/src/server.rs @@ -436,14 +436,11 @@ fn do_update_loop(server: &mut Server) -> ShutdownResult { shared.config().update(server); server.worlds.par_iter_mut().for_each(|(id, world)| { - world.chunks.par_iter_mut().for_each(|(_, chunk)| { - if chunk.created_tick() == shared.current_tick() { - // Chunks created this tick can have their changes applied immediately because - // they have not been observed by clients yet. Clients will not have to be sent - // the block change packet in this case. - chunk.apply_modifications(server.shared.biomes().len()); - } - }); + // Chunks created this tick can have their changes applied immediately because + // they have not been observed by clients yet. Clients will not have to be sent + // the block change packet in this case, since the changes are applied before we + // update clients. + world.chunks.update_created_this_tick(); world.spatial_index.update(&server.entities, id); }); @@ -460,9 +457,7 @@ fn do_update_loop(server: &mut Server) -> ShutdownResult { server.entities.update(); server.worlds.par_iter_mut().for_each(|(_, world)| { - world.chunks.par_iter_mut().for_each(|(_, chunk)| { - chunk.apply_modifications(server.shared.biomes().len()); - }); + world.chunks.update(); }); server.player_lists.update();