1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-06-30 11:47:45 +00:00

Allow reloading Global.lua with the new !reload debug command

Scripts are normally loaded when they are needed, with the exception of
Global.lua that's only loaded once at start-up. But now you can reload
it in-game with the !reload command, which should make event and command
scripting way less of a hassle.
This commit is contained in:
Joshua Goins 2025-06-21 12:16:27 -04:00
parent 0c967f8a56
commit f07d16b949
7 changed files with 86 additions and 57 deletions

View file

@ -111,7 +111,8 @@ These special debug commands start with `!` and are custom to Kawari.
* `!unlockaction <id>`: Unlock an action, for example: `1` for Return and `4` for Teleport. * `!unlockaction <id>`: Unlock an action, for example: `1` for Return and `4` for Teleport.
* `!equip <name>`: Forcefully equip an item, useful for bypassing class/job and other client restrictions. This will *overwrite* any item in that slot! * `!equip <name>`: Forcefully equip an item, useful for bypassing class/job and other client restrictions. This will *overwrite* any item in that slot!
* `!nudge <distance> <up/down (optional)>`: 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. * `!nudge <distance> <up/down (optional)>`: 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 <id1> <id2> <id3> <id4>`: Sets the festival in the current zone. Multiple festivals can be set together to create interesting effects. * `!festival <id1> <id2> <id3> <id4>`: 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 ### GM commands

View file

@ -81,3 +81,4 @@ registerCommand("setspeed", "commands/debug/SetSpeed.lua")
registerCommand("nudge", "commands/debug/Nudge.lua") registerCommand("nudge", "commands/debug/Nudge.lua")
registerCommand("festival", "commands/debug/Festival.lua") registerCommand("festival", "commands/debug/Festival.lua")
registerCommand("permtest", "commands/debug/PermissionTest.lua") registerCommand("permtest", "commands/debug/PermissionTest.lua")
registerCommand("reload", "commands/debug/Reload.lua")

View file

@ -0,0 +1,6 @@
required_rank = GM_RANK_DEBUG
function onCommand(args, player)
player:reload_scripts()
player:send_message("Scripts reloaded!")
end

View file

@ -20,10 +20,10 @@ use kawari::packet::oodle::OodleNetwork;
use kawari::packet::{ use kawari::packet::{
ConnectionType, PacketSegment, PacketState, SegmentData, SegmentType, send_keep_alive, 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::{ use kawari::world::{
ClientHandle, EffectsBuilder, Event, FromServer, LuaPlayer, PlayerData, ServerHandle, ClientHandle, Event, FromServer, LuaPlayer, PlayerData, ServerHandle, StatusEffects, ToServer,
StatusEffects, ToServer, WorldDatabase, handle_custom_ipc, server_main_loop, WorldDatabase, handle_custom_ipc, server_main_loop,
}; };
use mlua::{Function, Lua}; use mlua::{Function, Lua};
@ -888,58 +888,8 @@ async fn main() {
let game_data = Arc::new(Mutex::new(GameData::new())); let game_data = Arc::new(Mutex::new(GameData::new()));
{ {
let lua = lua.lock().unwrap(); let mut lua = lua.lock().unwrap();
load_global_script(&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::<ExtraLuaState>().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::<ExtraLuaState>().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::<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)
.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 (handle, _) = spawn_main_loop(); let (handle, _) = spawn_main_loop();

View file

@ -34,6 +34,7 @@ use super::{
Actor, CharacterData, EffectsBuilder, Event, LuaPlayer, StatusEffects, ToServer, WorldDatabase, Actor, CharacterData, EffectsBuilder, Event, LuaPlayer, StatusEffects, ToServer, WorldDatabase,
Zone, Zone,
common::{ClientId, ServerHandle}, common::{ClientId, ServerHandle},
load_global_script,
lua::Task, lua::Task,
}; };
@ -591,6 +592,10 @@ impl ZoneConnection {
Task::WarpAetheryte { aetheryte_id } => { Task::WarpAetheryte { aetheryte_id } => {
self.warp_aetheryte(*aetheryte_id).await; self.warp_aetheryte(*aetheryte_id).await;
} }
Task::ReloadScripts => {
let mut lua = self.lua.lock().unwrap();
load_global_script(&mut lua);
}
} }
} }
player.queued_tasks.clear(); player.queued_tasks.clear();

View file

@ -5,12 +5,14 @@ use crate::{
ObjectId, ObjectTypeId, Position, timestamp_secs, workdefinitions::RemakeMode, ObjectId, ObjectTypeId, Position, timestamp_secs, workdefinitions::RemakeMode,
write_quantized_rotation, write_quantized_rotation,
}, },
config::get_config,
ipc::zone::{ ipc::zone::{
ActionEffect, ActorControlCategory, ActorControlSelf, DamageElement, DamageKind, ActionEffect, ActorControlCategory, ActorControlSelf, DamageElement, DamageKind,
DamageType, EffectKind, EventScene, ServerZoneIpcData, ServerZoneIpcSegment, Warp, DamageType, EffectKind, EventScene, ServerZoneIpcData, ServerZoneIpcSegment, Warp,
}, },
opcodes::ServerZoneIpcType, opcodes::ServerZoneIpcType,
packet::{PacketSegment, SegmentData, SegmentType}, packet::{PacketSegment, SegmentData, SegmentType},
world::ExtraLuaState,
}; };
use super::{PlayerData, StatusEffects, Zone, connection::TeleportQuery}; use super::{PlayerData, StatusEffects, Zone, connection::TeleportQuery};
@ -23,6 +25,7 @@ pub enum Task {
FinishEvent { handler_id: u32 }, FinishEvent { handler_id: u32 },
SetClassJob { classjob_id: u8 }, SetClassJob { classjob_id: u8 },
WarpAetheryte { aetheryte_id: u32 }, WarpAetheryte { aetheryte_id: u32 },
ReloadScripts,
} }
#[derive(Default)] #[derive(Default)]
@ -156,6 +159,10 @@ impl LuaPlayer {
fn warp_aetheryte(&mut self, aetheryte_id: u32) { fn warp_aetheryte(&mut self, aetheryte_id: u32) {
self.queued_tasks.push(Task::WarpAetheryte { aetheryte_id }); self.queued_tasks.push(Task::WarpAetheryte { aetheryte_id });
} }
fn reload_scripts(&mut self) {
self.queued_tasks.push(Task::ReloadScripts);
}
} }
impl UserData for LuaPlayer { impl UserData for LuaPlayer {
@ -223,6 +230,10 @@ impl UserData for LuaPlayer {
this.warp_aetheryte(aetheryte_id); this.warp_aetheryte(aetheryte_id);
Ok(()) Ok(())
}); });
methods.add_method_mut("reload_scripts", |_, this, _: ()| {
this.reload_scripts();
Ok(())
});
} }
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: UserDataFields<Self>>(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::<ExtraLuaState>().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::<ExtraLuaState>().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::<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)
.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();
}

View file

@ -11,7 +11,7 @@ mod database;
pub use database::{CharacterData, WorldDatabase}; pub use database::{CharacterData, WorldDatabase};
mod lua; mod lua;
pub use lua::{EffectsBuilder, LuaPlayer}; pub use lua::{EffectsBuilder, LuaPlayer, load_global_script};
mod event; mod event;
pub use event::Event; pub use event::Event;