feat(client/movement): support inverse goal

This commit is contained in:
Ryan 2025-03-01 03:33:35 -05:00
parent 663873ba59
commit cbdca4b7c1
Signed by: ErrorNoInternet
GPG Key ID: 2486BFB7B1E6A4A3

View File

@ -5,7 +5,7 @@ use azalea::{
interact::HitResultComponent, interact::HitResultComponent,
pathfinder::{ pathfinder::{
ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt, ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt,
goals::{BlockPosGoal, Goal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal}, goals::{BlockPosGoal, Goal, InverseGoal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal},
}, },
protocol::packets::game::{ServerboundPlayerCommand, s_player_command::Action}, protocol::packets::game::{ServerboundPlayerCommand, s_player_command::Action},
world::MinecraftEntityId, world::MinecraftEntityId,
@ -27,36 +27,48 @@ pub async fn go_to(
client: UserDataRef<Client>, client: UserDataRef<Client>,
(data, metadata): (Value, Option<Table>), (data, metadata): (Value, Option<Table>),
) -> Result<()> { ) -> Result<()> {
fn g(client: &Client, without_mining: bool, goal: impl Goal + Send + Sync + 'static) { fn goto_with_options<G: Goal + Send + Sync + 'static>(
if without_mining { client: &Client,
options: &Table,
goal: G,
) {
if options.get("without_mining").unwrap_or_default() {
client.goto_without_mining(goal); client.goto_without_mining(goal);
} else { } else {
client.goto(goal); client.goto(goal);
} }
} }
fn goto<G: Goal + Send + Sync + 'static>(client: &Client, options: Table, goal: G) {
if options.get("inverse").unwrap_or_default() {
goto_with_options(client, &options, InverseGoal(goal));
} else {
goto_with_options(client, &options, goal);
}
}
let error = mlua::Error::FromLuaConversionError { let error = mlua::Error::FromLuaConversionError {
from: data.type_name(), from: data.type_name(),
to: "Table".to_string(), to: "Table".to_string(),
message: None, message: None,
}; };
let (goal_type, without_mining) = metadata let (goal_type, options) = if let Some(metadata) = metadata {
.map(|t| { (
( metadata.get("type")?,
t.get("type").unwrap_or_default(), metadata.get("options").unwrap_or(lua.create_table()?),
t.get("without_mining").unwrap_or_default(), )
) } else {
}) (0, lua.create_table()?)
.unwrap_or_default(); };
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
match goal_type { match goal_type {
1 => { 1 => {
let t = data.as_table().ok_or(error)?; let t = data.as_table().ok_or(error)?;
let p = Vec3::from_lua(t.get("position")?, &lua)?; let p = Vec3::from_lua(t.get("position")?, &lua)?;
g( goto(
&client, &client,
without_mining, options,
RadiusGoal { RadiusGoal {
pos: azalea::Vec3::new(p.x, p.y, p.z), pos: azalea::Vec3::new(p.x, p.y, p.z),
radius: t.get("radius")?, radius: t.get("radius")?,
@ -65,9 +77,9 @@ pub async fn go_to(
} }
2 => { 2 => {
let p = Vec3::from_lua(data, &lua)?; let p = Vec3::from_lua(data, &lua)?;
g( goto(
&client, &client,
without_mining, options,
ReachBlockPosGoal { ReachBlockPosGoal {
pos: BlockPos::new(p.x as i32, p.y as i32, p.z as i32), pos: BlockPos::new(p.x as i32, p.y as i32, p.z as i32),
chunk_storage: client.world().read().chunks.clone(), chunk_storage: client.world().read().chunks.clone(),
@ -76,27 +88,27 @@ pub async fn go_to(
} }
3 => { 3 => {
let t = data.as_table().ok_or(error)?; let t = data.as_table().ok_or(error)?;
g( goto(
&client, &client,
without_mining, options,
XZGoal { XZGoal {
x: t.get("x")?, x: t.get("x")?,
z: t.get("z")?, z: t.get("z")?,
}, },
); );
} }
4 => g( 4 => goto(
&client, &client,
without_mining, options,
YGoal { YGoal {
y: data.as_table().ok_or(error)?.get("y")?, y: data.as_table().ok_or(error)?.get("y")?,
}, },
), ),
_ => { _ => {
let p = Vec3::from_lua(data, &lua)?; let p = Vec3::from_lua(data, &lua)?;
g( goto(
&client, &client,
without_mining, options,
BlockPosGoal(BlockPos::new(p.x as i32, p.y as i32, p.z as i32)), BlockPosGoal(BlockPos::new(p.x as i32, p.y as i32, p.z as i32)),
); );
} }