aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/chunk_batching.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-09-21 11:16:29 -0500
committerGitHub <noreply@github.com>2023-09-21 11:16:29 -0500
commit7b3e2e4bf793466a351510c7fbbd08234e93bb0e (patch)
tree7177a919de9982d9e3c7f36a76d2025696f465b6 /azalea-client/src/chunk_batching.rs
parent83cce236145cdab1872a472a70943b669a880965 (diff)
downloadazalea-drasl-7b3e2e4bf793466a351510c7fbbd08234e93bb0e.tar.xz
1.20.2 (#99)
* add configuration state * start updating to 23w31a * implement a bit more of 23w31a * chunk batching * start adding configuration state * ioasfhjgsd * almost works * configuration state mostly implemented * handle other packets in configuration state and fix keepalive * cleanup, fix warnings * 23w32a * fix some doctests * 23w33a * 23w35a * 1.20.2-pre2 * fix system conflicts * 1.20.2-pre4 * make tests compile * tests pass * 1.20.2-rc2 * 1.20.2 * Revert "1.20.2" This reverts commit dd152fd265332ead333c919e585ded6d609d7468. * didn't mean to commit that code --------- Co-authored-by: mat <git@matdoes.dev>
Diffstat (limited to 'azalea-client/src/chunk_batching.rs')
-rw-r--r--azalea-client/src/chunk_batching.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/azalea-client/src/chunk_batching.rs b/azalea-client/src/chunk_batching.rs
new file mode 100644
index 00000000..c0e8bb34
--- /dev/null
+++ b/azalea-client/src/chunk_batching.rs
@@ -0,0 +1,146 @@
+//! Used for Minecraft's chunk batching introduced in 23w31a (1.20.2). It's used
+//! for making the server spread out how often it sends us chunk packets
+//! depending on our receiving speed.
+
+use std::time::{Duration, Instant};
+
+use azalea_protocol::packets::game::serverbound_chunk_batch_received_packet::ServerboundChunkBatchReceivedPacket;
+use bevy_app::{App, Plugin, Update};
+use bevy_ecs::prelude::*;
+
+use crate::{
+ interact::handle_block_interact_event,
+ inventory::InventorySet,
+ local_player::{handle_send_packet_event, SendPacketEvent},
+ respawn::perform_respawn,
+};
+
+pub struct ChunkBatchingPlugin;
+impl Plugin for ChunkBatchingPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(
+ Update,
+ (
+ handle_chunk_batch_start_event,
+ handle_chunk_batch_finished_event,
+ )
+ .chain()
+ .before(handle_send_packet_event)
+ .before(InventorySet)
+ .before(handle_block_interact_event)
+ .before(perform_respawn),
+ )
+ .add_event::<ChunkBatchStartEvent>()
+ .add_event::<ChunkBatchFinishedEvent>();
+ }
+}
+
+#[derive(Component, Clone, Debug)]
+pub struct ChunkBatchInfo {
+ pub start_time: Instant,
+ pub accumulator: ChunkReceiveSpeedAccumulator,
+}
+
+#[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(
+ mut query: Query<&mut ChunkBatchInfo>,
+ mut events: EventReader<ChunkBatchStartEvent>,
+) {
+ for event in events.iter() {
+ if let Ok(mut chunk_batch_info) = query.get_mut(event.entity) {
+ chunk_batch_info.start_time = Instant::now();
+ }
+ }
+}
+
+pub fn handle_chunk_batch_finished_event(
+ mut query: Query<&mut ChunkBatchInfo>,
+ mut events: EventReader<ChunkBatchFinishedEvent>,
+ mut send_packets: EventWriter<SendPacketEvent>,
+) {
+ for event in events.iter() {
+ if let Ok(mut chunk_batch_info) = query.get_mut(event.entity) {
+ let batch_duration = chunk_batch_info.start_time.elapsed();
+ if event.batch_size > 0 {
+ chunk_batch_info
+ .accumulator
+ .accumulate(event.batch_size, batch_duration);
+ }
+ let millis_per_chunk =
+ f64::max(0., chunk_batch_info.accumulator.get_millis_per_chunk());
+ let desired_chunks_per_tick = if millis_per_chunk == 0. {
+ // make it the server's problem instead
+ f32::NAN
+ } else {
+ (25. / millis_per_chunk) as f32
+ };
+ send_packets.send(SendPacketEvent {
+ entity: event.entity,
+ packet: ServerboundChunkBatchReceivedPacket {
+ desired_chunks_per_tick,
+ }
+ .get(),
+ });
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct ChunkReceiveSpeedAccumulator {
+ batch_sizes: Vec<u32>,
+ /// as milliseconds
+ batch_durations: Vec<u32>,
+ index: usize,
+ filled_size: usize,
+}
+impl ChunkReceiveSpeedAccumulator {
+ pub fn new(capacity: usize) -> Self {
+ Self {
+ batch_sizes: vec![0; capacity],
+ batch_durations: vec![0; capacity],
+ index: 0,
+ filled_size: 0,
+ }
+ }
+
+ pub fn accumulate(&mut self, batch_size: u32, batch_duration: Duration) {
+ self.batch_sizes[self.index] = batch_size;
+ self.batch_durations[self.index] =
+ f32::clamp(batch_duration.as_millis() as f32, 0., 15000.) as u32;
+ self.index = (self.index + 1) % self.batch_sizes.len();
+ if self.filled_size < self.batch_sizes.len() {
+ self.filled_size += 1;
+ }
+ }
+
+ pub fn get_millis_per_chunk(&self) -> f64 {
+ let mut total_batch_size = 0;
+ let mut total_batch_duration = 0;
+ for i in 0..self.filled_size {
+ total_batch_size += self.batch_sizes[i];
+ total_batch_duration += self.batch_durations[i];
+ }
+ if total_batch_size == 0 {
+ return 0.;
+ }
+ total_batch_duration as f64 / total_batch_size as f64
+ }
+}
+
+impl Default for ChunkBatchInfo {
+ fn default() -> Self {
+ Self {
+ start_time: Instant::now(),
+ accumulator: ChunkReceiveSpeedAccumulator::new(50),
+ }
+ }
+}