1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

fix entity deindexing happening at the wrong time

This commit is contained in:
mat 2025-03-28 00:54:17 +00:00
parent 02de98240f
commit 4e5c551d65
4 changed files with 59 additions and 25 deletions

View file

@ -703,7 +703,10 @@ impl GamePacketHandler<'_> {
let mut spawned = let mut spawned =
commands.spawn((entity_id, LoadedBy(HashSet::from([self.player])), bundle)); commands.spawn((entity_id, LoadedBy(HashSet::from([self.player])), bundle));
let ecs_entity: Entity = spawned.id(); let ecs_entity: Entity = spawned.id();
debug!("spawned entity {ecs_entity:?} with id {entity_id:?}"); debug!(
"spawned entity {ecs_entity:?} with id {entity_id:?} at {pos:?}",
pos = p.position
);
azalea_entity::indexing::add_entity_to_indexes( azalea_entity::indexing::add_entity_to_indexes(
entity_id, entity_id,
@ -918,11 +921,9 @@ impl GamePacketHandler<'_> {
debug!("Got move entity pos packet {p:?}"); debug!("Got move entity pos packet {p:?}");
let Some(entity) = entity_id_index.get(p.entity_id) else { let entity_id = p.entity_id;
debug!( let Some(entity) = entity_id_index.get(entity_id) else {
"Got move entity pos packet for unknown entity id {}", debug!("Got move entity pos packet for unknown entity id {entity_id}");
p.entity_id
);
return; return;
}; };
@ -944,6 +945,11 @@ impl GamePacketHandler<'_> {
if new_pos != **position { if new_pos != **position {
**position = new_pos; **position = new_pos;
} }
trace!(
"Applied movement update for {entity_id} / {entity}",
entity = entity_mut.id()
);
}, },
)); ));
}, },
@ -1071,7 +1077,7 @@ impl GamePacketHandler<'_> {
for &id in &p.entity_ids { for &id in &p.entity_ids {
let Some(entity) = entity_id_index.remove(id) else { let Some(entity) = entity_id_index.remove(id) else {
debug!( debug!(
"Tried to remove entity with id {id} but it wasn't in the EntityIdIndex" "Tried to remove entity with id {id} but it wasn't in the EntityIdIndex. This may be expected on certain server setups (like if they're using VeryManyPlayers)."
); );
continue; continue;
}; };
@ -1082,7 +1088,7 @@ impl GamePacketHandler<'_> {
continue; continue;
}; };
// the [`remove_despawned_entities_from_indexes`] system will despawn the entity // the `remove_despawned_entities_from_indexes` system will despawn the entity
// if it's not loaded by anything anymore // if it's not loaded by anything anymore
// also we can't just ecs.despawn because if we're in a swarm then the entity // also we can't just ecs.despawn because if we're in a swarm then the entity

View file

