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

add Loaded component and fix clamping look direction

This commit is contained in:
mat 2023-09-19 02:01:39 -05:00
parent 51963990bc
commit 83cce23614
5 changed files with 86 additions and 66 deletions

View file

@ -22,8 +22,9 @@ use azalea_auth::{game_profile::GameProfile, sessionserver::ClientSessionServerE
use azalea_chat::FormattedText;
use azalea_core::Vec3;
use azalea_entity::{
indexing::EntityIdIndex, metadata::Health, EntityPlugin, EntityUpdateSet, EyeHeight,
LocalEntity, Position,
indexing::{EntityIdIndex, Loaded},
metadata::Health,
EntityPlugin, EntityUpdateSet, EyeHeight, LocalEntity, Position,
};
use azalea_physics::PhysicsPlugin;
use azalea_protocol::{
@ -316,6 +317,7 @@ impl Client {
attack: attack::AttackBundle::default(),
_local: LocalEntity,
_loaded: Loaded,
});
let client = Client::new(
@ -634,6 +636,7 @@ pub struct JoinedClientBundle {
pub attack: attack::AttackBundle,
pub _local: LocalEntity,
pub _loaded: Loaded,
}
pub struct AzaleaPlugin;

View file

@ -388,7 +388,7 @@ impl Client {
/// An event sent when the client starts walking. This does not get sent for
/// non-local entities.
#[derive(Event)]
#[derive(Event, Debug)]
pub struct StartWalkEvent {
pub entity: Entity,
pub direction: WalkDirection,

View file

@ -76,6 +76,14 @@ impl Debug for EntityUuidIndex {
}
}
/// A marker component for entities that are in the world and aren't temporary
/// duplicates of other ones. This is meant to be used as a query filter
/// `Added<Loaded>` (since if you do `Added` with another component it might
/// trigger multiple times when in a swarm due to how entities are handled for
/// swarms).
#[derive(Component)]
pub struct Loaded;
/// Remove new entities that have the same id as an existing entity, and
/// increase the reference counts.
///
@ -86,7 +94,7 @@ impl Debug for EntityUuidIndex {
pub fn deduplicate_entities(
mut commands: Commands,
mut query: Query<
(Entity, &MinecraftEntityId, &InstanceName),
(Entity, &MinecraftEntityId, &InstanceName, Option<&Loaded>),
(Changed<MinecraftEntityId>, Without<LocalEntity>),
>,
mut loaded_by_query: Query<&mut LoadedBy>,
@ -94,43 +102,51 @@ pub fn deduplicate_entities(
instance_container: Res<InstanceContainer>,
) {
// if this entity already exists, remove it and keep the old one
for (new_entity, id, world_name) in query.iter_mut() {
if let Some(world_lock) = instance_container.get(world_name) {
let world = world_lock.write();
if let Some(old_entity) = world.entity_by_id.get(id) {
if old_entity == &new_entity {
continue;
}
for (new_entity, id, world_name, loaded) in query.iter_mut() {
let Some(world_lock) = instance_container.get(world_name) else {
error!("Entity was inserted into a world that doesn't exist.");
continue;
};
let world = world_lock.write();
let Some(old_entity) = world.entity_by_id.get(id) else {
// not in index yet, so it's good
if loaded.is_none() {
commands.entity(new_entity).insert(Loaded);
}
continue;
};
if old_entity == &new_entity {
if loaded.is_none() {
commands.entity(new_entity).insert(Loaded);
}
continue;
}
// this entity already exists!!! remove the one we just added but increase
// the reference count
let new_loaded_by = loaded_by_query
.get(new_entity)
.expect("Entities should always have the LoadedBy component ({new_entity:?} did not)")
.clone();
// this entity already exists!!! remove the one we just added but increase
// the reference count
let new_loaded_by = loaded_by_query
.get(new_entity)
.expect("Entities should always have the LoadedBy component ({new_entity:?} did not)")
.clone();
// update the `EntityIdIndex`s of the local players that have this entity loaded
for local_player in new_loaded_by.iter() {
let mut entity_id_index = entity_id_index_query
// update the `EntityIdIndex`s of the local players that have this entity loaded
for local_player in new_loaded_by.iter() {
let mut entity_id_index = entity_id_index_query
.get_mut(*local_player)
.expect("Local players should always have the EntityIdIndex component ({local_player:?} did not)");
entity_id_index.insert(*id, *old_entity);
}
let old_loaded_by = loaded_by_query.get_mut(*old_entity);
// merge them if possible
if let Ok(mut old_loaded_by) = old_loaded_by {
old_loaded_by.extend(new_loaded_by.iter());
}
commands.entity(new_entity).despawn();
info!(
"Entity with id {id:?} / {new_entity:?} already existed in the world, merging it with {old_entity:?}"
);
continue;
}
} else {
error!("Entity was inserted into a world that doesn't exist.");
entity_id_index.insert(*id, *old_entity);
}
let old_loaded_by = loaded_by_query.get_mut(*old_entity);
// merge them if possible
if let Ok(mut old_loaded_by) = old_loaded_by {
old_loaded_by.extend(new_loaded_by.iter());
}
commands.entity(new_entity).despawn();
info!(
"Entity with id {id:?} / {new_entity:?} already existed in the world, merging it with {old_entity:?}"
);
continue;
}
}
@ -147,23 +163,24 @@ pub fn deduplicate_local_entities(
) {
// if this entity already exists, remove the old one
for (new_entity, id, world_name) in query.iter_mut() {
if let Some(world_lock) = instance_container.get(world_name) {
let world = world_lock.write();
if let Some(old_entity) = world.entity_by_id.get(id) {
if old_entity == &new_entity {
// lol
continue;
}
commands.entity(*old_entity).despawn();
debug!(
"Added local entity {id:?} / {new_entity:?} but already existed in world as {old_entity:?}, despawning {old_entity:?}"
);
break;
}
} else {
let Some(world_lock) = instance_container.get(world_name) else {
error!("Entity was inserted into a world that doesn't exist.");
continue;
};
let world = world_lock.write();
let Some(old_entity) = world.entity_by_id.get(id) else {
continue;
};
if old_entity == &new_entity {
// lol
continue;
}
commands.entity(*old_entity).despawn();
debug!(
"Added local entity {id:?} / {new_entity:?} but already existed in world as {old_entity:?}, despawning {old_entity:?}"
);
break;
}
}

View file

@ -129,7 +129,7 @@ pub struct LoadedBy(pub HashSet<Entity>);
pub fn clamp_look_direction(mut query: Query<&mut LookDirection>) {
for mut look_direction in &mut query {
look_direction.y_rot %= 360.0;
look_direction.y_rot = look_direction.y_rot.rem_euclid(360.0);
look_direction.x_rot = look_direction.x_rot.clamp(-90.0, 90.0) % 360.0;
}
}

View file

@ -164,17 +164,17 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
println!("inventory: {:?}", bot.menu());
}
"findblock" => {
let target_pos = bot
.world()
.read()
.find_block(bot.position(), &azalea::Block::DiamondBlock.into());
let target_pos = bot.world().read().find_block(
bot.position(),
&azalea::registry::Block::DiamondBlock.into(),
);
bot.chat(&format!("target_pos: {target_pos:?}",));
}
"gotoblock" => {
let target_pos = bot
.world()
.read()
.find_block(bot.position(), &azalea::Block::DiamondBlock.into());
let target_pos = bot.world().read().find_block(
bot.position(),
&azalea::registry::Block::DiamondBlock.into(),
);
if let Some(target_pos) = target_pos {
// +1 to stand on top of the block
bot.goto(BlockPosGoal::from(target_pos.up(1)));
@ -183,10 +183,10 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
}
}
"mineblock" => {
let target_pos = bot
.world()
.read()
.find_block(bot.position(), &azalea::Block::DiamondBlock.into());
let target_pos = bot.world().read().find_block(
bot.position(),
&azalea::registry::Block::DiamondBlock.into(),
);
if let Some(target_pos) = target_pos {
// +1 to stand on top of the block
bot.chat("ok mining diamond block");
@ -201,7 +201,7 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
let target_pos = bot
.world()
.read()
.find_block(bot.position(), &azalea::Block::Lever.into());
.find_block(bot.position(), &azalea::registry::Block::Lever.into());
let Some(target_pos) = target_pos else {
bot.chat("no lever found");
return Ok(());
@ -218,7 +218,7 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
let target_pos = bot
.world()
.read()
.find_block(bot.position(), &azalea::Block::Chest.into());
.find_block(bot.position(), &azalea::registry::Block::Chest.into());
let Some(target_pos) = target_pos else {
bot.chat("no chest found");
return Ok(());