Pumpkin/pumpkin/src/world/player_chunker.rs
Alexander Medvedev cc0f30848e More clippy lints
Also made some vars NonZero
2024-12-19 01:25:19 +01:00

121 lines
3.8 KiB
Rust

use std::{num::NonZeroU8, sync::Arc};
use pumpkin_config::BASIC_CONFIG;
use pumpkin_core::{
math::{get_section_cord, position::WorldPosition, vector3::Vector3},
GameMode,
};
use pumpkin_protocol::client::play::{CCenterChunk, CUnloadChunk};
use pumpkin_world::cylindrical_chunk_iterator::Cylindrical;
use crate::entity::player::Player;
pub async fn get_view_distance(player: &Player) -> NonZeroU8 {
player.config.lock().await.view_distance.clamp(
unsafe { NonZeroU8::new_unchecked(2) },
BASIC_CONFIG.view_distance,
)
}
pub async fn player_join(player: &Arc<Player>) {
let chunk_pos = player.living_entity.entity.chunk_pos.load();
log::debug!("Sending center chunk to {}", player.gameprofile.name);
player
.client
.send_packet(&CCenterChunk {
chunk_x: chunk_pos.x.into(),
chunk_z: chunk_pos.z.into(),
})
.await;
let view_distance = get_view_distance(player).await;
log::debug!(
"Player {} ({}) joined with view distance: {}",
player.gameprofile.name,
player.client.id,
view_distance
);
update_position(player).await;
}
pub async fn update_position(player: &Arc<Player>) {
if !player.abilities.lock().await.flying {
player
.living_entity
.update_fall_distance(player.gamemode.load() == GameMode::Creative)
.await;
}
let entity = &player.living_entity.entity;
let view_distance = get_view_distance(player).await;
let new_chunk_center = entity.chunk_pos.load();
let old_cylindrical = player.watched_section.load();
let new_cylindrical = Cylindrical::new(new_chunk_center, view_distance);
if old_cylindrical != new_cylindrical {
player
.client
.send_packet(&CCenterChunk {
chunk_x: new_chunk_center.x.into(),
chunk_z: new_chunk_center.z.into(),
})
.await;
let mut loading_chunks = Vec::new();
let mut unloading_chunks = Vec::new();
Cylindrical::for_each_changed_chunk(
old_cylindrical,
new_cylindrical,
|chunk_pos| {
loading_chunks.push(chunk_pos);
},
|chunk_pos| {
unloading_chunks.push(chunk_pos);
},
);
// Make sure the watched section and the chunk watcher updates are async atomic. We want to
// ensure what we unload when the player disconnects is correct
entity.world.mark_chunks_as_watched(&loading_chunks);
let chunks_to_clean = entity.world.mark_chunks_as_not_watched(&unloading_chunks);
player.watched_section.store(new_cylindrical);
if !chunks_to_clean.is_empty() {
entity.world.clean_chunks(&chunks_to_clean);
// This can take a little if we are sending a bunch of packets, queue it up :p
let client = player.client.clone();
tokio::spawn(async move {
for chunk in unloading_chunks {
if client.closed.load(std::sync::atomic::Ordering::Relaxed) {
// We will never un-close a connection
break;
}
client
.send_packet(&CUnloadChunk::new(chunk.x, chunk.z))
.await;
}
});
}
if !loading_chunks.is_empty() {
entity
.world
.spawn_world_chunks(player.clone(), loading_chunks, new_chunk_center);
}
}
}
#[must_use]
pub const fn chunk_section_from_pos(block_pos: &WorldPosition) -> Vector3<i32> {
let block_pos = block_pos.0;
Vector3::new(
get_section_cord(block_pos.x),
get_section_cord(block_pos.y),
get_section_cord(block_pos.z),
)
}