@ -1,4 +1,4 @@
use azalea_entity::{EntityUpdateSet, metadata::Health}; use azalea_entity::metadata::Health;
use bevy_app::{App, First, Plugin, PreUpdate, Update}; use bevy_app::{App, First, Plugin, PreUpdate, Update};
use bevy_ecs::{ use bevy_ecs::{
prelude::*, prelude::*,
@ -46,9 +46,7 @@ impl Plugin for PacketPlugin {
.add_systems( .add_systems(
PreUpdate, PreUpdate,
( (
game::process_packet_events game::process_packet_events,
// we want to index and deindex right after
.before(EntityUpdateSet::Deindex),
config::process_packet_events, config::process_packet_events,
login::handle_send_packet_event, login::handle_send_packet_event,
login::process_packet_events, login::process_packet_events,

View file

@ -1,6 +1,9 @@
//! Stuff related to entity indexes and keeping track of entities in the world. //! Stuff related to entity indexes and keeping track of entities in the world.
use std::{collections::HashMap, fmt::Debug}; use std::{
collections::{HashMap, HashSet},
fmt::Debug,
};
use azalea_core::position::ChunkPos; use azalea_core::position::ChunkPos;
use azalea_world::{Instance, InstanceContainer, InstanceName, MinecraftEntityId}; use azalea_world::{Instance, InstanceContainer, InstanceName, MinecraftEntityId};
@ -12,7 +15,7 @@ use bevy_ecs::{
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use nohash_hasher::IntMap; use nohash_hasher::IntMap;
use tracing::{debug, warn}; use tracing::{debug, trace, warn};
use uuid::Uuid; use uuid::Uuid;
use super::LoadedBy; use super::LoadedBy;
@ -75,22 +78,39 @@ impl EntityIdIndex {
pub fn insert(&mut self, id: MinecraftEntityId, entity: Entity) { pub fn insert(&mut self, id: MinecraftEntityId, entity: Entity) {
self.entity_by_id.insert(id, entity); self.entity_by_id.insert(id, entity);
self.id_by_entity.insert(entity, id); self.id_by_entity.insert(entity, id);
trace!("Inserted {id} -> {entity:?} into a client's EntityIdIndex");
} }
pub fn remove(&mut self, id: MinecraftEntityId) -> Option<Entity> { pub fn remove(&mut self, id: MinecraftEntityId) -> Option<Entity> {
if let Some(entity) = self.entity_by_id.remove(&id) { if let Some(entity) = self.entity_by_id.remove(&id) {
trace!(
"Removed {id} -> {entity:?} from a client's EntityIdIndex (using EntityIdIndex::remove)"
);
self.id_by_entity.remove(&entity); self.id_by_entity.remove(&entity);
Some(entity) Some(entity)
} else { } else {
trace!(
"Failed to remove {id} from a client's EntityIdIndex (using EntityIdIndex::remove)"
);
None None
} }
} }
pub fn remove_by_ecs_entity(&mut self, entity: Entity) -> Option<MinecraftEntityId> { pub fn remove_by_ecs_entity(&mut self, entity: Entity) -> Option<MinecraftEntityId> {
if let Some(id) = self.id_by_entity.remove(&entity) { if let Some(id) = self.id_by_entity.remove(&entity) {
trace!(
"Removed {id} -> {entity:?} from a client's EntityIdIndex (using EntityIdIndex::remove_by_ecs_entity)."
);
self.entity_by_id.remove(&id); self.entity_by_id.remove(&id);
Some(id) Some(id)
} else { } else {
// this is expected to happen when despawning entities if it was already
// despawned for another reason (like because the client received a
// remove_entities packet, or if we're in a shared instance where entity ids are
// different for each client)
trace!(
"Failed to remove {entity:?} from a client's EntityIdIndex (using EntityIdIndex::remove_by_ecs_entity). This may be expected behavior."
);
None None
} }
} }
@ -132,6 +152,7 @@ pub fn update_entity_chunk_positions(
.entry(new_chunk) .entry(new_chunk)
.or_default() .or_default()
.insert(entity); .insert(entity);
trace!("Entity {entity:?} moved from {old_chunk:?} to {new_chunk:?}");
} }
} }
} }
@ -208,9 +229,22 @@ pub fn remove_despawned_entities_from_indexes(
instance.entities_by_chunk.remove(&chunk); instance.entities_by_chunk.remove(&chunk);
} }
} else { } else {
warn!( // search all the other chunks for it :(
"Tried to remove entity {entity:?} from chunk {chunk:?} but the entity was not there." let mut found_in_other_chunks = HashSet::new();
); for (other_chunk, entities_in_other_chunk) in &mut instance.entities_by_chunk {
if entities_in_other_chunk.remove(&entity) {
found_in_other_chunks.insert(other_chunk);
}
}
if found_in_other_chunks.is_empty() {
warn!(
"Tried to remove entity {entity:?} from chunk {chunk:?} but the entity was not there or in any other chunks."
);
} else {
warn!(
"Tried to remove entity {entity:?} from chunk {chunk:?} but the entity was not there. Found in and removed from other chunk(s): {found_in_other_chunks:?}"
);
}
} }
} }
_ => { _ => {
@ -225,17 +259,13 @@ pub fn remove_despawned_entities_from_indexes(
} }
if instance.entity_by_id.remove(minecraft_id).is_none() { if instance.entity_by_id.remove(minecraft_id).is_none() {
debug!( debug!(
"Tried to remove entity {entity:?} from the id index but it was not there. This may be expected if you're in a shared instance." "Tried to remove entity {entity:?} from the per-instance entity id index but it was not there. This may be expected if you're in a shared instance."
); );
} }
// remove it from every client's EntityIdIndex // remove it from every client's EntityIdIndex
for mut entity_id_index in entity_id_index_query.iter_mut() { for mut entity_id_index in entity_id_index_query.iter_mut() {
if entity_id_index.remove_by_ecs_entity(entity).is_none() { entity_id_index.remove_by_ecs_entity(entity);
debug!(
"Tried to remove entity {entity:?} from the id index but it was not there. This may be expected if you're in a shared instance."
);
}
} }
// and now remove the entity from the ecs // and now remove the entity from the ecs

View file

@ -9,7 +9,7 @@ use azalea_core::{
tick::GameTick, tick::GameTick,
}; };
use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId}; use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId};
use bevy_app::{App, Plugin, PreUpdate, Update}; use bevy_app::{App, Plugin, PostUpdate, Update};
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use indexing::EntityUuidIndex; use indexing::EntityUuidIndex;
@ -39,7 +39,7 @@ impl Plugin for EntityPlugin {
// modified during update // modified during update
// despawned post-update (done by this plugin) // despawned post-update (done by this plugin)
app.add_systems( app.add_systems(
PreUpdate, PostUpdate,
indexing::remove_despawned_entities_from_indexes.in_set(EntityUpdateSet::Deindex), indexing::remove_despawned_entities_from_indexes.in_set(EntityUpdateSet::Deindex),
) )
.add_systems( .add_systems(