diff --git a/src/lua/client/container.rs b/src/lua/client/container.rs index f6ab2a4..eb1e17f 100644 --- a/src/lua/client/container.rs +++ b/src/lua/client/container.rs @@ -7,6 +7,7 @@ use azalea::{ use mlua::{Lua, Result, UserDataRef, Value}; use super::{Client, Container, ContainerRef, ItemStack, Vec3}; +use crate::unpack; pub fn container(_lua: &Lua, client: &Client) -> Result { Ok(ContainerRef(client.get_inventory())) @@ -95,9 +96,10 @@ pub async fn open_container_at( client: UserDataRef, position: Vec3, ) -> Result> { + let client = unpack!(client); + #[allow(clippy::cast_possible_truncation)] Ok(client - .clone() .open_container_at(BlockPos::new( position.x as i32, position.y as i32, diff --git a/src/lua/client/interaction.rs b/src/lua/client/interaction.rs index 384268f..dc7ee2c 100644 --- a/src/lua/client/interaction.rs +++ b/src/lua/client/interaction.rs @@ -6,6 +6,7 @@ use azalea::{ use mlua::{Lua, Result, UserDataRef}; use super::{Client, Vec3}; +use crate::unpack; pub fn attack(_lua: &Lua, client: &Client, entity_id: i32) -> Result<()> { if let Some(entity) = client.entity_id_by_minecraft_id(MinecraftEntityId(entity_id)) { @@ -29,9 +30,10 @@ pub fn has_attack_cooldown(_lua: &Lua, client: &Client) -> Result { } pub async fn mine(_lua: Lua, client: UserDataRef, position: Vec3) -> Result<()> { + let client = unpack!(client); + #[allow(clippy::cast_possible_truncation)] client - .clone() .mine(BlockPos::new( position.x as i32, position.y as i32, diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 48adea7..54f42e7 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -6,7 +6,7 @@ mod movement; mod state; mod world; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use azalea::{Client as AzaleaClient, core::entity_id::MinecraftEntityId}; use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods}; @@ -28,12 +28,6 @@ impl Deref for Client { } } -impl DerefMut for Client { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().expect("should have received init event") - } -} - impl UserData for Client { fn add_fields>(f: &mut F) { f.add_field_method_get("air_supply", state::air_supply); @@ -121,3 +115,12 @@ fn username(_lua: &Lua, client: &Client) -> Result { fn uuid(_lua: &Lua, client: &Client) -> Result { Ok(client.uuid().to_string()) } + +#[macro_export] +macro_rules! unpack { + ($client:ident) => {{ + let inner = (**$client).clone(); + drop($client); + inner + }}; +} diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index 78b8dfe..caf2783 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -1,5 +1,5 @@ use azalea::{ - BlockPos, SprintDirection, WalkDirection, + BlockPos, Client as AzaleaClient, SprintDirection, WalkDirection, core::{entity_id::MinecraftEntityId, hit_result::HitResult}, entity::Position, interact::pick::HitResultComponent, @@ -12,6 +12,7 @@ use azalea::{ use mlua::{FromLua, Lua, Result, Table, UserDataRef, Value}; use super::{Client, Direction, Vec3}; +use crate::unpack; #[derive(Debug)] struct AnyGoal(Box); @@ -27,7 +28,7 @@ impl Goal for AnyGoal { } #[allow(clippy::cast_possible_truncation)] -fn to_goal(lua: &Lua, client: &Client, data: Table, kind: u8) -> Result { +fn to_goal(lua: &Lua, client: &AzaleaClient, data: Table, kind: u8) -> Result { let goal: Box = match kind { 1 => { let pos = Vec3::from_lua(data.get("position")?, lua)?; @@ -68,6 +69,7 @@ pub fn go_to_reached(_lua: &Lua, client: &Client) -> Result { } pub async fn wait_until_goal_reached(_lua: Lua, client: UserDataRef, (): ()) -> Result<()> { + let client = unpack!(client); client.wait_until_goto_target_reached().await; Ok(()) } @@ -77,6 +79,8 @@ pub async fn go_to( client: UserDataRef, (data, metadata): (Table, Option), ) -> Result<()> { + let client = unpack!(client); + let metadata = metadata.unwrap_or(lua.create_table()?); let options = metadata.get("options").unwrap_or(lua.create_table()?); let goal = to_goal( @@ -85,12 +89,13 @@ pub async fn go_to( data, metadata.get("type").unwrap_or_default(), )?; - if options.get("without_mining").unwrap_or_default() { - client.start_goto_with_opts(goal, PathfinderOpts::new().allow_mining(false)); - client.wait_until_goto_target_reached().await; - } else { - client.goto(goal).await; - } + client + .goto_with_opts( + goal, + PathfinderOpts::new().allow_mining(options.get("without_mining").unwrap_or_default()), + ) + .await; + Ok(()) } @@ -99,6 +104,8 @@ pub async fn start_go_to( client: UserDataRef, (data, metadata): (Table, Option
), ) -> Result<()> { + let client = unpack!(client); + let metadata = metadata.unwrap_or(lua.create_table()?); let options = metadata.get("options").unwrap_or(lua.create_table()?); let goal = to_goal( diff --git a/src/lua/client/state.rs b/src/lua/client/state.rs index 8054432..3d95f69 100644 --- a/src/lua/client/state.rs +++ b/src/lua/client/state.rs @@ -6,6 +6,7 @@ use azalea_hax::AntiKnockback; use mlua::{Error, Lua, Result, Table, UserDataRef}; use super::Client; +use crate::unpack; pub fn air_supply(_lua: &Lua, client: &Client) -> Result { Ok(client.component::().0) @@ -37,6 +38,8 @@ pub async fn set_client_information( client: UserDataRef, info: Table, ) -> Result<()> { + let client = unpack!(client); + let get_bool = |table: &Table, name| table.get(name).unwrap_or(true); client.set_client_information(ClientInformation { allows_listing: info.get("allows_listing")?, diff --git a/src/lua/client/world/find.rs b/src/lua/client/world/find.rs index 1da0297..5a8fbdd 100644 --- a/src/lua/client/world/find.rs +++ b/src/lua/client/world/find.rs @@ -10,7 +10,7 @@ use azalea::{ use mlua::{Function, Lua, Result, Table, UserDataRef}; use super::{Client, Direction, Vec3}; -use crate::lua::client::MinecraftEntityId; +use crate::{lua::client::MinecraftEntityId, unpack}; pub fn blocks( _lua: &Lua, @@ -39,6 +39,8 @@ pub fn blocks( } pub async fn all_entities(lua: Lua, client: UserDataRef, (): ()) -> Result> { + let client = unpack!(client); + let mut matched = Vec::with_capacity(256); for (position, custom_name, kind, uuid, direction, id, owner_uuid, pose) in get_entities!(client) @@ -65,6 +67,8 @@ pub async fn entities( client: UserDataRef, filter_fn: Function, ) -> Result> { + let client = unpack!(client); + let mut matched = Vec::new(); for (position, custom_name, kind, uuid, direction, id, owner_uuid, pose) in get_entities!(client) @@ -89,6 +93,8 @@ pub async fn entities( } pub async fn all_players(lua: Lua, client: UserDataRef, (): ()) -> Result> { + let client = unpack!(client); + let mut matched = Vec::new(); for (id, uuid, kind, position, direction, pose) in get_players!(client) { let table = lua.create_table()?; @@ -108,6 +114,8 @@ pub async fn players( client: UserDataRef, filter_fn: Function, ) -> Result> { + let client = unpack!(client); + let mut matched = Vec::new(); for (id, uuid, kind, position, direction, pose) in get_players!(client) { let table = lua.create_table()?; diff --git a/src/lua/client/world/queries.rs b/src/lua/client/world/queries.rs index 06aca95..3eb7610 100644 --- a/src/lua/client/world/queries.rs +++ b/src/lua/client/world/queries.rs @@ -1,8 +1,8 @@ #[macro_export] macro_rules! get_entities { ($client:ident) => {{ - let mut ecs = $client.ecs.write(); - ecs.query::<( + let ecs = $client.ecs.read(); + if let Some(mut query) = ecs.try_query::<( &AzaleaPosition, &CustomName, &EntityKindComponent, @@ -11,31 +11,35 @@ macro_rules! get_entities { &MinecraftEntityId, Option<&Owneruuid>, &Pose, - )>() - .iter(&ecs) - .map( - |(position, custom_name, kind, uuid, direction, id, owner_uuid, pose)| { - ( - Vec3::from(*position), - custom_name.as_ref().map(ToString::to_string), - kind.to_string(), - uuid.to_string(), - Direction::from(direction), - id.0, - owner_uuid.map(ToOwned::to_owned), - *pose as u8, + )>() { + query + .iter(&ecs) + .map( + |(position, custom_name, kind, uuid, direction, id, owner_uuid, pose)| { + ( + Vec3::from(*position), + custom_name.as_ref().map(ToString::to_string), + kind.to_string(), + uuid.to_string(), + Direction::from(direction), + id.0, + owner_uuid.map(ToOwned::to_owned), + *pose as u8, + ) + }, ) - }, - ) - .collect::>() + .collect::>() + } else { + Vec::new() + } }}; } #[macro_export] macro_rules! get_players { ($client:ident) => {{ - let mut ecs = $client.ecs.write(); - ecs.query_filtered::<( + let ecs = $client.ecs.read(); + if let Some(mut query) = ecs.try_query_filtered::<( &MinecraftEntityId, &EntityUuid, &EntityKindComponent, @@ -43,17 +47,22 @@ macro_rules! get_players { &LookDirection, &Pose, ), (With, Without)>() - .iter(&ecs) - .map(|(id, uuid, kind, position, direction, pose)| { - ( - id.0, - uuid.to_string(), - kind.to_string(), - Vec3::from(*position), - Direction::from(direction), - *pose as u8, - ) - }) - .collect::>() + { + query + .iter(&ecs) + .map(|(id, uuid, kind, position, direction, pose)| { + ( + id.0, + uuid.to_string(), + kind.to_string(), + Vec3::from(*position), + Direction::from(direction), + *pose as u8, + ) + }) + .collect::>() + } else { + Vec::new() + } }}; }