mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
make loading chunks its own bevy system
This commit is contained in:
parent
8d0acecdcf
commit
000abfa136
6 changed files with 103 additions and 75 deletions
|
@ -2,26 +2,37 @@
|
||||||
//! for making the server spread out how often it sends us chunk packets
|
//! for making the server spread out how often it sends us chunk packets
|
||||||
//! depending on our receiving speed.
|
//! depending on our receiving speed.
|
||||||
|
|
||||||
use std::time::{Duration, Instant};
|
use std::{
|
||||||
|
io::Cursor,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
use azalea_protocol::packets::game::serverbound_chunk_batch_received_packet::ServerboundChunkBatchReceivedPacket;
|
use azalea_core::position::ChunkPos;
|
||||||
|
use azalea_nbt::NbtCompound;
|
||||||
|
use azalea_protocol::packets::game::{
|
||||||
|
clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket,
|
||||||
|
serverbound_chunk_batch_received_packet::ServerboundChunkBatchReceivedPacket,
|
||||||
|
};
|
||||||
use bevy_app::{App, Plugin, Update};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
use tracing::{error, trace};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
interact::handle_block_interact_event,
|
interact::handle_block_interact_event,
|
||||||
inventory::InventorySet,
|
inventory::InventorySet,
|
||||||
local_player::{handle_send_packet_event, SendPacketEvent},
|
local_player::{handle_send_packet_event, SendPacketEvent},
|
||||||
respawn::perform_respawn,
|
respawn::perform_respawn,
|
||||||
|
InstanceHolder,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ChunkBatchingPlugin;
|
pub struct ChunkPlugin;
|
||||||
impl Plugin for ChunkBatchingPlugin {
|
impl Plugin for ChunkPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
handle_chunk_batch_start_event,
|
handle_chunk_batch_start_event,
|
||||||
|
handle_receive_chunk_events,
|
||||||
handle_chunk_batch_finished_event,
|
handle_chunk_batch_finished_event,
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
|
@ -30,11 +41,18 @@ impl Plugin for ChunkBatchingPlugin {
|
||||||
.before(handle_block_interact_event)
|
.before(handle_block_interact_event)
|
||||||
.before(perform_respawn),
|
.before(perform_respawn),
|
||||||
)
|
)
|
||||||
|
.add_event::<ReceiveChunkEvent>()
|
||||||
.add_event::<ChunkBatchStartEvent>()
|
.add_event::<ChunkBatchStartEvent>()
|
||||||
.add_event::<ChunkBatchFinishedEvent>();
|
.add_event::<ChunkBatchFinishedEvent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct ReceiveChunkEvent {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub packet: ClientboundLevelChunkWithLightPacket,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Component, Clone, Debug)]
|
#[derive(Component, Clone, Debug)]
|
||||||
pub struct ChunkBatchInfo {
|
pub struct ChunkBatchInfo {
|
||||||
pub start_time: Instant,
|
pub start_time: Instant,
|
||||||
|
@ -42,6 +60,69 @@ pub struct ChunkBatchInfo {
|
||||||
pub old_samples_weight: u32,
|
pub old_samples_weight: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct ChunkBatchStartEvent {
|
||||||
|
pub entity: Entity,
|
||||||
|
}
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct ChunkBatchFinishedEvent {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub batch_size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_receive_chunk_events(
|
||||||
|
mut events: EventReader<ReceiveChunkEvent>,
|
||||||
|
mut query: Query<&mut InstanceHolder>,
|
||||||
|
) {
|
||||||
|
for event in events.read() {
|
||||||
|
let pos = ChunkPos::new(event.packet.x, event.packet.z);
|
||||||
|
|
||||||
|
let local_player = query.get_mut(event.entity).unwrap();
|
||||||
|
|
||||||
|
// OPTIMIZATION: if we already know about the chunk from the
|
||||||
|
// shared world (and not ourselves), then we don't need to
|
||||||
|
// parse it again. This is only used when we have a shared
|
||||||
|
// world, since we check that the chunk isn't currently owned
|
||||||
|
// by this client.
|
||||||
|
let shared_chunk = local_player.instance.read().chunks.get(&pos);
|
||||||
|
let this_client_has_chunk = local_player
|
||||||
|
.partial_instance
|
||||||
|
.read()
|
||||||
|
.chunks
|
||||||
|
.limited_get(&pos)
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
let mut world = local_player.instance.write();
|
||||||
|
let mut partial_world = local_player.partial_instance.write();
|
||||||
|
|
||||||
|
if !this_client_has_chunk {
|
||||||
|
if let Some(shared_chunk) = shared_chunk {
|
||||||
|
trace!("Skipping parsing chunk {pos:?} because we already know about it");
|
||||||
|
partial_world.chunks.set_with_shared_reference(
|
||||||
|
&pos,
|
||||||
|
Some(shared_chunk.clone()),
|
||||||
|
&mut world.chunks,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let heightmaps = event.packet.chunk_data.heightmaps.as_compound();
|
||||||
|
// necessary to make the unwrap_or work
|
||||||
|
let empty_nbt_compound = NbtCompound::default();
|
||||||
|
let heightmaps = heightmaps.unwrap_or(&empty_nbt_compound);
|
||||||
|
|
||||||
|
if let Err(e) = partial_world.chunks.replace_with_packet_data(
|
||||||
|
&pos,
|
||||||
|
&mut Cursor::new(&event.packet.chunk_data.data),
|
||||||
|
heightmaps,
|
||||||
|
&mut world.chunks,
|
||||||
|
) {
|
||||||
|
error!("Couldn't set chunk data: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ChunkBatchInfo {
|
impl ChunkBatchInfo {
|
||||||
pub fn batch_finished(&mut self, batch_size: u32) {
|
pub fn batch_finished(&mut self, batch_size: u32) {
|
||||||
if batch_size == 0 {
|
if batch_size == 0 {
|
||||||
|
@ -65,16 +146,6 @@ impl ChunkBatchInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Event)]
|
|
||||||
pub struct ChunkBatchStartEvent {
|
|
||||||
pub entity: Entity,
|
|
||||||
}
|
|
||||||
#[derive(Event)]
|
|
||||||
pub struct ChunkBatchFinishedEvent {
|
|
||||||
pub entity: Entity,
|
|
||||||
pub batch_size: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_chunk_batch_start_event(
|
pub fn handle_chunk_batch_start_event(
|
||||||
mut query: Query<&mut ChunkBatchInfo>,
|
mut query: Query<&mut ChunkBatchInfo>,
|
||||||
mut events: EventReader<ChunkBatchStartEvent>,
|
mut events: EventReader<ChunkBatchStartEvent>,
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
attack::{self, AttackPlugin},
|
attack::{self, AttackPlugin},
|
||||||
chat::ChatPlugin,
|
chat::ChatPlugin,
|
||||||
chunk_batching::{ChunkBatchInfo, ChunkBatchingPlugin},
|
chunks::{ChunkBatchInfo, ChunkPlugin},
|
||||||
disconnect::{DisconnectEvent, DisconnectPlugin},
|
disconnect::{DisconnectEvent, DisconnectPlugin},
|
||||||
events::{Event, EventPlugin, LocalPlayerEvents},
|
events::{Event, EventPlugin, LocalPlayerEvents},
|
||||||
interact::{CurrentSequenceNumber, InteractPlugin},
|
interact::{CurrentSequenceNumber, InteractPlugin},
|
||||||
|
@ -782,7 +782,7 @@ impl PluginGroup for DefaultPlugins {
|
||||||
.add(RespawnPlugin)
|
.add(RespawnPlugin)
|
||||||
.add(MinePlugin)
|
.add(MinePlugin)
|
||||||
.add(AttackPlugin)
|
.add(AttackPlugin)
|
||||||
.add(ChunkBatchingPlugin)
|
.add(ChunkPlugin)
|
||||||
.add(TickBroadcastPlugin);
|
.add(TickBroadcastPlugin);
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
mod account;
|
mod account;
|
||||||
pub mod attack;
|
pub mod attack;
|
||||||
pub mod chat;
|
pub mod chat;
|
||||||
pub mod chunk_batching;
|
pub mod chunks;
|
||||||
mod client;
|
mod client;
|
||||||
pub mod disconnect;
|
pub mod disconnect;
|
||||||
mod entity_query;
|
mod entity_query;
|
||||||
|
|
|
@ -140,7 +140,7 @@ pub fn process_packet_events(ecs: &mut World) {
|
||||||
abilities: crate::local_player::PlayerAbilities::default(),
|
abilities: crate::local_player::PlayerAbilities::default(),
|
||||||
permission_level: crate::local_player::PermissionLevel::default(),
|
permission_level: crate::local_player::PermissionLevel::default(),
|
||||||
hunger: Hunger::default(),
|
hunger: Hunger::default(),
|
||||||
chunk_batch_info: crate::chunk_batching::ChunkBatchInfo::default(),
|
chunk_batch_info: crate::chunks::ChunkBatchInfo::default(),
|
||||||
|
|
||||||
entity_id_index: EntityIdIndex::default(),
|
entity_id_index: EntityIdIndex::default(),
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ use azalea_entity::{
|
||||||
Dead, EntityBundle, EntityKind, LastSentPosition, LoadedBy, LocalEntity, LookDirection,
|
Dead, EntityBundle, EntityKind, LastSentPosition, LoadedBy, LocalEntity, LookDirection,
|
||||||
Physics, PlayerBundle, Position, RelativeEntityUpdate,
|
Physics, PlayerBundle, Position, RelativeEntityUpdate,
|
||||||
};
|
};
|
||||||
use azalea_nbt::NbtCompound;
|
|
||||||
use azalea_protocol::{
|
use azalea_protocol::{
|
||||||
packets::game::{
|
packets::game::{
|
||||||
clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket,
|
clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket,
|
||||||
|
@ -34,7 +33,7 @@ use tracing::{debug, error, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
chat::{ChatPacket, ChatReceivedEvent},
|
chat::{ChatPacket, ChatReceivedEvent},
|
||||||
chunk_batching,
|
chunks,
|
||||||
disconnect::DisconnectEvent,
|
disconnect::DisconnectEvent,
|
||||||
inventory::{
|
inventory::{
|
||||||
ClientSideCloseContainerEvent, InventoryComponent, MenuOpenedEvent,
|
ClientSideCloseContainerEvent, InventoryComponent, MenuOpenedEvent,
|
||||||
|
@ -339,24 +338,22 @@ pub fn process_packet_events(ecs: &mut World) {
|
||||||
ClientboundGamePacket::ChunkBatchStart(_p) => {
|
ClientboundGamePacket::ChunkBatchStart(_p) => {
|
||||||
// the packet is empty, just a marker to tell us when the batch starts and ends
|
// the packet is empty, just a marker to tell us when the batch starts and ends
|
||||||
debug!("Got chunk batch start");
|
debug!("Got chunk batch start");
|
||||||
let mut system_state: SystemState<
|
let mut system_state: SystemState<EventWriter<chunks::ChunkBatchStartEvent>> =
|
||||||
EventWriter<chunk_batching::ChunkBatchStartEvent>,
|
SystemState::new(ecs);
|
||||||
> = SystemState::new(ecs);
|
|
||||||
let mut chunk_batch_start_events = system_state.get_mut(ecs);
|
let mut chunk_batch_start_events = system_state.get_mut(ecs);
|
||||||
|
|
||||||
chunk_batch_start_events.send(chunk_batching::ChunkBatchStartEvent {
|
chunk_batch_start_events.send(chunks::ChunkBatchStartEvent {
|
||||||
entity: player_entity,
|
entity: player_entity,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ClientboundGamePacket::ChunkBatchFinished(p) => {
|
ClientboundGamePacket::ChunkBatchFinished(p) => {
|
||||||
debug!("Got chunk batch finished {p:?}");
|
debug!("Got chunk batch finished {p:?}");
|
||||||
|
|
||||||
let mut system_state: SystemState<
|
let mut system_state: SystemState<EventWriter<chunks::ChunkBatchFinishedEvent>> =
|
||||||
EventWriter<chunk_batching::ChunkBatchFinishedEvent>,
|
SystemState::new(ecs);
|
||||||
> = SystemState::new(ecs);
|
|
||||||
let mut chunk_batch_start_events = system_state.get_mut(ecs);
|
let mut chunk_batch_start_events = system_state.get_mut(ecs);
|
||||||
|
|
||||||
chunk_batch_start_events.send(chunk_batching::ChunkBatchFinishedEvent {
|
chunk_batch_start_events.send(chunks::ChunkBatchFinishedEvent {
|
||||||
entity: player_entity,
|
entity: player_entity,
|
||||||
batch_size: p.batch_size,
|
batch_size: p.batch_size,
|
||||||
});
|
});
|
||||||
|
@ -597,54 +594,14 @@ pub fn process_packet_events(ecs: &mut World) {
|
||||||
}
|
}
|
||||||
ClientboundGamePacket::LevelChunkWithLight(p) => {
|
ClientboundGamePacket::LevelChunkWithLight(p) => {
|
||||||
debug!("Got chunk with light packet {} {}", p.x, p.z);
|
debug!("Got chunk with light packet {} {}", p.x, p.z);
|
||||||
let pos = ChunkPos::new(p.x, p.z);
|
|
||||||
|
|
||||||
let mut system_state: SystemState<Query<&mut InstanceHolder>> =
|
let mut system_state: SystemState<EventWriter<chunks::ReceiveChunkEvent>> =
|
||||||
SystemState::new(ecs);
|
SystemState::new(ecs);
|
||||||
let mut query = system_state.get_mut(ecs);
|
let mut receive_chunk_events = system_state.get_mut(ecs);
|
||||||
let local_player = query.get_mut(player_entity).unwrap();
|
receive_chunk_events.send(chunks::ReceiveChunkEvent {
|
||||||
|
entity: player_entity,
|
||||||
// OPTIMIZATION: if we already know about the chunk from the
|
packet: p.clone(),
|
||||||
// shared world (and not ourselves), then we don't need to
|
});
|
||||||
// parse it again. This is only used when we have a shared
|
|
||||||
// world, since we check that the chunk isn't currently owned
|
|
||||||
// by this client.
|
|
||||||
let shared_chunk = local_player.instance.read().chunks.get(&pos);
|
|
||||||
let this_client_has_chunk = local_player
|
|
||||||
.partial_instance
|
|
||||||
.read()
|
|
||||||
.chunks
|
|
||||||
.limited_get(&pos)
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
let mut world = local_player.instance.write();
|
|
||||||
let mut partial_world = local_player.partial_instance.write();
|
|
||||||
|
|
||||||
if !this_client_has_chunk {
|
|
||||||
if let Some(shared_chunk) = shared_chunk {
|
|
||||||
trace!("Skipping parsing chunk {pos:?} because we already know about it");
|
|
||||||
partial_world.chunks.set_with_shared_reference(
|
|
||||||
&pos,
|
|
||||||
Some(shared_chunk.clone()),
|
|
||||||
&mut world.chunks,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let heightmaps = p.chunk_data.heightmaps.as_compound();
|
|
||||||
// necessary to make the unwrap_or work
|
|
||||||
let empty_nbt_compound = NbtCompound::default();
|
|
||||||
let heightmaps = heightmaps.unwrap_or(&empty_nbt_compound);
|
|
||||||
|
|
||||||
if let Err(e) = partial_world.chunks.replace_with_packet_data(
|
|
||||||
&pos,
|
|
||||||
&mut Cursor::new(&p.chunk_data.data),
|
|
||||||
heightmaps,
|
|
||||||
&mut world.chunks,
|
|
||||||
) {
|
|
||||||
error!("Couldn't set chunk data: {e}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ClientboundGamePacket::AddEntity(p) => {
|
ClientboundGamePacket::AddEntity(p) => {
|
||||||
debug!("Got add entity packet {p:?}");
|
debug!("Got add entity packet {p:?}");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::app::{App, Plugin};
|
use crate::app::{App, Plugin};
|
||||||
use azalea_client::chunk_batching::handle_chunk_batch_finished_event;
|
use azalea_client::chunks::handle_chunk_batch_finished_event;
|
||||||
use azalea_client::inventory::InventorySet;
|
use azalea_client::inventory::InventorySet;
|
||||||
use azalea_client::packet_handling::{death_event_on_0_health, game::ResourcePackEvent};
|
use azalea_client::packet_handling::{death_event_on_0_health, game::ResourcePackEvent};
|
||||||
use azalea_client::respawn::perform_respawn;
|
use azalea_client::respawn::perform_respawn;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue