feat(client): add world interaction methods
This commit is contained in:
parent
8e89f8e9ea
commit
04b0bdd756
48
src/scripting/block.rs
Normal file
48
src/scripting/block.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use mlua::{FromLua, IntoLua, Lua, Result, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Block {
|
||||
pub id: String,
|
||||
pub friction: f32,
|
||||
pub jump_factor: f32,
|
||||
pub destroy_time: f32,
|
||||
pub explosion_resistance: f32,
|
||||
pub requires_correct_tool_for_drops: bool,
|
||||
}
|
||||
|
||||
impl IntoLua for Block {
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
let table = lua.create_table()?;
|
||||
table.set("id", self.id)?;
|
||||
table.set("friction", self.friction)?;
|
||||
table.set("jump_factor", self.jump_factor)?;
|
||||
table.set("destroy_time", self.destroy_time)?;
|
||||
table.set("explosion_resistance", self.explosion_resistance)?;
|
||||
table.set(
|
||||
"requires_correct_tool_for_drops",
|
||||
self.requires_correct_tool_for_drops,
|
||||
)?;
|
||||
Ok(Value::Table(table))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Block {
|
||||
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
Ok(Self {
|
||||
id: table.get("id")?,
|
||||
friction: table.get("friction")?,
|
||||
jump_factor: table.get("jump_factor")?,
|
||||
destroy_time: table.get("destroy_time")?,
|
||||
explosion_resistance: table.get("explosion_resistance")?,
|
||||
requires_correct_tool_for_drops: table.get("requires_correct_tool_for_drops")?,
|
||||
})
|
||||
} else {
|
||||
Err(mlua::Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Block".to_string(),
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,17 @@
|
||||
mod interaction;
|
||||
mod movement;
|
||||
mod state;
|
||||
mod world;
|
||||
|
||||
use super::{direction::Direction, entity::Entity, hunger::Hunger, vec3::Vec3};
|
||||
use super::{
|
||||
block::Block, direction::Direction, entity::Entity, fluid_state::FluidState, hunger::Hunger,
|
||||
vec3::Vec3,
|
||||
};
|
||||
use azalea::{
|
||||
Client as AzaleaClient,
|
||||
ecs::query::Without,
|
||||
entity::{
|
||||
Dead, EntityKind, EntityUuid, Position as AzaleaPosition,
|
||||
metadata::{AirSupply, CustomName, Score},
|
||||
},
|
||||
world::MinecraftEntityId,
|
||||
entity::metadata::{AirSupply, Score},
|
||||
};
|
||||
use mlua::{Function, Lua, Result, UserData, UserDataFields, UserDataMethods};
|
||||
use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods};
|
||||
|
||||
pub struct Client {
|
||||
pub inner: Option<AzaleaClient>,
|
||||
@ -87,7 +86,11 @@ impl UserData for Client {
|
||||
fn add_methods<M: UserDataMethods<Self>>(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("find_blocks", world::find_blocks);
|
||||
m.add_method("find_entities", world::find_entities);
|
||||
m.add_method("get_block_from_state", world::get_block_from_state);
|
||||
m.add_method("get_block_state", world::get_block_state);
|
||||
m.add_method("get_fluid_state", world::get_fluid_state);
|
||||
m.add_method("stop_pathfinding", movement::stop_pathfinding);
|
||||
m.add_method_mut("attack", interaction::attack);
|
||||
m.add_method_mut("block_interact", interaction::block_interact);
|
||||
@ -102,39 +105,6 @@ impl UserData for Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result<Vec<Entity>> {
|
||||
let mut matched = Vec::new();
|
||||
|
||||
let mut ecs = client.inner.as_ref().unwrap().ecs.lock();
|
||||
let mut query = ecs.query_filtered::<(
|
||||
&MinecraftEntityId,
|
||||
&EntityUuid,
|
||||
&EntityKind,
|
||||
&AzaleaPosition,
|
||||
&CustomName,
|
||||
), Without<Dead>>();
|
||||
|
||||
for (&id, uuid, kind, position, custom_name) in query.iter(&ecs) {
|
||||
let entity = Entity {
|
||||
id: id.0,
|
||||
uuid: uuid.to_string(),
|
||||
kind: kind.to_string(),
|
||||
position: Vec3 {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
z: position.z,
|
||||
},
|
||||
custom_name: custom_name.as_ref().map(ToString::to_string),
|
||||
};
|
||||
|
||||
if filter_fn.call::<bool>(entity.clone()).unwrap() {
|
||||
matched.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(matched)
|
||||
}
|
||||
|
||||
fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> {
|
||||
client.inner.as_ref().unwrap().chat(&message);
|
||||
Ok(())
|
||||
|
132
src/scripting/client/world.rs
Normal file
132
src/scripting/client/world.rs
Normal file
@ -0,0 +1,132 @@
|
||||
use super::{Block, Client, Entity, FluidState, Vec3};
|
||||
use azalea::{
|
||||
BlockPos,
|
||||
blocks::{Block as AzaleaBlock, BlockState, BlockStates},
|
||||
ecs::query::Without,
|
||||
entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName},
|
||||
world::MinecraftEntityId,
|
||||
};
|
||||
use mlua::{Function, Lua, Result};
|
||||
|
||||
pub fn find_blocks(
|
||||
_lua: &Lua,
|
||||
client: &Client,
|
||||
(nearest_to, block_names): (Vec3, Vec<String>),
|
||||
) -> Result<Vec<Vec3>> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
Ok(client
|
||||
.inner
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.world()
|
||||
.read()
|
||||
.find_blocks(
|
||||
BlockPos::new(
|
||||
nearest_to.x as i32,
|
||||
nearest_to.y as i32,
|
||||
nearest_to.z as i32,
|
||||
),
|
||||
&BlockStates {
|
||||
set: block_names
|
||||
.iter()
|
||||
.flat_map(|n| {
|
||||
(u32::MIN..u32::MAX)
|
||||
.map_while(|i| BlockState::try_from(i).ok())
|
||||
.filter(move |&b| n == Into::<Box<dyn AzaleaBlock>>::into(b).id())
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.map(|p| Vec3 {
|
||||
x: f64::from(p.x),
|
||||
y: f64::from(p.y),
|
||||
z: f64::from(p.z),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result<Vec<Entity>> {
|
||||
let mut matched = Vec::new();
|
||||
|
||||
let mut ecs = client.inner.as_ref().unwrap().ecs.lock();
|
||||
let mut query = ecs.query_filtered::<(
|
||||
&MinecraftEntityId,
|
||||
&EntityUuid,
|
||||
&EntityKind,
|
||||
&AzaleaPosition,
|
||||
&CustomName,
|
||||
), Without<Dead>>();
|
||||
|
||||
for (&id, uuid, kind, position, custom_name) in query.iter(&ecs) {
|
||||
let entity = Entity {
|
||||
id: id.0,
|
||||
uuid: uuid.to_string(),
|
||||
kind: kind.to_string(),
|
||||
position: Vec3 {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
z: position.z,
|
||||
},
|
||||
custom_name: custom_name.as_ref().map(ToString::to_string),
|
||||
};
|
||||
|
||||
if filter_fn.call::<bool>(entity.clone()).unwrap() {
|
||||
matched.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(matched)
|
||||
}
|
||||
|
||||
pub fn get_block_from_state(_lua: &Lua, _client: &Client, state: u32) -> Result<Option<Block>> {
|
||||
let Ok(state) = BlockState::try_from(state) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let block: Box<dyn AzaleaBlock> = state.into();
|
||||
let behavior = block.behavior();
|
||||
|
||||
Ok(Some(Block {
|
||||
id: block.id().to_string(),
|
||||
friction: behavior.friction,
|
||||
jump_factor: behavior.jump_factor,
|
||||
destroy_time: behavior.destroy_time,
|
||||
explosion_resistance: behavior.explosion_resistance,
|
||||
requires_correct_tool_for_drops: behavior.requires_correct_tool_for_drops,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn get_block_state(_lua: &Lua, client: &Client, position: Vec3) -> Result<Option<u16>> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
Ok(client
|
||||
.inner
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.world()
|
||||
.read()
|
||||
.get_block_state(&BlockPos::new(
|
||||
position.x as i32,
|
||||
position.y as i32,
|
||||
position.z as i32,
|
||||
))
|
||||
.map(|b| b.id))
|
||||
}
|
||||
|
||||
pub fn get_fluid_state(_lua: &Lua, client: &Client, position: Vec3) -> Result<Option<FluidState>> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
Ok(client
|
||||
.inner
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.world()
|
||||
.read()
|
||||
.get_fluid_state(&BlockPos::new(
|
||||
position.x as i32,
|
||||
position.y as i32,
|
||||
position.z as i32,
|
||||
))
|
||||
.map(|f| FluidState {
|
||||
kind: f.kind as u8,
|
||||
amount: f.amount,
|
||||
falling: f.falling,
|
||||
}))
|
||||
}
|
36
src/scripting/fluid_state.rs
Normal file
36
src/scripting/fluid_state.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use mlua::{FromLua, IntoLua, Lua, Result, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FluidState {
|
||||
pub kind: u8,
|
||||
pub amount: u8,
|
||||
pub falling: bool,
|
||||
}
|
||||
|
||||
impl IntoLua for FluidState {
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
let table = lua.create_table()?;
|
||||
table.set("kind", self.kind)?;
|
||||
table.set("amount", self.amount)?;
|
||||
table.set("falling", self.falling)?;
|
||||
Ok(Value::Table(table))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for FluidState {
|
||||
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
Ok(Self {
|
||||
kind: table.get("kind")?,
|
||||
amount: table.get("amount")?,
|
||||
falling: table.get("falling")?,
|
||||
})
|
||||
} else {
|
||||
Err(mlua::Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "FluidState".to_string(),
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
pub mod block;
|
||||
pub mod client;
|
||||
pub mod direction;
|
||||
pub mod entity;
|
||||
pub mod fluid_state;
|
||||
pub mod hunger;
|
||||
pub mod logging;
|
||||
pub mod vec3;
|
||||
|
Loading…
x
Reference in New Issue
Block a user