Improve chunks API

This commit is contained in:
Ryan 2022-08-10 20:09:10 -07:00
parent e27144bc01
commit 55cb595740
4 changed files with 44 additions and 43 deletions

View file

@ -170,7 +170,7 @@ impl Config for Game {
// Generate chunk data for chunks created this tick. // Generate chunk data for chunks created this tick.
world.chunks.par_iter_mut().for_each(|(pos, chunk)| { world.chunks.par_iter_mut().for_each(|(pos, chunk)| {
if chunk.created_tick() != server.shared.current_tick() { if !chunk.created_this_tick() {
return; return;
} }

View file

@ -22,7 +22,6 @@ use crate::protocol_inner::packets::s2c::play::{
}; };
use crate::protocol_inner::{Encode, Nbt, VarInt, VarLong}; use crate::protocol_inner::{Encode, Nbt, VarInt, VarLong};
use crate::server::SharedServer; use crate::server::SharedServer;
use crate::Ticks;
/// A container for all [`Chunks`]s in a [`World`](crate::world::World). /// A container for all [`Chunks`]s in a [`World`](crate::world::World).
pub struct Chunks<C: Config> { pub struct Chunks<C: Config> {
@ -32,10 +31,7 @@ pub struct Chunks<C: Config> {
} }
impl<C: Config> Chunks<C> { impl<C: Config> Chunks<C> {
pub(crate) fn new( pub(crate) fn new(shared: SharedServer<C>, dimension: DimensionId) -> Self {
shared: SharedServer<C>,
dimension: DimensionId,
) -> Self {
Self { Self {
chunks: HashMap::new(), chunks: HashMap::new(),
shared, shared,
@ -56,12 +52,7 @@ impl<C: Config> Chunks<C> {
pub fn insert(&mut self, pos: impl Into<ChunkPos>, state: C::ChunkState) -> &mut Chunk<C> { pub fn insert(&mut self, pos: impl Into<ChunkPos>, state: C::ChunkState) -> &mut Chunk<C> {
let section_count = (self.shared.dimension(self.dimension).height / 16) as u32; let section_count = (self.shared.dimension(self.dimension).height / 16) as u32;
let biome_registry_len = self.shared.biomes().len(); let biome_registry_len = self.shared.biomes().len();
let chunk = Chunk::new( let chunk = Chunk::new(section_count, biome_registry_len, state);
section_count,
self.shared.current_tick(),
biome_registry_len,
state,
);
match self.chunks.entry(pos.into()) { match self.chunks.entry(pos.into()) {
Entry::Occupied(mut oe) => { Entry::Occupied(mut oe) => {
@ -194,6 +185,27 @@ impl<C: Config> Chunks<C> {
false 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 /// A chunk is a 16x16-block segment of a world with a height determined by the
@ -208,16 +220,11 @@ pub struct Chunk<C: Config> {
// TODO block_entities: HashMap<u32, BlockEntity>, // TODO block_entities: HashMap<u32, BlockEntity>,
/// The MOTION_BLOCKING heightmap /// The MOTION_BLOCKING heightmap
heightmap: Vec<i64>, heightmap: Vec<i64>,
created_tick: Ticks, created_this_tick: bool,
} }
impl<C: Config> Chunk<C> { impl<C: Config> Chunk<C> {
pub(crate) fn new( fn new(section_count: u32, biome_registry_len: usize, data: C::ChunkState) -> Self {
section_count: u32,
current_tick: Ticks,
biome_registry_len: usize,
data: C::ChunkState,
) -> Self {
let sect = ChunkSection { let sect = ChunkSection {
blocks: [BlockState::AIR.to_raw(); 4096], blocks: [BlockState::AIR.to_raw(); 4096],
modified_count: 1, // Must be >0 so the chunk is initialized. modified_count: 1, // Must be >0 so the chunk is initialized.
@ -229,15 +236,15 @@ impl<C: Config> Chunk<C> {
state: data, state: data,
sections: vec![sect; section_count as usize].into(), sections: vec![sect; section_count as usize].into(),
heightmap: Vec::new(), heightmap: Vec::new(),
created_tick: current_tick, created_this_tick: true,
}; };
chunk.apply_modifications(biome_registry_len); chunk.apply_modifications(biome_registry_len);
chunk chunk
} }
pub fn created_tick(&self) -> Ticks { pub fn created_this_tick(&self) -> bool {
self.created_tick self.created_this_tick
} }
pub fn height(&self) -> usize { pub fn height(&self) -> usize {
@ -327,7 +334,7 @@ impl<C: Config> Chunk<C> {
&self, &self,
pos: ChunkPos, pos: ChunkPos,
min_y: i32, min_y: i32,
mut packet: impl FnMut(BlockChangePacket), mut push_packet: impl FnMut(BlockChangePacket),
) { ) {
for (sect_y, sect) in self.sections.iter().enumerate() { for (sect_y, sect) in self.sections.iter().enumerate() {
if sect.modified_count == 1 { if sect.modified_count == 1 {
@ -342,7 +349,7 @@ impl<C: Config> Chunk<C> {
let global_y = sect_y as i32 * 16 + (idx / (16 * 16)) as i32 + min_y; 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; 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), location: BlockPos::new(global_x, global_y, global_z),
block_id: VarInt((block & BLOCK_STATE_MASK).into()), block_id: VarInt((block & BLOCK_STATE_MASK).into()),
})); }));
@ -368,7 +375,7 @@ impl<C: Config> Chunk<C> {
| (pos.z as i64 & 0x3fffff) << 20 | (pos.z as i64 & 0x3fffff) << 20
| (sect_y as i64 + min_y.div_euclid(16) as i64) & 0xfffff; | (sect_y as i64 + min_y.div_euclid(16) as i64) & 0xfffff;
packet(BlockChangePacket::Multi(ChunkSectionUpdate { push_packet(BlockChangePacket::Multi(ChunkSectionUpdate {
chunk_section_position, chunk_section_position,
invert_trust_edges: false, invert_trust_edges: false,
blocks, blocks,
@ -377,7 +384,7 @@ impl<C: Config> Chunk<C> {
} }
} }
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; let mut any_modified = false;
for sect in self.sections.iter_mut() { for sect in self.sections.iter_mut() {

View file

@ -1064,8 +1064,6 @@ impl<C: Config> Client<C> {
} }
} }
let view_dist = self.view_distance();
let center = ChunkPos::at(self.position.x, self.position.z); let center = ChunkPos::at(self.position.x, self.position.z);
// Send the update view position packet if the client changes the chunk section // Send the update view position packet if the client changes the chunk section
@ -1092,8 +1090,8 @@ impl<C: Config> Client<C> {
let cache = 2; let cache = 2;
if let Some(chunk) = world.chunks.get(pos) { if let Some(chunk) = world.chunks.get(pos) {
if is_chunk_in_view_distance(center, pos, view_dist + cache) if is_chunk_in_view_distance(center, pos, self.view_distance + cache)
&& chunk.created_tick() != current_tick && !chunk.created_this_tick()
{ {
chunk.block_change_packets(pos, dimension.min_y, |pkt| { chunk.block_change_packets(pos, dimension.min_y, |pkt| {
send_packet(&mut self.send, pkt) send_packet(&mut self.send, pkt)
@ -1113,7 +1111,7 @@ impl<C: Config> Client<C> {
}); });
// Load new chunks within the view distance // 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 let Some(chunk) = world.chunks.get(pos) {
if self.loaded_chunks.insert(pos) { if self.loaded_chunks.insert(pos) {
self.send_packet(chunk.chunk_data_packet(pos)); self.send_packet(chunk.chunk_data_packet(pos));
@ -1188,7 +1186,7 @@ impl<C: Config> Client<C> {
self.loaded_entities.retain(|&id| { self.loaded_entities.retain(|&id| {
if let Some(entity) = entities.get(id) { if let Some(entity) = entities.get(id) {
debug_assert!(entity.kind() != EntityKind::Marker); 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) { if let Some(meta) = entity.updated_tracked_data_packet(id) {
send_packet(&mut self.send, meta); send_packet(&mut self.send, meta);
} }
@ -1300,6 +1298,7 @@ impl<C: Config> Client<C> {
// Spawn new entities within the view distance. // Spawn new entities within the view distance.
let pos = self.position(); let pos = self.position();
let view_dist = self.view_distance;
world.spatial_index.query::<_, _, ()>( world.spatial_index.query::<_, _, ()>(
|bb| bb.projected_point(pos).distance(pos) <= view_dist as f64 * 16.0, |bb| bb.projected_point(pos).distance(pos) <= view_dist as f64 * 16.0,
|id, _| { |id, _| {

View file

@ -436,14 +436,11 @@ fn do_update_loop<C: Config>(server: &mut Server<C>) -> ShutdownResult {
shared.config().update(server); shared.config().update(server);
server.worlds.par_iter_mut().for_each(|(id, world)| { server.worlds.par_iter_mut().for_each(|(id, world)| {
world.chunks.par_iter_mut().for_each(|(_, chunk)| { // Chunks created this tick can have their changes applied immediately because
if chunk.created_tick() == shared.current_tick() { // they have not been observed by clients yet. Clients will not have to be sent
// Chunks created this tick can have their changes applied immediately because // the block change packet in this case, since the changes are applied before we
// they have not been observed by clients yet. Clients will not have to be sent // update clients.
// the block change packet in this case. world.chunks.update_created_this_tick();
chunk.apply_modifications(server.shared.biomes().len());
}
});
world.spatial_index.update(&server.entities, id); world.spatial_index.update(&server.entities, id);
}); });
@ -460,9 +457,7 @@ fn do_update_loop<C: Config>(server: &mut Server<C>) -> ShutdownResult {
server.entities.update(); server.entities.update();
server.worlds.par_iter_mut().for_each(|(_, world)| { server.worlds.par_iter_mut().for_each(|(_, world)| {
world.chunks.par_iter_mut().for_each(|(_, chunk)| { world.chunks.update();
chunk.apply_modifications(server.shared.biomes().len());
});
}); });
server.player_lists.update(); server.player_lists.update();