Pumpkin/pumpkin/src/world/chunker.rs
Alexander Medvedev e46459915c feat: Implement fireworks
also fix: https://github.com/Pumpkin-MC/Pumpkin/issues/1217
also includes some bedrock work, but still broken
2026-01-13 19:09:19 +01:00

96 lines
3.1 KiB
Rust

use std::{num::NonZeroU8, sync::Arc};
use pumpkin_protocol::{
bedrock::client::network_chunk_publisher_update::CNetworkChunkPublisherUpdate,
java::client::play::{CCenterChunk, CUnloadChunk},
};
use pumpkin_world::cylindrical_chunk_iterator::Cylindrical;
use crate::{
entity::{EntityBase, player::Player},
net::ClientPlatform,
};
pub async fn get_view_distance(player: &Player) -> NonZeroU8 {
let server = player.world().server.upgrade().unwrap();
player.config.read().await.view_distance.clamp(
NonZeroU8::new(2).unwrap(),
server.basic_config.view_distance,
)
}
pub async fn update_position(player: &Arc<Player>) {
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 {
match &player.client {
ClientPlatform::Java(java_client) => {
java_client
.send_packet_now(&CCenterChunk {
chunk_x: new_chunk_center.x.into(),
chunk_z: new_chunk_center.y.into(),
})
.await;
}
ClientPlatform::Bedrock(bedrock_client) => {
bedrock_client
.send_game_packet(&CNetworkChunkPublisherUpdate::new(
player.get_entity().block_pos.load(),
u32::from(view_distance.get()) * 16,
))
.await;
}
}
let mut loading_chunks = Vec::new();
let mut unloading_chunks = Vec::new();
Cylindrical::for_each_changed_chunk(
old_cylindrical,
new_cylindrical,
&mut loading_chunks,
&mut unloading_chunks,
);
// 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.
let level = &entity.world.level;
level.mark_chunks_as_newly_watched(&loading_chunks).await;
let chunks_to_clean = level.mark_chunks_as_not_watched(&unloading_chunks).await;
{
let mut chunk_manager = player.chunk_manager.lock().await;
chunk_manager.update_center_and_view_distance(
new_chunk_center,
view_distance.into(),
level,
);
};
player.watched_section.store(new_cylindrical);
if !chunks_to_clean.is_empty() {
// level.clean_chunks(&chunks_to_clean).await;
for chunk in unloading_chunks {
player
.client
.enqueue_packet(&CUnloadChunk::new(chunk.x, chunk.y))
.await;
}
}
if !loading_chunks.is_empty() {
entity.world.spawn_world_entity_chunks(
player.clone(),
loading_chunks,
new_chunk_center,
);
}
}
}