1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-12 14:47:46 +00:00

Add Lua API for commands

This is super simple, you get the player and the args (which you can
choose to split if you so choose.) I reimplemented the !setpos, and will
start doing the rest of the commands.
This commit is contained in:
Joshua Goins 2025-05-06 21:57:52 -04:00
parent 5b35896365
commit 4c17f28eb0
6 changed files with 91 additions and 30 deletions

View file

@ -3,6 +3,19 @@ function onBeginLogin(player)
player:send_message("Welcome to Kawari!")
end
function split(input, separator)
if separator == nil then
separator = '%s'
end
local t = {}
for str in string.gmatch(input, '([^'..separator..']+)') do
table.insert(t, str)
end
return t
end
-- please keep these ids sorted!
-- Actions
@ -28,3 +41,6 @@ registerEvent(1245186, "opening/OpeningGridania.lua")
registerEvent(1245187, "opening/OpeningUldah.lua")
-- TODO: Generic warps might be decided through ArrayEventHandler?
-- Commands
registerCommand("setpos", "commands/debug/SetPos.lua")

View file

@ -0,0 +1,4 @@
function onCommand(args, player)
local parts = split(args)
player:set_position({ x = tonumber(parts[1]), y = tonumber(parts[2]), z = tonumber(parts[3]) })
end

View file

@ -38,6 +38,7 @@ use tokio::task::JoinHandle;
struct ExtraLuaState {
action_scripts: HashMap<u32, String>,
event_scripts: HashMap<u32, String>,
command_scripts: HashMap<String, String>,
}
fn spawn_main_loop() -> (ServerHandle, JoinHandle<()>) {
@ -478,12 +479,60 @@ async fn client_loop(
ClientZoneIpcData::ChatMessage(chat_message) => {
connection.handle.send(ToServer::Message(connection.id, chat_message.message.clone())).await;
ChatHandler::handle_chat_message(
&mut connection,
&mut lua_player,
chat_message,
)
.await
let mut handled = false;
{
let parts: Vec<&str> = chat_message.message.split(' ').collect();
let command_name = &parts[0][1..];
let lua = lua.lock().unwrap();
let state = lua.app_data_ref::<ExtraLuaState>().unwrap();
if let Some(command_script) =
state.command_scripts.get(command_name)
{
handled = true;
lua.scope(|scope| {
let connection_data = scope
.create_userdata_ref_mut(&mut lua_player)
.unwrap();
let config = get_config();
let file_name = format!(
"{}/{}",
&config.world.scripts_location, command_script
);
lua.load(
std::fs::read(&file_name)
.expect("Failed to locate scripts directory!"),
)
.set_name("@".to_string() + &file_name)
.exec()
.unwrap();
let func: Function =
lua.globals().get("onCommand").unwrap();
tracing::info!("{}", &chat_message.message[command_name.len() + 2..]);
func.call::<()>((&chat_message.message[command_name.len() + 2..], connection_data))
.unwrap();
Ok(())
})
.unwrap();
}
}
if !handled {
ChatHandler::handle_chat_message(
&mut connection,
&mut lua_player,
chat_message,
)
.await;
}
}
ClientZoneIpcData::GMCommand { command, arg0, .. } => {
tracing::info!("Got a game master command!");
@ -866,6 +915,15 @@ async fn main() {
})
.unwrap();
let register_command_func = lua
.create_function(|lua, (command_name, command_script): (String, String)| {
tracing::info!("Registering {command_name} with {command_script}!");
let mut state = lua.app_data_mut::<ExtraLuaState>().unwrap();
let _ = state.command_scripts.insert(command_name, command_script);
Ok(())
})
.unwrap();
lua.set_app_data(ExtraLuaState::default());
lua.globals()
.set("registerAction", register_action_func)
@ -873,6 +931,9 @@ async fn main() {
lua.globals()
.set("registerEvent", register_event_func)
.unwrap();
lua.globals()
.set("registerCommand", register_command_func)
.unwrap();
let effectsbuilder_constructor = lua
.create_function(|_, ()| Ok(EffectsBuilder::default()))

View file

@ -1,7 +1,8 @@
use binrw::binrw;
use serde::{Deserialize, Serialize};
#[binrw]
#[derive(Debug, Clone, Copy, Default)]
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
pub struct Position {
pub x: f32,
pub y: f32,

View file

@ -54,19 +54,6 @@ impl ChatHandler {
let parts: Vec<&str> = chat_message.message.split(' ').collect();
match parts[0] {
"!setpos" => {
let pos_x = parts[1].parse::<f32>().unwrap();
let pos_y = parts[2].parse::<f32>().unwrap();
let pos_z = parts[3].parse::<f32>().unwrap();
connection
.set_player_position(Position {
x: pos_x,
y: pos_y,
z: pos_z,
})
.await;
}
"!spawnplayer" => {
let config = get_config();

View file

@ -146,7 +146,8 @@ impl UserData for LuaPlayer {
Ok(())
},
);
methods.add_method_mut("set_position", |_, this, position: Position| {
methods.add_method_mut("set_position", |lua, this, position: Value| {
let position: Position = lua.from_value(position).unwrap();
this.set_position(position);
Ok(())
});
@ -185,15 +186,6 @@ impl UserData for LuaPlayer {
impl UserData for Position {}
impl FromLua for Position {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
match value {
Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
_ => unreachable!(),
}
}
}
impl UserData for ObjectTypeId {}
impl FromLua for ObjectTypeId {