diff --git a/USAGE.md b/USAGE.md index 375b899..5450ee3 100644 --- a/USAGE.md +++ b/USAGE.md @@ -111,7 +111,8 @@ These special debug commands start with `!` and are custom to Kawari. * `!unlockaction `: Unlock an action, for example: `1` for Return and `4` for Teleport. * `!equip `: Forcefully equip an item, useful for bypassing class/job and other client restrictions. This will *overwrite* any item in that slot! * `!nudge `: Teleport forward, back, up or down `distance` yalms. Specifying up or down will move the player up or down instead of forward or back. Examples: `!nudge 5 up` to move up 5 yalms, `!nudge 5` to move forward 5 yalms, `!nudge -5` to move backward 5 yalms. -*`!festival `: Sets the festival in the current zone. Multiple festivals can be set together to create interesting effects. +* `!festival `: Sets the festival in the current zone. Multiple festivals can be set together to create interesting effects. +* `!reload`: Reloads `Global.lua` that is normally only loaded once at start-up. ### GM commands diff --git a/resources/scripts/Global.lua b/resources/scripts/Global.lua index d909c5f..bf88e81 100644 --- a/resources/scripts/Global.lua +++ b/resources/scripts/Global.lua @@ -81,3 +81,4 @@ registerCommand("setspeed", "commands/debug/SetSpeed.lua") registerCommand("nudge", "commands/debug/Nudge.lua") registerCommand("festival", "commands/debug/Festival.lua") registerCommand("permtest", "commands/debug/PermissionTest.lua") +registerCommand("reload", "commands/debug/Reload.lua") diff --git a/resources/scripts/commands/debug/Reload.lua b/resources/scripts/commands/debug/Reload.lua new file mode 100644 index 0000000..6c69111 --- /dev/null +++ b/resources/scripts/commands/debug/Reload.lua @@ -0,0 +1,6 @@ +required_rank = GM_RANK_DEBUG + +function onCommand(args, player) + player:reload_scripts() + player:send_message("Scripts reloaded!") +end diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 531f5d8..f5c1aa3 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -20,10 +20,10 @@ use kawari::packet::oodle::OodleNetwork; use kawari::packet::{ ConnectionType, PacketSegment, PacketState, SegmentData, SegmentType, send_keep_alive, }; -use kawari::world::{ChatHandler, ExtraLuaState, Zone, ZoneConnection}; +use kawari::world::{ChatHandler, ExtraLuaState, Zone, ZoneConnection, load_global_script}; use kawari::world::{ - ClientHandle, EffectsBuilder, Event, FromServer, LuaPlayer, PlayerData, ServerHandle, - StatusEffects, ToServer, WorldDatabase, handle_custom_ipc, server_main_loop, + ClientHandle, Event, FromServer, LuaPlayer, PlayerData, ServerHandle, StatusEffects, ToServer, + WorldDatabase, handle_custom_ipc, server_main_loop, }; use mlua::{Function, Lua}; @@ -888,58 +888,8 @@ async fn main() { let game_data = Arc::new(Mutex::new(GameData::new())); { - let lua = lua.lock().unwrap(); - - let register_action_func = lua - .create_function(|lua, (action_id, action_script): (u32, String)| { - tracing::info!("Registering {action_id} with {action_script}!"); - let mut state = lua.app_data_mut::().unwrap(); - let _ = state.action_scripts.insert(action_id, action_script); - Ok(()) - }) - .unwrap(); - - let register_event_func = lua - .create_function(|lua, (event_id, event_script): (u32, String)| { - tracing::info!("Registering {event_id} with {event_script}!"); - let mut state = lua.app_data_mut::().unwrap(); - let _ = state.event_scripts.insert(event_id, event_script); - Ok(()) - }) - .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::().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) - .unwrap(); - 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())) - .unwrap(); - lua.globals() - .set("EffectsBuilder", effectsbuilder_constructor) - .unwrap(); - - let file_name = format!("{}/Global.lua", &config.world.scripts_location); - lua.load(std::fs::read(&file_name).expect("Failed to locate scripts directory!")) - .set_name("@".to_string() + &file_name) - .exec() - .unwrap(); + let mut lua = lua.lock().unwrap(); + load_global_script(&mut lua); } let (handle, _) = spawn_main_loop(); diff --git a/src/world/connection.rs b/src/world/connection.rs index d9e4efa..a2dfee6 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -34,6 +34,7 @@ use super::{ Actor, CharacterData, EffectsBuilder, Event, LuaPlayer, StatusEffects, ToServer, WorldDatabase, Zone, common::{ClientId, ServerHandle}, + load_global_script, lua::Task, }; @@ -591,6 +592,10 @@ impl ZoneConnection { Task::WarpAetheryte { aetheryte_id } => { self.warp_aetheryte(*aetheryte_id).await; } + Task::ReloadScripts => { + let mut lua = self.lua.lock().unwrap(); + load_global_script(&mut lua); + } } } player.queued_tasks.clear(); diff --git a/src/world/lua.rs b/src/world/lua.rs index f4ddad8..32af325 100644 --- a/src/world/lua.rs +++ b/src/world/lua.rs @@ -5,12 +5,14 @@ use crate::{ ObjectId, ObjectTypeId, Position, timestamp_secs, workdefinitions::RemakeMode, write_quantized_rotation, }, + config::get_config, ipc::zone::{ ActionEffect, ActorControlCategory, ActorControlSelf, DamageElement, DamageKind, DamageType, EffectKind, EventScene, ServerZoneIpcData, ServerZoneIpcSegment, Warp, }, opcodes::ServerZoneIpcType, packet::{PacketSegment, SegmentData, SegmentType}, + world::ExtraLuaState, }; use super::{PlayerData, StatusEffects, Zone, connection::TeleportQuery}; @@ -23,6 +25,7 @@ pub enum Task { FinishEvent { handler_id: u32 }, SetClassJob { classjob_id: u8 }, WarpAetheryte { aetheryte_id: u32 }, + ReloadScripts, } #[derive(Default)] @@ -156,6 +159,10 @@ impl LuaPlayer { fn warp_aetheryte(&mut self, aetheryte_id: u32) { self.queued_tasks.push(Task::WarpAetheryte { aetheryte_id }); } + + fn reload_scripts(&mut self) { + self.queued_tasks.push(Task::ReloadScripts); + } } impl UserData for LuaPlayer { @@ -223,6 +230,10 @@ impl UserData for LuaPlayer { this.warp_aetheryte(aetheryte_id); Ok(()) }); + methods.add_method_mut("reload_scripts", |_, this, _: ()| { + this.reload_scripts(); + Ok(()) + }); } fn add_fields>(fields: &mut F) { @@ -324,3 +335,58 @@ impl FromLua for EffectsBuilder { } } } + +/// Loads `Global.lua` +pub fn load_global_script(lua: &mut Lua) { + let register_action_func = lua + .create_function(|lua, (action_id, action_script): (u32, String)| { + tracing::info!("Registering {action_id} with {action_script}!"); + let mut state = lua.app_data_mut::().unwrap(); + let _ = state.action_scripts.insert(action_id, action_script); + Ok(()) + }) + .unwrap(); + + let register_event_func = lua + .create_function(|lua, (event_id, event_script): (u32, String)| { + tracing::info!("Registering {event_id} with {event_script}!"); + let mut state = lua.app_data_mut::().unwrap(); + let _ = state.event_scripts.insert(event_id, event_script); + Ok(()) + }) + .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::().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) + .unwrap(); + 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())) + .unwrap(); + lua.globals() + .set("EffectsBuilder", effectsbuilder_constructor) + .unwrap(); + + let config = get_config(); + let file_name = format!("{}/Global.lua", &config.world.scripts_location); + lua.load(std::fs::read(&file_name).expect("Failed to locate scripts directory!")) + .set_name("@".to_string() + &file_name) + .exec() + .unwrap(); +} diff --git a/src/world/mod.rs b/src/world/mod.rs index 485121c..9f723d6 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -11,7 +11,7 @@ mod database; pub use database::{CharacterData, WorldDatabase}; mod lua; -pub use lua::{EffectsBuilder, LuaPlayer}; +pub use lua::{EffectsBuilder, LuaPlayer, load_global_script}; mod event; pub use event::Event;