diff --git a/Resources/Server/TestPlugin/main.lua b/Resources/Server/TestPlugin/main.lua index fdee842..b07198e 100644 --- a/Resources/Server/TestPlugin/main.lua +++ b/Resources/Server/TestPlugin/main.lua @@ -40,6 +40,8 @@ function onPlayerDisconnect(pid, name, identifiers) end function onChatMessage(pid, name, message) + MP.SendChatMessage(-1, "i hate this " .. name .. " guy!") + MP.SendChatMessage(pid, "hiii babe i didnt mean it :3") print("" .. name .. " (" .. pid .. "): " .. message) return message .. " (edited by lua!!!)" end diff --git a/TODO.md b/TODO.md deleted file mode 100644 index c31bf7b..0000000 --- a/TODO.md +++ /dev/null @@ -1,4 +0,0 @@ -# Todo List -- Redo the entire download process. Currently it is very very clunky, and the implementation is terrible. It essentially acts as a second client and it would be much better if this was either implemented as part of the original client (server-sided client), or if the entire download flow was redone both client and server side. -- Implement the Lua API (and discuss wanted changes). -- Implement the auth-key stuff to have public servers be possible. diff --git a/src/config.rs b/src/config.rs index 29cab79..5cc430d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,11 +41,12 @@ pub struct GeneralSettings { #[serde(rename = "ResourceFolder")] pub resource_folder: String, + #[serde(rename = "Debug")] + pub debug: bool, + // Options below are not yet supported #[serde(rename = "LogChat")] pub log_chat: bool, - #[serde(rename = "Debug")] - pub debug: bool, } impl GeneralSettings { diff --git a/src/main.rs b/src/main.rs index 6534d4e..a979d90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,21 +27,20 @@ struct Args { async fn main() { let args: Args = argh::from_env(); - if !args.disable_tui { - logger::init(log::LevelFilter::max()).expect("Failed to enable logger!"); - } else { - // pretty_env_logger::formatted_timed_builder().filter_level(log::LevelFilter::max()).init(); - pretty_env_logger::formatted_timed_builder().filter_level(log::LevelFilter::Debug).init(); - } - let mut user_config: config::Config = toml::from_str( &std::fs::read_to_string("ServerConfig.toml") .map_err(|_| error!("Failed to read config file!")) .expect("Failed to read config file!") ) - .map_err(|_| error!("Failed to parse config file!")) + .map_err(|_| eprintln!("Failed to parse config file!")) .expect("Failed to parse config file!"); + let level_filter = if user_config.general.debug { log::LevelFilter::max() } else { log::LevelFilter::Info }; + if !args.disable_tui { + logger::init(level_filter).expect("Failed to enable logger!"); + } else { + pretty_env_logger::formatted_timed_builder().filter_level(level_filter).init(); + } let client_resources = user_config.general .get_client_resource_folder() diff --git a/src/server/mod.rs b/src/server/mod.rs index 2fd7267..716f218 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -507,12 +507,15 @@ impl Server { async fn process_lua_events(&mut self) -> anyhow::Result<()> { // Receive plugin events and process them - for plugin in &mut self.plugins { - for event in plugin.get_events() { + // TODO: Any methods called in this for loop cannot modify the list of plugins. + // If any plugin disappears during this call, it will panic trying to index out of bounds! + for i in 0..self.plugins.len() { + for event in self.plugins[i].get_events() { debug!("event: {:?}", event); // TODO: Error handling (?) match event { - ServerBoundPluginEvent::PluginLoaded => plugin.send_event(PluginBoundPluginEvent::CallEventHandler((ScriptEvent::OnPluginLoaded, None))).await, + ServerBoundPluginEvent::PluginLoaded => self.plugins[i].send_event(PluginBoundPluginEvent::CallEventHandler((ScriptEvent::OnPluginLoaded, None))).await, + ServerBoundPluginEvent::RequestPlayerCount(responder) => { let _ = responder.send(PluginBoundPluginEvent::PlayerCount(self.clients.len() + self.clients_queue.len())); }, ServerBoundPluginEvent::RequestPlayers(responder) => { trace!("request players received"); @@ -534,6 +537,12 @@ impl Server { let _ = responder.send(PluginBoundPluginEvent::None); } }, + + ServerBoundPluginEvent::SendChatMessage((pid, msg)) => { + let pid = if pid >= 0 { Some(pid as u8) } else { None }; + self.send_chat_message(&msg, pid).await; + }, + _ => {}, } } @@ -609,12 +618,17 @@ impl Server { } pub async fn send_chat_message(&self, message: &str, target: Option) { - let packet = Packet::Raw(RawPacket::from_str(&format!("C:Server: {message}"))); - if let Some(_id) = target { - // TODO: Implement this! - todo!("Sending server chat messages to specific player is not supported yet!"); - // info!("[CHAT] Server @ {id}: {message}"); + if let Some(id) = target { + let packet = Packet::Raw(RawPacket::from_str(&format!("C:Server @ {id}: {message}"))); + info!("[CHAT] Server @ {id}: {message}"); + for client in &self.clients { + if id == client.id { + client.queue_packet(packet).await; + break; + } + } } else { + let packet = Packet::Raw(RawPacket::from_str(&format!("C:Server: {message}"))); info!("[CHAT] Server: {message}"); self.broadcast(packet, None).await; } diff --git a/src/server/plugins/backend_lua.rs b/src/server/plugins/backend_lua.rs index 82f70bf..d13e0ab 100644 --- a/src/server/plugins/backend_lua.rs +++ b/src/server/plugins/backend_lua.rs @@ -53,7 +53,7 @@ impl UserData for Context { }); methods.add_function("GetServerVersion", |_lua, ()| { - Ok((1, 0, 0)) + Ok((3, 3, 0)) }); methods.add_function("GetPlayerCount", |lua, ()| { @@ -96,6 +96,35 @@ impl UserData for Context { todo!("Receiving a response from the server failed! How?") } }); + + methods.add_function("GetPlayerIdentifiers", |lua, (id,): (u8,)| { + let me: Context = lua.globals().get("MP")?; + let (tx, rx) = oneshot::channel(); + if let Err(e) = me.tx.blocking_send(ServerBoundPluginEvent::RequestPlayerIdentifiers((id, tx))) { + error!("Failed to send packet: {:?}", e); + } + let message = rx.blocking_recv(); + if let Ok(message) = message { + if let PluginBoundPluginEvent::PlayerIdentifiers(identifiers) = message { + let table = lua.create_table()?; + table.set("id", identifiers.ip)?; + table.set("beammp_id", identifiers.beammp_id)?; + Ok(table) + } else { + unreachable!() // This should really never be reachable + } + } else { + todo!("Receiving a response from the server failed! How?") + } + }); + + methods.add_function("SendChatMessage", |lua, (id, msg): (isize, String)| { + let me: Context = lua.globals().get("MP")?; + if let Err(e) = me.tx.blocking_send(ServerBoundPluginEvent::SendChatMessage((id, msg))) { + error!("Failed to send packet: {:?}", e); + } + Ok(()) + }); } } diff --git a/src/server/plugins/mod.rs b/src/server/plugins/mod.rs index 70a29d3..8ebb114 100644 --- a/src/server/plugins/mod.rs +++ b/src/server/plugins/mod.rs @@ -72,6 +72,8 @@ pub enum ServerBoundPluginEvent { RequestPlayerCount(oneshot::Sender), RequestPlayers(oneshot::Sender), RequestPlayerIdentifiers((u8, oneshot::Sender)), + + SendChatMessage((isize, String)), } pub struct Plugin {