refactor: rename a few things
This commit is contained in:
48
src/lua/block.rs
Normal file
48
src/lua/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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
52
src/lua/client/interaction.rs
Normal file
52
src/lua/client/interaction.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use super::{Client, Vec3};
|
||||
use azalea::{BlockPos, BotClientExt, world::MinecraftEntityId};
|
||||
use mlua::{Lua, Result, UserDataRef};
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
pub async fn mine(_lua: Lua, client: UserDataRef<Client>, position: Vec3) -> Result<()> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
client
|
||||
.inner
|
||||
.clone()
|
||||
.unwrap()
|
||||
.mine(BlockPos::new(
|
||||
position.x as i32,
|
||||
position.y as i32,
|
||||
position.z as i32,
|
||||
))
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_mining(_lua: &Lua, client: &Client, mining: bool) -> Result<()> {
|
||||
client.inner.as_ref().unwrap().left_click_mine(mining);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
client.inner.as_mut().unwrap().start_mining(BlockPos::new(
|
||||
position.x as i32,
|
||||
position.y as i32,
|
||||
position.z as i32,
|
||||
));
|
||||
Ok(())
|
||||
}
|
79
src/lua/client/mod.rs
Normal file
79
src/lua/client/mod.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
mod interaction;
|
||||
mod movement;
|
||||
mod state;
|
||||
mod world;
|
||||
|
||||
use super::{
|
||||
block::Block, direction::Direction, entity::Entity, fluid_state::FluidState, hunger::Hunger,
|
||||
vec3::Vec3,
|
||||
};
|
||||
use azalea::Client as AzaleaClient;
|
||||
use mlua::{Lua, Result, Table, UserData, UserDataFields, UserDataMethods};
|
||||
|
||||
pub struct Client {
|
||||
pub inner: Option<AzaleaClient>,
|
||||
}
|
||||
|
||||
impl UserData for Client {
|
||||
fn add_fields<F: UserDataFields<Self>>(f: &mut F) {
|
||||
f.add_field_method_get("air_supply", state::air_supply);
|
||||
f.add_field_method_get("direction", movement::direction);
|
||||
f.add_field_method_get("eye_position", movement::eye_position);
|
||||
f.add_field_method_get("health", state::health);
|
||||
f.add_field_method_get("hunger", state::hunger);
|
||||
f.add_field_method_get("looking_at", movement::looking_at);
|
||||
f.add_field_method_get("pathfinder", movement::pathfinder);
|
||||
f.add_field_method_get("position", movement::position);
|
||||
f.add_field_method_get("score", state::score);
|
||||
f.add_field_method_get("tab_list", tab_list);
|
||||
f.add_field_method_get("uuid", uuid);
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(m: &mut M) {
|
||||
m.add_async_method("mine", interaction::mine);
|
||||
m.add_async_method("set_client_information", state::set_client_information);
|
||||
m.add_method("chat", chat);
|
||||
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("set_mining", interaction::set_mining);
|
||||
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("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("start_mining", interaction::start_mining);
|
||||
m.add_method_mut("walk", movement::walk);
|
||||
}
|
||||
}
|
||||
|
||||
fn tab_list(lua: &Lua, client: &Client) -> Result<Table> {
|
||||
let tab_list = lua.create_table()?;
|
||||
for (uuid, player_info) in client.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)
|
||||
}
|
||||
|
||||
fn uuid(_lua: &Lua, client: &Client) -> Result<String> {
|
||||
Ok(client.inner.as_ref().unwrap().uuid().to_string())
|
||||
}
|
||||
|
||||
fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> {
|
||||
client.inner.as_ref().unwrap().chat(&message);
|
||||
Ok(())
|
||||
}
|
229
src/lua/client/movement.rs
Normal file
229
src/lua/client/movement.rs
Normal file
@@ -0,0 +1,229 @@
|
||||
use super::{Client, Direction, Vec3};
|
||||
use azalea::{
|
||||
BlockPos, BotClientExt, Client as AzaleaClient, SprintDirection, WalkDirection,
|
||||
interact::HitResultComponent,
|
||||
pathfinder::{
|
||||
ExecutingPath, Pathfinder, PathfinderClientExt,
|
||||
goals::{BlockPosGoal, Goal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal},
|
||||
},
|
||||
};
|
||||
use mlua::{FromLua, Lua, Result, Table, Value};
|
||||
|
||||
pub fn direction(_lua: &Lua, client: &Client) -> Result<Direction> {
|
||||
let d = client.inner.as_ref().unwrap().direction();
|
||||
Ok(Direction { x: d.0, y: d.1 })
|
||||
}
|
||||
|
||||
pub fn eye_position(_lua: &Lua, client: &Client) -> Result<Vec3> {
|
||||
let p = client.inner.as_ref().unwrap().eye_position();
|
||||
Ok(Vec3 {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
z: p.z,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn goto(
|
||||
lua: &Lua,
|
||||
client: &mut Client,
|
||||
(data, metadata): (Value, Option<Table>),
|
||||
) -> Result<()> {
|
||||
fn g(client: &AzaleaClient, without_mining: bool, goal: impl Goal + Send + Sync + 'static) {
|
||||
if without_mining {
|
||||
client.goto_without_mining(goal);
|
||||
} else {
|
||||
client.goto(goal);
|
||||
}
|
||||
}
|
||||
|
||||
let error = mlua::Error::FromLuaConversionError {
|
||||
from: data.type_name(),
|
||||
to: "Table".to_string(),
|
||||
message: None,
|
||||
};
|
||||
let client = client.inner.as_ref().unwrap();
|
||||
let (goal_type, without_mining) = metadata
|
||||
.map(|t| {
|
||||
(
|
||||
t.get("type").unwrap_or_default(),
|
||||
t.get("without_mining").unwrap_or_default(),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
match goal_type {
|
||||
1 => {
|
||||
let t = data.as_table().ok_or(error)?;
|
||||
let p = Vec3::from_lua(t.get("position")?, lua)?;
|
||||
g(
|
||||
client,
|
||||
without_mining,
|
||||
RadiusGoal {
|
||||
pos: azalea::Vec3::new(p.x, p.y, p.z),
|
||||
radius: t.get("radius")?,
|
||||
},
|
||||
);
|
||||
}
|
||||
2 => {
|
||||
let p = Vec3::from_lua(data, lua)?;
|
||||
g(
|
||||
client,
|
||||
without_mining,
|
||||
ReachBlockPosGoal {
|
||||
pos: BlockPos::new(p.x as i32, p.y as i32, p.z as i32),
|
||||
chunk_storage: client.world().read().chunks.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
3 => {
|
||||
let t = data.as_table().ok_or(error)?;
|
||||
g(
|
||||
client,
|
||||
without_mining,
|
||||
XZGoal {
|
||||
x: t.get("x")?,
|
||||
z: t.get("z")?,
|
||||
},
|
||||
);
|
||||
}
|
||||
4 => g(
|
||||
client,
|
||||
without_mining,
|
||||
YGoal {
|
||||
y: data.as_integer().ok_or(error)?,
|
||||
},
|
||||
),
|
||||
_ => {
|
||||
let p = Vec3::from_lua(data, lua)?;
|
||||
g(
|
||||
client,
|
||||
without_mining,
|
||||
BlockPosGoal(BlockPos::new(p.x as i32, p.y as i32, p.z as i32)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn jump(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> {
|
||||
client.inner.as_mut().unwrap().jump();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn looking_at(lua: &Lua, client: &Client) -> Result<Option<Table>> {
|
||||
let hr = client
|
||||
.inner
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.component::<HitResultComponent>();
|
||||
Ok(if hr.miss {
|
||||
None
|
||||
} else {
|
||||
let result = lua.create_table()?;
|
||||
result.set(
|
||||
"position",
|
||||
Vec3 {
|
||||
x: f64::from(hr.block_pos.x),
|
||||
y: f64::from(hr.block_pos.y),
|
||||
z: f64::from(hr.block_pos.z),
|
||||
},
|
||||
)?;
|
||||
result.set("inside", hr.inside)?;
|
||||
result.set("world_border", hr.world_border)?;
|
||||
Some(result)
|
||||
})
|
||||
}
|
||||
|
||||
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 pathfinder(lua: &Lua, client: &Client) -> Result<Table> {
|
||||
let client = client.inner.as_ref().unwrap();
|
||||
let pathfinder = lua.create_table()?;
|
||||
pathfinder.set(
|
||||
"is_calculating",
|
||||
client.component::<Pathfinder>().is_calculating,
|
||||
)?;
|
||||
pathfinder.set(
|
||||
"is_executing",
|
||||
if let Some(p) = client.get_component::<ExecutingPath>() {
|
||||
pathfinder.set(
|
||||
"last_reached_node",
|
||||
Vec3 {
|
||||
x: f64::from(p.last_reached_node.x),
|
||||
y: f64::from(p.last_reached_node.y),
|
||||
z: f64::from(p.last_reached_node.z),
|
||||
},
|
||||
)?;
|
||||
pathfinder.set(
|
||||
"last_node_reach_elapsed",
|
||||
p.last_node_reached_at.elapsed().as_millis(),
|
||||
)?;
|
||||
pathfinder.set("is_path_partial", p.is_path_partial)?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
},
|
||||
)?;
|
||||
Ok(pathfinder)
|
||||
}
|
||||
|
||||
pub fn position(_lua: &Lua, client: &Client) -> Result<Vec3> {
|
||||
let p = client.inner.as_ref().unwrap().position();
|
||||
Ok(Vec3 {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
z: p.z,
|
||||
})
|
||||
}
|
||||
|
||||
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 stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> {
|
||||
client.inner.as_ref().unwrap().stop_pathfinding();
|
||||
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(())
|
||||
}
|
44
src/lua/client/state.rs
Normal file
44
src/lua/client/state.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use super::{Client, Hunger};
|
||||
use azalea::{
|
||||
ClientInformation,
|
||||
entity::metadata::{AirSupply, Score},
|
||||
};
|
||||
use mlua::{Lua, Result, Table, UserDataRef};
|
||||
|
||||
pub fn air_supply(_lua: &Lua, client: &Client) -> Result<i32> {
|
||||
Ok(client.inner.as_ref().unwrap().component::<AirSupply>().0)
|
||||
}
|
||||
|
||||
pub fn health(_lua: &Lua, client: &Client) -> Result<f32> {
|
||||
Ok(client.inner.as_ref().unwrap().health())
|
||||
}
|
||||
|
||||
pub fn hunger(_lua: &Lua, client: &Client) -> Result<Hunger> {
|
||||
let h = client.inner.as_ref().unwrap().hunger();
|
||||
Ok(Hunger {
|
||||
food: h.food,
|
||||
saturation: h.saturation,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn score(_lua: &Lua, client: &Client) -> Result<i32> {
|
||||
Ok(client.inner.as_ref().unwrap().component::<Score>().0)
|
||||
}
|
||||
|
||||
pub async fn set_client_information(
|
||||
_lua: Lua,
|
||||
client: UserDataRef<Client>,
|
||||
client_information: Table,
|
||||
) -> Result<()> {
|
||||
client
|
||||
.inner
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.set_client_information(ClientInformation {
|
||||
view_distance: client_information.get("view_distance")?,
|
||||
..ClientInformation::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
132
src/lua/client/world.rs
Normal file
132
src/lua/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,
|
||||
}))
|
||||
}
|
33
src/lua/direction.rs
Normal file
33
src/lua/direction.rs
Normal file
@@ -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<Value> {
|
||||
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<Self> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
43
src/lua/entity.rs
Normal file
43
src/lua/entity.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use super::vec3::Vec3;
|
||||
use mlua::{FromLua, IntoLua, Lua, Result, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Entity {
|
||||
pub id: u32,
|
||||
pub uuid: String,
|
||||
pub kind: String,
|
||||
pub position: Vec3,
|
||||
pub custom_name: Option<String>,
|
||||
}
|
||||
|
||||
impl IntoLua for Entity {
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
let entity = lua.create_table()?;
|
||||
entity.set("id", self.id)?;
|
||||
entity.set("uuid", self.uuid)?;
|
||||
entity.set("kind", self.kind)?;
|
||||
entity.set("position", self.position)?;
|
||||
entity.set("custom_name", self.custom_name)?;
|
||||
Ok(Value::Table(entity))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Entity {
|
||||
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
Ok(Self {
|
||||
id: table.get("id")?,
|
||||
uuid: table.get("uuid")?,
|
||||
kind: table.get("kind")?,
|
||||
position: table.get("position")?,
|
||||
custom_name: table.get("custom_name")?,
|
||||
})
|
||||
} else {
|
||||
Err(mlua::Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Position".to_string(),
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
36
src/lua/fluid_state.rs
Normal file
36
src/lua/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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
33
src/lua/hunger.rs
Normal file
33
src/lua/hunger.rs
Normal file
@@ -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<Value> {
|
||||
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<Self> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
42
src/lua/logging.rs
Normal file
42
src/lua/logging.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use mlua::{Lua, Result, Table};
|
||||
|
||||
pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> {
|
||||
globals.set(
|
||||
"error",
|
||||
lua.create_function(|_, message: String| {
|
||||
error!("{message}");
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
globals.set(
|
||||
"warn",
|
||||
lua.create_function(|_, message: String| {
|
||||
warn!("{message}");
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
globals.set(
|
||||
"info",
|
||||
lua.create_function(|_, message: String| {
|
||||
info!("{message}");
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
globals.set(
|
||||
"debug",
|
||||
lua.create_function(|_, message: String| {
|
||||
debug!("{message}");
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
globals.set(
|
||||
"trace",
|
||||
lua.create_function(|_, message: String| {
|
||||
trace!("{message}");
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
56
src/lua/mod.rs
Normal file
56
src/lua/mod.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
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;
|
||||
|
||||
use mlua::{Lua, Table};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Error {
|
||||
EvalChunk(mlua::Error),
|
||||
ExecChunk(mlua::Error),
|
||||
LoadChunk(mlua::Error),
|
||||
MissingPath(mlua::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(
|
||||
lua.globals()
|
||||
.get::<String>("script_path")
|
||||
.map_err(Error::MissingPath)?,
|
||||
)
|
||||
.map_err(Error::ReadFile)?,
|
||||
)
|
||||
.exec()
|
||||
.map_err(Error::LoadChunk)
|
||||
}
|
||||
|
||||
pub async fn eval(lua: &Lua, code: &str) -> Result<String, Error> {
|
||||
lua.load(code)
|
||||
.eval_async::<String>()
|
||||
.await
|
||||
.map_err(Error::EvalChunk)
|
||||
}
|
||||
|
||||
pub async fn exec(lua: &Lua, code: &str) -> Result<(), Error> {
|
||||
lua.load(code).exec_async().await.map_err(Error::ExecChunk)
|
||||
}
|
36
src/lua/vec3.rs
Normal file
36
src/lua/vec3.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use mlua::{FromLua, IntoLua, Lua, Result, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vec3 {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
}
|
||||
|
||||
impl IntoLua for Vec3 {
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
let table = lua.create_table()?;
|
||||
table.set("x", self.x)?;
|
||||
table.set("y", self.y)?;
|
||||
table.set("z", self.z)?;
|
||||
Ok(Value::Table(table))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Vec3 {
|
||||
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
Ok(Self {
|
||||
x: table.get("x")?,
|
||||
y: table.get("y")?,
|
||||
z: table.get("z")?,
|
||||
})
|
||||
} else {
|
||||
Err(mlua::Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Position".to_string(),
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user