Compare commits
No commits in common. "d633820d198ebec34c92f37a4f4ff53ac8cec454" and "168ac1bb46bf0201352f1fbb248a274af4646b4a" have entirely different histories.
d633820d19
...
168ac1bb46
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1184,7 +1184,6 @@ dependencies = [
|
|||||||
"bevy_log",
|
"bevy_log",
|
||||||
"clap",
|
"clap",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-locks",
|
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
@ -1318,17 +1317,6 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-locks"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-task",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
@ -21,7 +21,6 @@ bevy_app = "0"
|
|||||||
bevy_log = "0"
|
bevy_log = "0"
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
futures = "0"
|
futures = "0"
|
||||||
futures-locks = "0"
|
|
||||||
http-body-util = "0"
|
http-body-util = "0"
|
||||||
hyper = { version = "1", features = ["server"] }
|
hyper = { version = "1", features = ["server"] }
|
||||||
hyper-util = "0"
|
hyper-util = "0"
|
||||||
|
@ -14,17 +14,17 @@ function log_player_positions()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_listener("init", function()
|
function on_init()
|
||||||
info("client initialized, setting information...")
|
info("client initialized, setting information...")
|
||||||
client:set_client_information({ view_distance = 16 })
|
client:set_client_information({ view_distance = 16 })
|
||||||
end)
|
|
||||||
|
|
||||||
add_listener("login", function()
|
add_listener("login", function()
|
||||||
info("player successfully logged in!")
|
info("player successfully logged in!")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
add_listener("death", function()
|
add_listener("death", function()
|
||||||
warn(string.format("player died at %.1f %.1f %.1f!", client.position.x, client.position.y, client.position.z))
|
warn(string.format("player died at %.1f %.1f %.1f!", client.position.x, client.position.y, client.position.z))
|
||||||
end, "warn_player_died")
|
end, "warn_player_died")
|
||||||
|
|
||||||
add_listener("tick", log_player_positions)
|
add_listener("tick", log_player_positions)
|
||||||
|
end
|
||||||
|
@ -17,7 +17,7 @@ function steal(item_name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
container = nil
|
container = nil
|
||||||
while client.container do
|
while client.open_container do
|
||||||
sleep(50)
|
sleep(50)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,17 +4,20 @@ use crate::{
|
|||||||
State,
|
State,
|
||||||
commands::CommandSource,
|
commands::CommandSource,
|
||||||
http::serve,
|
http::serve,
|
||||||
lua::{self, player::Player},
|
lua::{self, events::register_functions, player::Player},
|
||||||
};
|
};
|
||||||
use azalea::{prelude::*, protocol::packets::game::ClientboundGamePacket};
|
use azalea::{prelude::*, protocol::packets::game::ClientboundGamePacket};
|
||||||
use hyper::{server::conn::http1, service::service_fn};
|
use hyper::{server::conn::http1, service::service_fn};
|
||||||
use hyper_util::rt::TokioIo;
|
use hyper_util::rt::TokioIo;
|
||||||
use log::{debug, error, info, trace};
|
use log::{debug, error, info, trace};
|
||||||
use mlua::IntoLuaMulti;
|
use mlua::{Function, IntoLuaMulti};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> {
|
pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> {
|
||||||
|
state.lua.gc_stop();
|
||||||
|
let globals = state.lua.globals();
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::AddPlayer(player_info) => {
|
Event::AddPlayer(player_info) => {
|
||||||
call_listeners(&state, "add_player", Player::from(player_info)).await;
|
call_listeners(&state, "add_player", Player::from(player_info)).await;
|
||||||
@ -23,7 +26,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
|
|||||||
let formatted_message = message.message();
|
let formatted_message = message.message();
|
||||||
info!("{}", formatted_message.to_ansi());
|
info!("{}", formatted_message.to_ansi());
|
||||||
|
|
||||||
let owners = state.lua.globals().get::<Vec<String>>("Owners")?;
|
let owners = globals.get::<Vec<String>>("Owners")?;
|
||||||
if message.is_whisper()
|
if message.is_whisper()
|
||||||
&& let (Some(sender), content) = message.split_sender_and_content()
|
&& let (Some(sender), content) = message.split_sender_and_content()
|
||||||
&& owners.contains(&sender)
|
&& owners.contains(&sender)
|
||||||
@ -66,62 +69,56 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
|
|||||||
Event::UpdatePlayer(player_info) => {
|
Event::UpdatePlayer(player_info) => {
|
||||||
call_listeners(&state, "update_player", Player::from(player_info)).await;
|
call_listeners(&state, "update_player", Player::from(player_info)).await;
|
||||||
}
|
}
|
||||||
Event::Packet(packet) => match packet.as_ref() {
|
Event::Packet(packet) => {
|
||||||
ClientboundGamePacket::SetPassengers(packet) => {
|
if let ClientboundGamePacket::SetPassengers(packet) = packet.as_ref() {
|
||||||
let table = state.lua.create_table()?;
|
let table = state.lua.create_table()?;
|
||||||
table.set("vehicle", packet.vehicle)?;
|
table.set("vehicle", packet.vehicle)?;
|
||||||
table.set("passengers", &*packet.passengers)?;
|
table.set("passengers", &*packet.passengers)?;
|
||||||
call_listeners(&state, "set_passengers", table).await;
|
call_listeners(&state, "set_passengers", table).await;
|
||||||
}
|
}
|
||||||
ClientboundGamePacket::SetHealth(packet) => {
|
}
|
||||||
let table = state.lua.create_table()?;
|
|
||||||
table.set("food", packet.food)?;
|
|
||||||
table.set("health", packet.health)?;
|
|
||||||
table.set("saturation", packet.saturation)?;
|
|
||||||
call_listeners(&state, "set_health", table).await;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
Event::Init => {
|
Event::Init => {
|
||||||
debug!("received initialize event");
|
debug!("client initialized");
|
||||||
|
|
||||||
let globals = state.lua.globals();
|
|
||||||
globals.set(
|
globals.set(
|
||||||
"client",
|
"client",
|
||||||
lua::client::Client {
|
lua::client::Client {
|
||||||
inner: Some(client),
|
inner: Some(client),
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
call_listeners(&state, "init", ()).await;
|
register_functions(&state.lua, &globals, state.clone()).await?;
|
||||||
|
if let Ok(on_init) = globals.get::<Function>("on_init")
|
||||||
|
&& let Err(error) = on_init.call::<()>(())
|
||||||
|
{
|
||||||
|
error!("failed to call lua on_init function: {error:?}");
|
||||||
|
}
|
||||||
|
|
||||||
let Some(address) = state.http_address else {
|
if let Some(address) = state.http_address {
|
||||||
return Ok(());
|
let listener = TcpListener::bind(address).await.map_err(|error| {
|
||||||
};
|
error!("failed to listen on {address}: {error:?}");
|
||||||
|
error
|
||||||
|
})?;
|
||||||
|
debug!("http server listening on {address}");
|
||||||
|
|
||||||
let listener = TcpListener::bind(address).await.map_err(|error| {
|
loop {
|
||||||
error!("failed to listen on {address}: {error:?}");
|
let (stream, peer) = listener.accept().await?;
|
||||||
error
|
trace!("http server got connection from {peer}");
|
||||||
})?;
|
|
||||||
debug!("http server listening on {address}");
|
|
||||||
|
|
||||||
loop {
|
let conn_state = state.clone();
|
||||||
let (stream, peer) = listener.accept().await?;
|
let service = service_fn(move |request| {
|
||||||
trace!("http server got connection from {peer}");
|
let request_state = conn_state.clone();
|
||||||
|
async move { serve(request, request_state).await }
|
||||||
|
});
|
||||||
|
|
||||||
let conn_state = state.clone();
|
tokio::spawn(async move {
|
||||||
let service = service_fn(move |request| {
|
if let Err(error) = http1::Builder::new()
|
||||||
let request_state = conn_state.clone();
|
.serve_connection(TokioIo::new(stream), service)
|
||||||
async move { serve(request, request_state).await }
|
.await
|
||||||
});
|
{
|
||||||
|
error!("failed to serve connection: {error:?}");
|
||||||
tokio::spawn(async move {
|
}
|
||||||
if let Err(error) = http1::Builder::new()
|
});
|
||||||
.serve_connection(TokioIo::new(stream), service)
|
}
|
||||||
.await
|
|
||||||
{
|
|
||||||
error!("failed to serve connection: {error:?}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -131,10 +128,10 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn call_listeners<T: Clone + IntoLuaMulti>(state: &State, event_type: &str, data: T) {
|
async fn call_listeners<T: Clone + IntoLuaMulti>(state: &State, event_type: &str, data: T) {
|
||||||
if let Some(listeners) = state.event_listeners.read().await.get(event_type) {
|
if let Some(listeners) = state.event_listeners.lock().await.get(event_type) {
|
||||||
for (id, callback) in listeners {
|
for (_, listener) in listeners {
|
||||||
if let Err(error) = callback.call_async::<()>(data.clone()).await {
|
if let Err(error) = listener.call_async::<()>(data.clone()).await {
|
||||||
error!("failed to call lua event listener {id} for {event_type}: {error:?}");
|
error!("failed to call lua event listener for {event_type}: {error:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
use super::{Client, Container, ContainerRef, ItemStack, Vec3};
|
use super::{Client, Container, ContainerRef, ItemStack, Vec3};
|
||||||
use azalea::{
|
use azalea::{
|
||||||
BlockPos,
|
BlockPos, inventory::Inventory, prelude::ContainerClientExt,
|
||||||
inventory::{Inventory, Menu, Player, SlotList},
|
|
||||||
prelude::ContainerClientExt,
|
|
||||||
protocol::packets::game::ServerboundSetCarriedItem,
|
protocol::packets::game::ServerboundSetCarriedItem,
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use mlua::{Lua, Result, Table, UserDataRef};
|
use mlua::{Lua, Result, UserDataRef};
|
||||||
|
|
||||||
pub fn container(_lua: &Lua, client: &Client) -> Result<Option<ContainerRef>> {
|
pub fn container(_lua: &Lua, client: &Client) -> Result<Option<ContainerRef>> {
|
||||||
Ok(client
|
Ok(client
|
||||||
@ -15,46 +13,15 @@ pub fn container(_lua: &Lua, client: &Client) -> Result<Option<ContainerRef>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn held_item(_lua: &Lua, client: &Client) -> Result<ItemStack> {
|
pub fn held_item(_lua: &Lua, client: &Client) -> Result<ItemStack> {
|
||||||
Ok(ItemStack::from(client.component::<Inventory>().held_item()))
|
Ok(ItemStack {
|
||||||
|
inner: client.component::<Inventory>().held_item(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn held_slot(_lua: &Lua, client: &Client) -> Result<u8> {
|
pub fn held_slot(_lua: &Lua, client: &Client) -> Result<u8> {
|
||||||
Ok(client.component::<Inventory>().selected_hotbar_slot)
|
Ok(client.component::<Inventory>().selected_hotbar_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn menu(lua: &Lua, client: &Client) -> Result<Table> {
|
|
||||||
fn from_slot_list<const N: usize>(s: SlotList<N>) -> Vec<ItemStack> {
|
|
||||||
s.iter()
|
|
||||||
.map(|i| ItemStack::from(i.to_owned()))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
let table = lua.create_table()?;
|
|
||||||
match client.menu() {
|
|
||||||
Menu::Player(Player {
|
|
||||||
craft_result,
|
|
||||||
craft,
|
|
||||||
armor,
|
|
||||||
inventory,
|
|
||||||
offhand,
|
|
||||||
}) => {
|
|
||||||
table.set("type", 0)?;
|
|
||||||
table.set("craft_result", ItemStack::from(craft_result))?;
|
|
||||||
table.set("craft", from_slot_list(craft))?;
|
|
||||||
table.set("armor", from_slot_list(armor))?;
|
|
||||||
table.set("inventory", from_slot_list(inventory))?;
|
|
||||||
table.set("offhand", ItemStack::from(offhand))?;
|
|
||||||
}
|
|
||||||
Menu::Generic9x6 { contents, player } => {
|
|
||||||
table.set("type", 6)?;
|
|
||||||
table.set("contents", from_slot_list(contents))?;
|
|
||||||
table.set("player", from_slot_list(player))?;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
Ok(table)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn open_container_at(
|
pub async fn open_container_at(
|
||||||
_lua: Lua,
|
_lua: Lua,
|
||||||
client: UserDataRef<Client>,
|
client: UserDataRef<Client>,
|
||||||
|
@ -49,7 +49,6 @@ impl UserData for Client {
|
|||||||
f.add_field_method_get("held_slot", container::held_slot);
|
f.add_field_method_get("held_slot", container::held_slot);
|
||||||
f.add_field_method_get("hunger", state::hunger);
|
f.add_field_method_get("hunger", state::hunger);
|
||||||
f.add_field_method_get("looking_at", movement::looking_at);
|
f.add_field_method_get("looking_at", movement::looking_at);
|
||||||
f.add_field_method_get("menu", container::menu);
|
|
||||||
f.add_field_method_get("pathfinder", movement::pathfinder);
|
f.add_field_method_get("pathfinder", movement::pathfinder);
|
||||||
f.add_field_method_get("position", movement::position);
|
f.add_field_method_get("position", movement::position);
|
||||||
f.add_field_method_get("score", state::score);
|
f.add_field_method_get("score", state::score);
|
||||||
|
@ -15,7 +15,7 @@ use mlua::{FromLua, Lua, Result, Table, UserDataRef, Value};
|
|||||||
|
|
||||||
pub fn direction(_lua: &Lua, client: &Client) -> Result<Direction> {
|
pub fn direction(_lua: &Lua, client: &Client) -> Result<Direction> {
|
||||||
let d = client.direction();
|
let d = client.direction();
|
||||||
Ok(Direction { y: d.0, x: d.1 })
|
Ok(Direction { x: d.0, y: d.1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eye_position(_lua: &Lua, client: &Client) -> Result<Vec3> {
|
pub fn eye_position(_lua: &Lua, client: &Client) -> Result<Vec3> {
|
||||||
|
@ -5,12 +5,6 @@ pub struct ItemStack {
|
|||||||
pub inner: azalea::inventory::ItemStack,
|
pub inner: azalea::inventory::ItemStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<azalea::inventory::ItemStack> for ItemStack {
|
|
||||||
fn from(inner: azalea::inventory::ItemStack) -> Self {
|
|
||||||
Self { inner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserData for ItemStack {
|
impl UserData for ItemStack {
|
||||||
fn add_fields<F: UserDataFields<Self>>(f: &mut F) {
|
fn add_fields<F: UserDataFields<Self>>(f: &mut F) {
|
||||||
f.add_field_method_get("is_empty", |_, this| Ok(this.inner.is_empty()));
|
f.add_field_method_get("is_empty", |_, this| Ok(this.inner.is_empty()));
|
||||||
@ -44,7 +38,9 @@ impl UserData for ItemStack {
|
|||||||
|
|
||||||
fn add_methods<M: UserDataMethods<Self>>(m: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(m: &mut M) {
|
||||||
m.add_method_mut("split", |_, this, count: u32| {
|
m.add_method_mut("split", |_, this, count: u32| {
|
||||||
Ok(ItemStack::from(this.inner.split(count)))
|
Ok(ItemStack {
|
||||||
|
inner: this.inner.split(count),
|
||||||
|
})
|
||||||
});
|
});
|
||||||
m.add_method_mut("update_empty", |_, this, (): ()| {
|
m.add_method_mut("update_empty", |_, this, (): ()| {
|
||||||
this.inner.update_empty();
|
this.inner.update_empty();
|
||||||
|
@ -25,7 +25,7 @@ impl UserData for Container {
|
|||||||
f.add_field_method_get("contents", |_, this| {
|
f.add_field_method_get("contents", |_, this| {
|
||||||
Ok(this.inner.contents().map(|v| {
|
Ok(this.inner.contents().map(|v| {
|
||||||
v.iter()
|
v.iter()
|
||||||
.map(|i| ItemStack::from(i.to_owned()))
|
.map(|i| ItemStack { inner: i.clone() })
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
@ -58,7 +58,7 @@ impl UserData for ContainerRef {
|
|||||||
f.add_field_method_get("contents", |_, this| {
|
f.add_field_method_get("contents", |_, this| {
|
||||||
Ok(this.inner.contents().map(|v| {
|
Ok(this.inner.contents().map(|v| {
|
||||||
v.iter()
|
v.iter()
|
||||||
.map(|i| ItemStack::from(i.to_owned()))
|
.map(|i| ItemStack { inner: i.clone() })
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
@ -3,15 +3,15 @@ use mlua::{FromLua, IntoLua, Lua, Result, Value};
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Direction {
|
pub struct Direction {
|
||||||
pub y: f32,
|
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&LookDirection> for Direction {
|
impl From<&LookDirection> for Direction {
|
||||||
fn from(d: &LookDirection) -> Self {
|
fn from(d: &LookDirection) -> Self {
|
||||||
Self {
|
Self {
|
||||||
y: d.y_rot,
|
|
||||||
x: d.x_rot,
|
x: d.x_rot,
|
||||||
|
y: d.y_rot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,8 +19,8 @@ impl From<&LookDirection> for Direction {
|
|||||||
impl IntoLua for Direction {
|
impl IntoLua for Direction {
|
||||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||||
let table = lua.create_table()?;
|
let table = lua.create_table()?;
|
||||||
table.set("y", self.y)?;
|
|
||||||
table.set("x", self.x)?;
|
table.set("x", self.x)?;
|
||||||
|
table.set("y", self.y)?;
|
||||||
Ok(Value::Table(table))
|
Ok(Value::Table(table))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,12 +28,12 @@ impl IntoLua for Direction {
|
|||||||
impl FromLua for Direction {
|
impl FromLua for Direction {
|
||||||
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
|
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
|
||||||
if let Value::Table(table) = value {
|
if let Value::Table(table) = value {
|
||||||
Ok(if let (Ok(y), Ok(x)) = (table.get(1), table.get(2)) {
|
Ok(if let (Ok(x), Ok(y)) = (table.get(1), table.get(2)) {
|
||||||
Self { y, x }
|
Self { x, y }
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
y: table.get("y")?,
|
|
||||||
x: table.get("x")?,
|
x: table.get("x")?,
|
||||||
|
y: table.get("y")?,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,53 +1,47 @@
|
|||||||
use crate::ListenerMap;
|
use crate::State;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use mlua::{Function, Lua, Result, Table};
|
use mlua::{Function, Lua, Result, Table};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
pub fn register_functions(lua: &Lua, globals: &Table, event_listeners: ListenerMap) -> Result<()> {
|
pub async fn register_functions(lua: &Lua, globals: &Table, state: State) -> Result<()> {
|
||||||
let m = event_listeners.clone();
|
let l = state.event_listeners.clone();
|
||||||
globals.set(
|
globals.set(
|
||||||
"add_listener",
|
"add_listener",
|
||||||
lua.create_function(
|
lua.create_function(
|
||||||
move |_, (event_type, callback, optional_id): (String, Function, Option<String>)| {
|
move |_, (event_type, callback, id): (String, Function, Option<String>)| {
|
||||||
let m = m.clone();
|
let mut l = block_on(l.lock());
|
||||||
let id = optional_id.unwrap_or_else(|| {
|
|
||||||
callback.info().name.unwrap_or(format!(
|
l.entry(event_type).or_default().push((
|
||||||
"anonymous @ {}",
|
id.unwrap_or(callback.info().name.unwrap_or(format!(
|
||||||
SystemTime::now()
|
"anonymous @ {}",
|
||||||
.duration_since(UNIX_EPOCH)
|
SystemTime::now()
|
||||||
.unwrap_or_default()
|
.duration_since(UNIX_EPOCH)
|
||||||
.as_millis()
|
.unwrap_or_default()
|
||||||
))
|
.as_millis()
|
||||||
});
|
))),
|
||||||
tokio::spawn(async move {
|
callback,
|
||||||
m.write()
|
));
|
||||||
.await
|
|
||||||
.entry(event_type)
|
|
||||||
.or_default()
|
|
||||||
.push((id, callback));
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)?,
|
)?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let m = event_listeners.clone();
|
let l = state.event_listeners.clone();
|
||||||
globals.set(
|
globals.set(
|
||||||
"remove_listener",
|
"remove_listener",
|
||||||
lua.create_function(move |_, (event_type, target_id): (String, String)| {
|
lua.create_function(move |_, (event_type, target_id): (String, String)| {
|
||||||
let m = m.clone();
|
let mut l = block_on(l.lock());
|
||||||
tokio::spawn(async move {
|
|
||||||
let mut m = m.write().await;
|
let empty = if let Some(listeners) = l.get_mut(&event_type) {
|
||||||
let empty = if let Some(listeners) = m.get_mut(&event_type) {
|
listeners.retain(|(id, _)| target_id != *id);
|
||||||
listeners.retain(|(id, _)| target_id != *id);
|
listeners.is_empty()
|
||||||
listeners.is_empty()
|
} else {
|
||||||
} else {
|
false
|
||||||
false
|
};
|
||||||
};
|
if empty {
|
||||||
if empty {
|
l.remove(&event_type);
|
||||||
m.remove(&event_type);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
@ -55,10 +49,10 @@ pub fn register_functions(lua: &Lua, globals: &Table, event_listeners: ListenerM
|
|||||||
globals.set(
|
globals.set(
|
||||||
"get_listeners",
|
"get_listeners",
|
||||||
lua.create_function(move |lua, (): ()| {
|
lua.create_function(move |lua, (): ()| {
|
||||||
let m = block_on(event_listeners.read());
|
let l = block_on(state.event_listeners.lock());
|
||||||
|
|
||||||
let listeners = lua.create_table()?;
|
let listeners = lua.create_table()?;
|
||||||
for (event_type, callbacks) in m.iter() {
|
for (event_type, callbacks) in l.iter() {
|
||||||
let type_listeners = lua.create_table()?;
|
let type_listeners = lua.create_table()?;
|
||||||
for (id, callback) in callbacks {
|
for (id, callback) in callbacks {
|
||||||
let listener = lua.create_table()?;
|
let listener = lua.create_table()?;
|
||||||
|
@ -8,9 +8,7 @@ pub mod player;
|
|||||||
pub mod system;
|
pub mod system;
|
||||||
pub mod vec3;
|
pub mod vec3;
|
||||||
|
|
||||||
use crate::ListenerMap;
|
|
||||||
use mlua::{Lua, Table};
|
use mlua::{Lua, Table};
|
||||||
use std::{io, time::Duration};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -20,24 +18,19 @@ pub enum Error {
|
|||||||
ExecChunk(mlua::Error),
|
ExecChunk(mlua::Error),
|
||||||
LoadChunk(mlua::Error),
|
LoadChunk(mlua::Error),
|
||||||
MissingPath(mlua::Error),
|
MissingPath(mlua::Error),
|
||||||
ReadFile(io::Error),
|
ReadFile(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_functions(
|
pub fn register_functions(lua: &Lua, globals: &Table) -> mlua::Result<()> {
|
||||||
lua: &Lua,
|
|
||||||
globals: &Table,
|
|
||||||
event_listeners: ListenerMap,
|
|
||||||
) -> mlua::Result<()> {
|
|
||||||
globals.set(
|
globals.set(
|
||||||
"sleep",
|
"sleep",
|
||||||
lua.create_async_function(async |_, duration: u64| {
|
lua.create_async_function(async |_, duration: u64| {
|
||||||
tokio::time::sleep(Duration::from_millis(duration)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(duration)).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
block::register_functions(lua, globals)?;
|
block::register_functions(lua, globals)?;
|
||||||
events::register_functions(lua, globals, event_listeners)?;
|
|
||||||
logging::register_functions(lua, globals)?;
|
logging::register_functions(lua, globals)?;
|
||||||
system::register_functions(lua, globals)
|
system::register_functions(lua, globals)
|
||||||
}
|
}
|
||||||
|
@ -48,12 +48,12 @@ pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> {
|
|||||||
.args(args.unwrap_or_default().iter())
|
.args(args.unwrap_or_default().iter())
|
||||||
.output()
|
.output()
|
||||||
{
|
{
|
||||||
Ok(output) => {
|
Ok(o) => {
|
||||||
let table = lua.create_table()?;
|
let output = lua.create_table()?;
|
||||||
table.set("status", output.status.code())?;
|
output.set("status", o.status.code())?;
|
||||||
table.set("stdout", lua.create_string(output.stdout)?)?;
|
output.set("stdout", o.stdout)?;
|
||||||
table.set("stderr", lua.create_string(output.stderr)?)?;
|
output.set("stderr", o.stderr)?;
|
||||||
Some(table)
|
Some(output)
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("failed to run system command: {error:?}");
|
error!("failed to run system command: {error:?}");
|
||||||
|
48
src/main.rs
48
src/main.rs
@ -16,8 +16,8 @@ use bevy_log::{
|
|||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use commands::{CommandSource, register};
|
use commands::{CommandSource, register};
|
||||||
|
use events::handle_event;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use futures_locks::RwLock;
|
|
||||||
use mlua::{Function, Lua};
|
use mlua::{Function, Lua};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -30,12 +30,12 @@ use std::{
|
|||||||
|
|
||||||
const DEFAULT_SCRIPT_PATH: &str = "errornowatcher.lua";
|
const DEFAULT_SCRIPT_PATH: &str = "errornowatcher.lua";
|
||||||
|
|
||||||
type ListenerMap = Arc<RwLock<HashMap<String, Vec<(String, Function)>>>>;
|
type ListenerMap = HashMap<String, Vec<(String, Function)>>;
|
||||||
|
|
||||||
#[derive(Default, Clone, Component)]
|
#[derive(Default, Clone, Component)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
lua: Lua,
|
lua: Lua,
|
||||||
event_listeners: ListenerMap,
|
event_listeners: Arc<Mutex<ListenerMap>>,
|
||||||
commands: Arc<CommandDispatcher<Mutex<CommandSource>>>,
|
commands: Arc<CommandDispatcher<Mutex<CommandSource>>>,
|
||||||
http_address: Option<SocketAddr>,
|
http_address: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
@ -43,14 +43,13 @@ pub struct State {
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
let args = arguments::Arguments::parse();
|
let args = arguments::Arguments::parse();
|
||||||
|
|
||||||
let script_path = args.script.unwrap_or(PathBuf::from(DEFAULT_SCRIPT_PATH));
|
let script_path = args.script.unwrap_or(PathBuf::from(DEFAULT_SCRIPT_PATH));
|
||||||
let event_listeners = Arc::new(RwLock::new(HashMap::new()));
|
|
||||||
|
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let globals = lua.globals();
|
let globals = lua.globals();
|
||||||
globals.set("script_path", &*script_path)?;
|
globals.set("script_path", &*script_path)?;
|
||||||
lua::register_functions(&lua, &globals, event_listeners.clone())?;
|
lua::register_functions(&lua, &globals)?;
|
||||||
|
|
||||||
lua.load(
|
lua.load(
|
||||||
read_to_string(script_path)
|
read_to_string(script_path)
|
||||||
.expect(&(DEFAULT_SCRIPT_PATH.to_owned() + " should be in current directory")),
|
.expect(&(DEFAULT_SCRIPT_PATH.to_owned() + " should be in current directory")),
|
||||||
@ -66,29 +65,28 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let mut commands = CommandDispatcher::new();
|
let mut commands = CommandDispatcher::new();
|
||||||
register(&mut commands);
|
register(&mut commands);
|
||||||
|
|
||||||
let log_plugin = LogPlugin {
|
|
||||||
custom_layer: |_| {
|
|
||||||
env::var("LOG_FILE").ok().map(|log_file| {
|
|
||||||
layer()
|
|
||||||
.with_writer(
|
|
||||||
OpenOptions::new()
|
|
||||||
.append(true)
|
|
||||||
.create(true)
|
|
||||||
.open(log_file)
|
|
||||||
.expect("log file should be accessible"),
|
|
||||||
)
|
|
||||||
.boxed()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let Err(error) = ClientBuilder::new_without_plugins()
|
let Err(error) = ClientBuilder::new_without_plugins()
|
||||||
.add_plugins(DefaultPlugins.set(log_plugin))
|
.add_plugins(DefaultPlugins.set(LogPlugin {
|
||||||
|
custom_layer: |_| {
|
||||||
|
env::var("LOG_FILE").ok().map(|log_file| {
|
||||||
|
layer()
|
||||||
|
.with_writer(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.create(true)
|
||||||
|
.open(log_file)
|
||||||
|
.expect("should have been able to open log file"),
|
||||||
|
)
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
.add_plugins(DefaultBotPlugins)
|
.add_plugins(DefaultBotPlugins)
|
||||||
.set_handler(events::handle_event)
|
.set_handler(handle_event)
|
||||||
.set_state(State {
|
.set_state(State {
|
||||||
lua,
|
lua,
|
||||||
event_listeners,
|
event_listeners: Arc::new(Mutex::new(HashMap::new())),
|
||||||
commands: Arc::new(commands),
|
commands: Arc::new(commands),
|
||||||
http_address: args.http_address,
|
http_address: args.http_address,
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user