From 8e89f8e9ea1d8ec7d7934a284f4a3570862c611a Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 14:21:29 -0500 Subject: [PATCH] feat(client): add remaining miscellaneous fields and methods --- src/main.rs | 2 +- src/scripting/client/interaction.rs | 22 +++++ src/scripting/client/mod.rs | 107 +++++++++++++++++++++---- src/scripting/client/movement.rs | 90 +++++++++++++++++++++ src/scripting/client/pathfinding.rs | 22 ----- src/scripting/direction.rs | 33 ++++++++ src/scripting/entity.rs | 4 +- src/scripting/hunger.rs | 33 ++++++++ src/scripting/logging.rs | 3 +- src/scripting/mod.rs | 18 ++++- src/scripting/{position.rs => vec3.rs} | 6 +- 11 files changed, 292 insertions(+), 48 deletions(-) create mode 100644 src/scripting/client/interaction.rs create mode 100644 src/scripting/client/movement.rs delete mode 100644 src/scripting/client/pathfinding.rs create mode 100644 src/scripting/direction.rs create mode 100644 src/scripting/hunger.rs rename src/scripting/{position.rs => vec3.rs} (91%) diff --git a/src/main.rs b/src/main.rs index 791c852..b882784 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,7 @@ async fn main() -> anyhow::Result<()> { let username = globals.get::("USERNAME")?; globals.set("script_path", script_path)?; - scripting::logging::register(&lua, &globals)?; + scripting::register_functions(&lua, &globals)?; let mut commands = CommandDispatcher::new(); register(&mut commands); diff --git a/src/scripting/client/interaction.rs b/src/scripting/client/interaction.rs new file mode 100644 index 0000000..3345242 --- /dev/null +++ b/src/scripting/client/interaction.rs @@ -0,0 +1,22 @@ +use super::{Client, Vec3}; +use azalea::{BlockPos, world::MinecraftEntityId}; +use mlua::{Lua, Result}; + +pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { + client + .inner + .as_mut() + .unwrap() + .attack(MinecraftEntityId(entity_id)); + Ok(()) +} + +pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client.inner.as_mut().unwrap().block_interact(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )); + Ok(()) +} diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index ff3f7c9..9c92473 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -1,36 +1,104 @@ -mod pathfinding; +mod interaction; +mod movement; mod state; -use super::{entity::Entity, position::Position}; +use super::{direction::Direction, entity::Entity, hunger::Hunger, vec3::Vec3}; use azalea::{ Client as AzaleaClient, ecs::query::Without, - entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, + entity::{ + Dead, EntityKind, EntityUuid, Position as AzaleaPosition, + metadata::{AirSupply, CustomName, Score}, + }, world::MinecraftEntityId, }; -use mlua::{Function, Lua, Result, UserData}; +use mlua::{Function, Lua, Result, UserData, UserDataFields, UserDataMethods}; pub struct Client { pub inner: Option, } impl UserData for Client { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("position", |_, this| { - let position = this.inner.as_ref().unwrap().position(); - Ok(Position { - x: position.x, - y: position.y, - z: position.z, + fn add_fields>(f: &mut F) { + f.add_field_method_get("air_supply", |_, this| { + Ok(this.inner.as_ref().unwrap().component::().0) + }); + + f.add_field_method_get("direction", |_, this| { + let d = this.inner.as_ref().unwrap().direction(); + Ok(Direction { x: d.0, y: d.1 }) + }); + + f.add_field_method_get("eye_position", |_, this| { + let p = this.inner.as_ref().unwrap().eye_position(); + Ok(Vec3 { + x: p.x, + y: p.y, + z: p.z, }) }); + + f.add_field_method_get("health", |_, this| { + Ok(this.inner.as_ref().unwrap().health()) + }); + + f.add_field_method_get("hunger", |_, this| { + let h = this.inner.as_ref().unwrap().hunger(); + Ok(Hunger { + food: h.food, + saturation: h.saturation, + }) + }); + + f.add_field_method_get("position", |_, this| { + let p = this.inner.as_ref().unwrap().position(); + Ok(Vec3 { + x: p.x, + y: p.y, + z: p.z, + }) + }); + + f.add_field_method_get("score", |_, this| { + Ok(this.inner.as_ref().unwrap().component::().0) + }); + + f.add_field_method_get("tab_list", |lua, this| { + let tab_list = lua.create_table()?; + for (uuid, player_info) in this.inner.as_ref().unwrap().tab_list() { + let player = lua.create_table()?; + player.set("gamemode", player_info.gamemode.name())?; + player.set("latency", player_info.latency)?; + player.set("name", player_info.profile.name)?; + player.set( + "display_name", + player_info.display_name.map(|n| n.to_string()), + )?; + tab_list.set(uuid.to_string(), player)?; + } + Ok(tab_list) + }); + + f.add_field_method_get("uuid", |_, this| { + Ok(this.inner.as_ref().unwrap().uuid().to_string()) + }); } - fn add_methods>(methods: &mut M) { - methods.add_async_method("set_client_information", state::set_client_information); - methods.add_method("find_entities", find_entities); - methods.add_method("stop_pathfinding", pathfinding::stop_pathfinding); - methods.add_method_mut("goto", pathfinding::goto); + fn add_methods>(m: &mut M) { + m.add_async_method("set_client_information", state::set_client_information); + m.add_method("chat", chat); + m.add_method("find_entities", find_entities); + m.add_method("stop_pathfinding", movement::stop_pathfinding); + m.add_method_mut("attack", interaction::attack); + m.add_method_mut("block_interact", interaction::block_interact); + m.add_method_mut("goto", movement::goto); + m.add_method_mut("goto_without_mining", movement::goto_without_mining); + m.add_method_mut("jump", movement::jump); + m.add_method_mut("look_at", movement::look_at); + m.add_method_mut("set_direction", movement::set_direction); + m.add_method_mut("set_jumping", movement::set_jumping); + m.add_method_mut("sprint", movement::sprint); + m.add_method_mut("walk", movement::walk); } } @@ -51,7 +119,7 @@ fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result Result Result<()> { + client.inner.as_ref().unwrap().chat(&message); + Ok(()) +} diff --git a/src/scripting/client/movement.rs b/src/scripting/client/movement.rs new file mode 100644 index 0000000..52616a8 --- /dev/null +++ b/src/scripting/client/movement.rs @@ -0,0 +1,90 @@ +use super::{Client, Vec3}; +use azalea::{ + BlockPos, SprintDirection, WalkDirection, pathfinder::goals::BlockPosGoal, prelude::*, +}; +use mlua::{Lua, Result}; + +pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { + client.inner.as_ref().unwrap().stop_pathfinding(); + Ok(()) +} + +pub fn goto(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_ref() + .unwrap() + .goto(BlockPosGoal(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + ))); + Ok(()) +} + +pub fn goto_without_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_ref() + .unwrap() + .goto_without_mining(BlockPosGoal(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + ))); + Ok(()) +} + +pub fn jump(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { + client.inner.as_mut().unwrap().jump(); + Ok(()) +} + +pub fn look_at(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + client + .inner + .as_mut() + .unwrap() + .look_at(azalea::Vec3::new(position.x, position.y, position.z)); + Ok(()) +} + +pub fn set_direction(_lua: &Lua, client: &mut Client, direction: (f32, f32)) -> Result<()> { + client + .inner + .as_mut() + .unwrap() + .set_direction(direction.0, direction.1); + Ok(()) +} + +pub fn set_jumping(_lua: &Lua, client: &mut Client, jumping: bool) -> Result<()> { + client.inner.as_mut().unwrap().set_jumping(jumping); + Ok(()) +} + +pub fn sprint(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { + client.inner.as_mut().unwrap().sprint(match direction { + 5 => SprintDirection::ForwardRight, + 6 => SprintDirection::ForwardLeft, + _ => SprintDirection::Forward, + }); + Ok(()) +} + +pub fn walk(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { + client.inner.as_mut().unwrap().walk(match direction { + 1 => WalkDirection::Forward, + 2 => WalkDirection::Backward, + 3 => WalkDirection::Left, + 4 => WalkDirection::Right, + 5 => WalkDirection::ForwardRight, + 6 => WalkDirection::ForwardLeft, + 7 => WalkDirection::BackwardRight, + 8 => WalkDirection::BackwardLeft, + _ => WalkDirection::None, + }); + Ok(()) +} diff --git a/src/scripting/client/pathfinding.rs b/src/scripting/client/pathfinding.rs deleted file mode 100644 index 95fe164..0000000 --- a/src/scripting/client/pathfinding.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{Client, Position}; -use azalea::{BlockPos, pathfinder::goals::BlockPosGoal, prelude::*}; -use mlua::{Lua, Result}; - -pub fn goto(_lua: &Lua, client: &mut Client, position: Position) -> Result<()> { - #[allow(clippy::cast_possible_truncation)] - client - .inner - .as_ref() - .unwrap() - .goto(BlockPosGoal(BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - ))); - Ok(()) -} - -pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { - client.inner.as_ref().unwrap().stop_pathfinding(); - Ok(()) -} diff --git a/src/scripting/direction.rs b/src/scripting/direction.rs new file mode 100644 index 0000000..c58153e --- /dev/null +++ b/src/scripting/direction.rs @@ -0,0 +1,33 @@ +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Direction { + pub x: f32, + pub y: f32, +} + +impl IntoLua for Direction { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("x", self.x)?; + table.set("y", self.y)?; + Ok(Value::Table(table)) + } +} + +impl FromLua for Direction { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + x: table.get("x")?, + y: table.get("y")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Direction".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/entity.rs b/src/scripting/entity.rs index d74a9e6..8d8a881 100644 --- a/src/scripting/entity.rs +++ b/src/scripting/entity.rs @@ -1,4 +1,4 @@ -use super::position::Position; +use super::vec3::Vec3; use mlua::{FromLua, IntoLua, Lua, Result, Value}; #[derive(Clone)] @@ -6,7 +6,7 @@ pub struct Entity { pub id: u32, pub uuid: String, pub kind: String, - pub position: Position, + pub position: Vec3, pub custom_name: Option, } diff --git a/src/scripting/hunger.rs b/src/scripting/hunger.rs new file mode 100644 index 0000000..fd74f59 --- /dev/null +++ b/src/scripting/hunger.rs @@ -0,0 +1,33 @@ +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Hunger { + pub food: u32, + pub saturation: f32, +} + +impl IntoLua for Hunger { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("food", self.food)?; + table.set("saturation", self.saturation)?; + Ok(Value::Table(table)) + } +} + +impl FromLua for Hunger { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + food: table.get("food")?, + saturation: table.get("saturation")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Hunger".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/logging.rs b/src/scripting/logging.rs index c0c78e9..ed073a4 100644 --- a/src/scripting/logging.rs +++ b/src/scripting/logging.rs @@ -1,7 +1,7 @@ use log::{debug, error, info, trace, warn}; use mlua::{Lua, Result, Table}; -pub fn register(lua: &Lua, globals: &Table) -> Result<()> { +pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> { globals.set( "error", lua.create_function(|_, message: String| { @@ -37,5 +37,6 @@ pub fn register(lua: &Lua, globals: &Table) -> Result<()> { Ok(()) })?, )?; + Ok(()) } diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index c1b67f4..10f71b2 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,9 +1,11 @@ pub mod client; +pub mod direction; pub mod entity; +pub mod hunger; pub mod logging; -pub mod position; +pub mod vec3; -use mlua::Lua; +use mlua::{Lua, Table}; #[derive(Debug)] #[allow(dead_code)] @@ -15,6 +17,18 @@ pub enum Error { ReadFile(std::io::Error), } +pub fn register_functions(lua: &Lua, globals: &Table) -> mlua::Result<()> { + globals.set( + "sleep", + lua.create_async_function(async |_, duration: u64| { + tokio::time::sleep(std::time::Duration::from_millis(duration)).await; + Ok(()) + })?, + )?; + + logging::register_functions(lua, globals) +} + pub fn reload(lua: &Lua) -> Result<(), Error> { lua.load( &std::fs::read_to_string( diff --git a/src/scripting/position.rs b/src/scripting/vec3.rs similarity index 91% rename from src/scripting/position.rs rename to src/scripting/vec3.rs index 16df16e..45cdbe5 100644 --- a/src/scripting/position.rs +++ b/src/scripting/vec3.rs @@ -1,13 +1,13 @@ use mlua::{FromLua, IntoLua, Lua, Result, Value}; #[derive(Clone)] -pub struct Position { +pub struct Vec3 { pub x: f64, pub y: f64, pub z: f64, } -impl IntoLua for Position { +impl IntoLua for Vec3 { fn into_lua(self, lua: &Lua) -> Result { let table = lua.create_table()?; table.set("x", self.x)?; @@ -17,7 +17,7 @@ impl IntoLua for Position { } } -impl FromLua for Position { +impl FromLua for Vec3 { fn from_lua(value: Value, _lua: &Lua) -> Result { if let Value::Table(table) = value { Ok(Self {