diff --git a/Cargo.lock b/Cargo.lock index b6166e1..1521e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,7 +199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -266,6 +266,7 @@ dependencies = [ "futures-task", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -549,7 +550,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -560,6 +561,7 @@ checksum = "d3f763c1041eff92ffb5d7169968a327e1ed2ebfe425dac0ee5a35f29082534b" dependencies = [ "bstr", "either", + "futures-util", "mlua-sys", "num-traits", "parking_lot", @@ -599,9 +601,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "c2806eaa3524762875e21c3dcd057bc4b7bfa01ce4da8d46be1cd43649e1cc6b" [[package]] name = "parking_lot" @@ -635,7 +637,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "physis" version = "0.4.0" -source = "git+https://github.com/redstrate/physis#020480e82c5537bdcd15ab3b9826f409d9e77e1a" +source = "git+https://github.com/redstrate/physis#eee7d5867fb7424592ff1249f28c90dbe1daec13" dependencies = [ "binrw", "bitflags 1.3.2", @@ -770,7 +772,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -873,6 +875,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.14.0" @@ -886,7 +897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -940,7 +951,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1065,6 +1076,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index 27cf252..aa2a52e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,4 +86,4 @@ rusqlite = { version = "0.34", features = ["bundled"], default-features = false bitflags = { version = "1.3", default-features = false } # For server-side scripting -mlua = { version = "0.10", features = ["lua51", "vendored", "send"] } +mlua = { version = "0.10", features = ["lua51", "vendored", "send", "async"] } diff --git a/build.rs b/build.rs index 0ef1c05..6b0af84 100644 --- a/build.rs +++ b/build.rs @@ -11,6 +11,8 @@ fn main() { let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); d.push("resources/opcodes.json"); + println!("cargo::rerun-if-changed={}", d.to_str().unwrap()); + let mut output_str = "use binrw::binrw;\n".to_string(); let opcodes_buffer = std::fs::read_to_string(d).unwrap(); diff --git a/resources/opcodes.json b/resources/opcodes.json index 520a6dc..c2121b7 100644 --- a/resources/opcodes.json +++ b/resources/opcodes.json @@ -52,7 +52,7 @@ }, { "name": "ServerChatMessage", - "opcode": 406, + "opcode": 837, "size": 776 }, { diff --git a/resources/scripts/test.lua b/resources/scripts/test.lua index 21f3e33..213a2cf 100644 --- a/resources/scripts/test.lua +++ b/resources/scripts/test.lua @@ -1,3 +1,4 @@ function onBeginLogin(player) - print("Player " .. player.content_id .. " is connecting!") + -- send a welcome message + player:send_message("Welcome to Kawari!") end diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 35ebd48..c1fa1b3 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -23,8 +23,8 @@ use kawari::world::{ SocialList, }, }; -use kawari::world::{PlayerData, WorldDatabase}; -use mlua::{Function, Lua}; +use kawari::world::{LuaPlayer, PlayerData, WorldDatabase}; +use mlua::{AnyUserData, Function, Lua}; use physis::common::{Language, Platform}; use physis::gamedata::GameData; use tokio::io::AsyncReadExt; @@ -47,12 +47,11 @@ async fn main() { { let lua = lua.lock().unwrap(); - lua.load( - std::fs::read(format!("{}/test.lua", &config.world.scripts_location)) - .expect("Failed to locate scripts directory!"), - ) - .exec() - .unwrap(); + let file_name = format!("{}/test.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(); } loop { @@ -79,6 +78,8 @@ async fn main() { inventory: Inventory::new(), }; + let mut lua_player = LuaPlayer::default(); + tokio::spawn(async move { let mut buf = [0; 2056]; loop { @@ -98,6 +99,7 @@ async fn main() { // collect actor data connection.player_data = database.find_player_data(actor_id.parse::().unwrap()); + lua_player.player_data = connection.player_data; // We have send THEM a keep alive { @@ -309,37 +311,16 @@ async fn main() { connection.change_zone(zone_id).await; - // send welcome message - { - let ipc = ServerZoneIpcSegment { - op_code: ServerZoneIpcType::ServerChatMessage, - timestamp: timestamp_secs(), - data: ServerZoneIpcData::ServerChatMessage { - message: "Welcome to Kawari!".to_string(), - unk: 0, - }, - ..Default::default() - }; - - connection - .send_segment(PacketSegment { - source_actor: connection.player_data.actor_id, - target_actor: connection.player_data.actor_id, - segment_type: SegmentType::Ipc { data: ipc }, - }) - .await; - } - let lua = lua.lock().unwrap(); lua.scope(|scope| { - let player_data = scope - .create_userdata_ref(&connection.player_data) + let connection_data = scope + .create_userdata_ref_mut(&mut lua_player) .unwrap(); let func: Function = lua.globals().get("onBeginLogin").unwrap(); - func.call::<()>(player_data).unwrap(); + func.call::<()>(connection_data).unwrap(); Ok(()) }) @@ -976,6 +957,8 @@ async fn main() { } } } + + connection.process_lua_player(&mut lua_player).await; } } }); diff --git a/src/world/connection.rs b/src/world/connection.rs index 5dc8ceb..1046fee 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -1,4 +1,4 @@ -use mlua::{UserData, UserDataFields}; +use mlua::{UserData, UserDataFields, UserDataMethods}; use tokio::net::TcpStream; use crate::{ @@ -18,7 +18,7 @@ use super::{ }, }; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone, Copy)] pub struct PlayerData { pub actor_id: u32, pub content_id: u64, @@ -243,4 +243,69 @@ impl ZoneConnection { .await; } } + + pub async fn send_message(&mut self, message: &str) { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::ServerChatMessage, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::ServerChatMessage { + message: message.to_string(), + unk: 0, + }, + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: self.player_data.actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc { data: ipc }, + }) + .await; + } + + pub async fn process_lua_player(&mut self, player: &mut LuaPlayer) { + for segment in &player.queued_segments { + self.send_segment(segment.clone()).await; + } + player.queued_segments.clear(); + } +} + +#[derive(Default)] +pub struct LuaPlayer { + pub player_data: PlayerData, + queued_segments: Vec>, +} + +impl LuaPlayer { + fn queue_segment(&mut self, segment: PacketSegment) { + self.queued_segments.push(segment); + } + + fn send_message(&mut self, message: &str) { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::ServerChatMessage, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::ServerChatMessage { + message: message.to_string(), + unk: 0, + }, + ..Default::default() + }; + + self.queue_segment(PacketSegment { + source_actor: self.player_data.actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc { data: ipc }, + }); + } +} + +impl UserData for LuaPlayer { + fn add_methods>(methods: &mut M) { + methods.add_method_mut("send_message", |_, this, message: String| { + this.send_message(&message); + Ok(()) + }); + } } diff --git a/src/world/mod.rs b/src/world/mod.rs index 321e7e1..ca3e0f0 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -7,7 +7,7 @@ mod chat_handler; pub use chat_handler::ChatHandler; mod connection; -pub use connection::{PlayerData, ZoneConnection}; +pub use connection::{LuaPlayer, PlayerData, ZoneConnection}; mod database; pub use database::{CharacterData, WorldDatabase};