mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
add Event::ReceiveChunk and find_blocks_in_chunk function
This commit is contained in:
parent
5adf67fe04
commit
2c5f293210
2 changed files with 89 additions and 68 deletions
|
@ -4,7 +4,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use azalea_chat::FormattedText;
|
use azalea_chat::FormattedText;
|
||||||
use azalea_core::tick::GameTick;
|
use azalea_core::{position::ChunkPos, tick::GameTick};
|
||||||
use azalea_entity::{Dead, InLoadedChunk};
|
use azalea_entity::{Dead, InLoadedChunk};
|
||||||
use azalea_protocol::packets::game::c_player_combat_kill::ClientboundPlayerCombatKill;
|
use azalea_protocol::packets::game::c_player_combat_kill::ClientboundPlayerCombatKill;
|
||||||
use azalea_world::{InstanceName, MinecraftEntityId};
|
use azalea_world::{InstanceName, MinecraftEntityId};
|
||||||
|
@ -15,6 +15,7 @@ use tokio::sync::mpsc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
chat::{ChatPacket, ChatReceivedEvent},
|
chat::{ChatPacket, ChatReceivedEvent},
|
||||||
|
chunks::ReceiveChunkEvent,
|
||||||
disconnect::DisconnectEvent,
|
disconnect::DisconnectEvent,
|
||||||
packet::game::{
|
packet::game::{
|
||||||
AddPlayerEvent, DeathEvent, KeepAliveEvent, RemovePlayerEvent, UpdatePlayerEvent,
|
AddPlayerEvent, DeathEvent, KeepAliveEvent, RemovePlayerEvent, UpdatePlayerEvent,
|
||||||
|
@ -118,6 +119,7 @@ pub enum Event {
|
||||||
KeepAlive(u64),
|
KeepAlive(u64),
|
||||||
/// The client disconnected from the server.
|
/// The client disconnected from the server.
|
||||||
Disconnect(Option<FormattedText>),
|
Disconnect(Option<FormattedText>),
|
||||||
|
ReceiveChunk(ChunkPos),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A component that contains an event sender for events that are only
|
/// A component that contains an event sender for events that are only
|
||||||
|
@ -294,3 +296,17 @@ pub fn disconnect_listener(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn receive_chunk_listener(
|
||||||
|
query: Query<&LocalPlayerEvents>,
|
||||||
|
mut events: EventReader<ReceiveChunkEvent>,
|
||||||
|
) {
|
||||||
|
for event in events.read() {
|
||||||
|
if let Ok(local_player_events) = query.get(event.entity) {
|
||||||
|
let _ = local_player_events.send(Event::ReceiveChunk(ChunkPos::new(
|
||||||
|
event.packet.x,
|
||||||
|
event.packet.z,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,7 @@
|
||||||
use azalea_block::{BlockState, BlockStates};
|
use azalea_block::{BlockState, BlockStates};
|
||||||
use azalea_core::position::{BlockPos, ChunkPos};
|
use azalea_core::position::{BlockPos, ChunkPos};
|
||||||
|
|
||||||
use crate::{ChunkStorage, Instance, iterators::ChunkIterator, palette::Palette};
|
use crate::{Chunk, ChunkStorage, Instance, iterators::ChunkIterator, palette::Palette};
|
||||||
|
|
||||||
fn palette_maybe_has_block(palette: &Palette<BlockState>, block_states: &BlockStates) -> bool {
|
|
||||||
match &palette {
|
|
||||||
Palette::SingleValue(id) => block_states.contains(id),
|
|
||||||
Palette::Linear(ids) => ids.iter().any(|id| block_states.contains(id)),
|
|
||||||
Palette::Hashmap(ids) => ids.iter().any(|id| block_states.contains(id)),
|
|
||||||
Palette::Global => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
/// Find the coordinates of a block in the world.
|
/// Find the coordinates of a block in the world.
|
||||||
|
@ -52,35 +43,20 @@ impl Instance {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (section_index, section) in chunk.read().sections.iter().enumerate() {
|
find_blocks_in_chunk(
|
||||||
let maybe_has_block =
|
block_states,
|
||||||
palette_maybe_has_block(§ion.states.palette, block_states);
|
chunk_pos,
|
||||||
if !maybe_has_block {
|
&chunk.read(),
|
||||||
continue;
|
self.chunks.min_y,
|
||||||
}
|
|this_block_pos| {
|
||||||
|
let this_block_distance = (nearest_to - this_block_pos).length_manhattan();
|
||||||
for i in 0..4096 {
|
// only update if it's closer
|
||||||
let block_state = section.states.get_at_index(i);
|
if nearest_found_pos.is_none() || this_block_distance < nearest_found_distance {
|
||||||
|
nearest_found_pos = Some(this_block_pos);
|
||||||
if block_states.contains(&block_state) {
|
nearest_found_distance = this_block_distance;
|
||||||
let section_pos = section.states.coords_from_index(i);
|
|
||||||
let (x, y, z) = (
|
|
||||||
chunk_pos.x * 16 + (section_pos.x as i32),
|
|
||||||
self.chunks.min_y + (section_index * 16) as i32 + section_pos.y as i32,
|
|
||||||
chunk_pos.z * 16 + (section_pos.z as i32),
|
|
||||||
);
|
|
||||||
let this_block_pos = BlockPos { x, y, z };
|
|
||||||
let this_block_distance = (nearest_to - this_block_pos).length_manhattan();
|
|
||||||
// only update if it's closer
|
|
||||||
if nearest_found_pos.is_none()
|
|
||||||
|| this_block_distance < nearest_found_distance
|
|
||||||
{
|
|
||||||
nearest_found_pos = Some(this_block_pos);
|
|
||||||
nearest_found_distance = this_block_distance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
);
|
||||||
|
|
||||||
if let Some(nearest_found_pos) = nearest_found_pos {
|
if let Some(nearest_found_pos) = nearest_found_pos {
|
||||||
// this is required because find_block searches chunk-by-chunk, which can cause
|
// this is required because find_block searches chunk-by-chunk, which can cause
|
||||||
|
@ -179,38 +155,22 @@ impl Iterator for FindBlocks<'_> {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (section_index, section) in chunk.read().sections.iter().enumerate() {
|
find_blocks_in_chunk(
|
||||||
let maybe_has_block =
|
self.block_states,
|
||||||
palette_maybe_has_block(§ion.states.palette, self.block_states);
|
chunk_pos,
|
||||||
if !maybe_has_block {
|
&chunk.read(),
|
||||||
continue;
|
self.chunks.min_y,
|
||||||
}
|
|this_block_pos| {
|
||||||
|
let this_block_distance = (self.nearest_to - this_block_pos).length_manhattan();
|
||||||
|
|
||||||
for i in 0..4096 {
|
found.push((this_block_pos, this_block_distance));
|
||||||
let block_state = section.states.get_at_index(i);
|
|
||||||
|
|
||||||
if self.block_states.contains(&block_state) {
|
if nearest_found_pos.is_none() || this_block_distance < nearest_found_distance {
|
||||||
let section_pos = section.states.coords_from_index(i);
|
nearest_found_pos = Some(this_block_pos);
|
||||||
let (x, y, z) = (
|
nearest_found_distance = this_block_distance;
|
||||||
chunk_pos.x * 16 + (section_pos.x as i32),
|
|
||||||
self.chunks.min_y + (section_index * 16) as i32 + section_pos.y as i32,
|
|
||||||
chunk_pos.z * 16 + (section_pos.z as i32),
|
|
||||||
);
|
|
||||||
let this_block_pos = BlockPos { x, y, z };
|
|
||||||
let this_block_distance =
|
|
||||||
(self.nearest_to - this_block_pos).length_manhattan();
|
|
||||||
|
|
||||||
found.push((this_block_pos, this_block_distance));
|
|
||||||
|
|
||||||
if nearest_found_pos.is_none()
|
|
||||||
|| this_block_distance < nearest_found_distance
|
|
||||||
{
|
|
||||||
nearest_found_pos = Some(this_block_pos);
|
|
||||||
nearest_found_distance = this_block_distance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
);
|
||||||
|
|
||||||
if let Some(nearest_found_pos) = nearest_found_pos {
|
if let Some(nearest_found_pos) = nearest_found_pos {
|
||||||
// this is required because find_block searches chunk-by-chunk, which can cause
|
// this is required because find_block searches chunk-by-chunk, which can cause
|
||||||
|
@ -242,6 +202,51 @@ impl Iterator for FindBlocks<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An optimized function for finding the block positions in a chunk that match
|
||||||
|
/// the given block states.
|
||||||
|
///
|
||||||
|
/// This is used internally by [`Instance::find_block`] and
|
||||||
|
/// [`Instance::find_blocks`].
|
||||||
|
pub fn find_blocks_in_chunk(
|
||||||
|
block_states: &BlockStates,
|
||||||
|
chunk_pos: ChunkPos,
|
||||||
|
chunk: &Chunk,
|
||||||
|
min_y: i32,
|
||||||
|
mut cb: impl FnMut(BlockPos),
|
||||||
|
) {
|
||||||
|
for (section_index, section) in chunk.sections.iter().enumerate() {
|
||||||
|
let maybe_has_block = palette_maybe_has_block(§ion.states.palette, block_states);
|
||||||
|
if !maybe_has_block {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..4096 {
|
||||||
|
let block_state = section.states.get_at_index(i);
|
||||||
|
|
||||||
|
if block_states.contains(&block_state) {
|
||||||
|
let section_pos = section.states.coords_from_index(i);
|
||||||
|
let (x, y, z) = (
|
||||||
|
chunk_pos.x * 16 + (section_pos.x as i32),
|
||||||
|
min_y + (section_index * 16) as i32 + section_pos.y as i32,
|
||||||
|
chunk_pos.z * 16 + (section_pos.z as i32),
|
||||||
|
);
|
||||||
|
let this_block_pos = BlockPos { x, y, z };
|
||||||
|
|
||||||
|
cb(this_block_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn palette_maybe_has_block(palette: &Palette<BlockState>, block_states: &BlockStates) -> bool {
|
||||||
|
match &palette {
|
||||||
|
Palette::SingleValue(id) => block_states.contains(id),
|
||||||
|
Palette::Linear(ids) => ids.iter().any(|id| block_states.contains(id)),
|
||||||
|
Palette::Hashmap(ids) => ids.iter().any(|id| block_states.contains(id)),
|
||||||
|
Palette::Global => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use azalea_registry::Block;
|
use azalea_registry::Block;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue