cancellable vehicle spawns

This commit is contained in:
Luuk van Oijen 2023-11-28 19:22:03 +01:00
parent adfda5a8cb
commit 452a4c5e16
3 changed files with 134 additions and 10 deletions

View File

@ -136,6 +136,7 @@ pub struct Server {
connect_runtime_handle: JoinHandle<()>,
chat_queue: Vec<(u8, String, String, Option<oneshot::Receiver<Argument>>, usize)>,
veh_spawn_queue: Vec<(RawPacket, u8, u8, String, Vec<oneshot::Receiver<Argument>>, Vec<Argument>)>,
config: Arc<Config>,
@ -307,8 +308,8 @@ impl Server {
debug!("Client acception runtime started!");
Ok(Self {
tcp_listener: tcp_listener,
udp_socket: udp_socket,
tcp_listener,
udp_socket,
clients_incoming_rx,
clients_queue: Vec::new(),
@ -318,6 +319,7 @@ impl Server {
connect_runtime_handle: connect_runtime_handle,
chat_queue: Vec::new(),
veh_spawn_queue: Vec::new(),
config: config,
@ -455,8 +457,7 @@ impl Server {
Ok(())
}
// TODO: I don't think this can return an error lol
async fn process_chat_messages(&mut self) -> anyhow::Result<()> {
async fn process_chat_messages(&mut self) {
let mut new_queue = Vec::new();
let mut to_send = Vec::new();
for (pid, pname, mut message, resp, mut next_plugin_id) in self.chat_queue.drain(..) {
@ -503,8 +504,70 @@ impl Server {
for packet in to_send {
self.broadcast(Packet::Raw(packet), None).await;
}
}
Ok(())
async fn process_veh_spawns(&mut self) {
let mut new_queue = Vec::new();
let mut to_send = Vec::new();
for (packet, pid, vid, car_json, mut receivers, mut results) in self.veh_spawn_queue.drain(..) {
let mut new_receivers = Vec::new();
for mut receiver in receivers.drain(..) {
match receiver.try_recv() {
Ok(arg) => results.push(arg),
Err(oneshot::error::TryRecvError::Empty) => new_receivers.push(receiver),
Err(_) => error!("Failed to receive response from a plugin!"),
}
}
if new_receivers.len() > 0 {
new_queue.push((packet, pid, vid, car_json, new_receivers, results));
} else {
let mut allowed = true;
for arg in results {
match arg {
Argument::Integer(i) => if i == 1 { allowed = false; },
Argument::Number(f) => if f == 1f32 { allowed = false; },
Argument::Boolean(b) => if b == true { allowed = false; },
_ => {},
}
}
if allowed {
to_send.push((packet, pid));
} else {
if let Some(client_idx) = self.clients.iter().enumerate().find(|(i, client)| client.id == pid).map(|(i, _)| i) {
let packet_data = format!(
"Os:{}:{}:{}-{}:{}",
self.clients[client_idx].get_roles(),
self.clients[client_idx].get_name(),
pid,
vid,
car_json.clone(),
);
let response = RawPacket::from_str(&packet_data);
self.clients[client_idx].write_packet(Packet::Raw(response)).await;
let packet_data = format!(
"Od:{}-{}",
pid,
vid,
);
let response = RawPacket::from_str(&packet_data);
self.clients[client_idx].write_packet(Packet::Raw(response)).await;
self.clients[client_idx].unregister_car(vid);
info!("Blocked spawn for client #{}!", pid);
} else {
error!("Could not find client with pid {pid}!");
}
}
}
}
for (packet, pid) in to_send {
self.broadcast(Packet::Raw(packet), None).await;
info!("Spawned car for client #{}!", pid);
}
self.veh_spawn_queue = new_queue;
}
async fn process_lua_events(&mut self) -> anyhow::Result<()> {
@ -540,6 +603,15 @@ impl Server {
}
},
ServerBoundPluginEvent::RequestPlayerVehicles((pid, responder)) => {
if let Some(client) = self.clients.iter().find(|client| client.id == pid) {
let vehicles = client.cars.iter().map(|(id, car)| (*id, car.car_json.clone())).collect();
let _ = responder.send(PluginBoundPluginEvent::PlayerVehicles(vehicles));
} else {
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;
@ -555,7 +627,8 @@ impl Server {
pub async fn process(&mut self) -> anyhow::Result<()> {
self.process_authenticated_clients().await?;
self.process_chat_messages().await?;
self.process_chat_messages().await;
self.process_veh_spawns().await;
self.process_lua_events().await?;
// I'm sorry for this code :(
@ -989,8 +1062,25 @@ impl Server {
car_json_str
);
let response = RawPacket::from_str(&packet_data);
self.broadcast(Packet::Raw(response), None).await;
info!("Spawned car for client #{}!", client_id);
// self.broadcast(Packet::Raw(response), None).await;
// info!("Spawned car for client #{}!", client_id);
let mut receivers = Vec::new();
for plugin in &self.plugins {
let (tx, rx) = oneshot::channel();
plugin.send_event(PluginBoundPluginEvent::CallEventHandler((
ScriptEvent::OnVehicleSpawn { pid: client_id, vid: car_id, car_data: car_json_str.to_string() },
Some(tx),
))).await;
receivers.push(rx);
}
self.veh_spawn_queue.push((
response,
client_id,
car_id,
car_json_str.to_string(),
receivers,
Vec::new(),
));
} else {
let packet_data = format!(
"Os:{}:{}:{}-{}:{}",

View File

@ -81,7 +81,6 @@ impl UserData for Context {
error!("Failed to send packet: {:?}", e);
}
let message = rx.blocking_recv();
trace!("received player info");
if let Ok(message) = message {
if let PluginBoundPluginEvent::Players(players) = message {
let table = lua.create_table()?;
@ -126,7 +125,6 @@ impl UserData for Context {
error!("Failed to send packet: {:?}", e);
}
let message = rx.blocking_recv();
trace!("received player info");
if let Ok(message) = message {
if let PluginBoundPluginEvent::Players(players) = message {
let mut name = None;
@ -145,6 +143,28 @@ impl UserData for Context {
}
});
methods.add_function("GetPlayerVehicles", |lua, (id,): (u8,)| {
let me: Context = lua.globals().get("MP")?;
let (tx, rx) = oneshot::channel();
if let Err(e) = me.tx.blocking_send(ServerBoundPluginEvent::RequestPlayerVehicles((id, tx))) {
error!("Failed to send packet: {:?}", e);
}
let message = rx.blocking_recv();
if let Ok(message) = message {
if let PluginBoundPluginEvent::PlayerVehicles(vehicles) = message {
let table = lua.create_table()?;
for (vid, veh_json) in vehicles {
table.set(vid, veh_json)?;
}
Ok(table)
} else {
unreachable!() // This really should 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))) {
@ -201,6 +221,10 @@ impl Backend for BackendLua {
ScriptEvent::OnPlayerDisconnect { pid, name } => ("onPlayerDisconnect", vec![Argument::Integer(pid as i64), Argument::String(name)]),
ScriptEvent::OnVehicleSpawn { pid, vid, car_data } => ("onVehicleSpawn", vec![Argument::Integer(pid as i64), Argument::Integer(vid as i64), Argument::String(car_data)]),
ScriptEvent::OnVehicleEdited { pid, vid, car_data } => ("onVehicleEdited", vec![Argument::Integer(pid as i64), Argument::Integer(vid as i64), Argument::String(car_data)]),
ScriptEvent::OnVehicleDeleted { pid, vid } => ("onVehicleDeleted", vec![Argument::Integer(pid as i64), Argument::Integer(vid as i64)]),
ScriptEvent::OnChatMessage { pid, name, message } => ("onChatMessage", vec![Argument::Integer(pid as i64), Argument::String(name), Argument::String(message)]),
};

View File

@ -59,6 +59,10 @@ pub enum ScriptEvent {
OnPlayerDisconnect { pid: u8, name: String },
OnVehicleSpawn { pid: u8, vid: u8, car_data: String },
OnVehicleEdited { pid: u8, vid: u8, car_data: String },
OnVehicleDeleted { pid: u8, vid: u8 },
OnChatMessage { pid: u8, name: String, message: String },
}
@ -71,8 +75,12 @@ pub enum PluginBoundPluginEvent {
PlayerCount(usize),
Players(HashMap<u8, String>),
PlayerIdentifiers(PlayerIdentifiers),
PlayerVehicles(HashMap<u8, String>),
}
// TODO: Perhaps it would be nice to ensure each sender can only sned specifically what it needs to.
// Purely to ensure type safety and slightly cleaner code on the backend implementation side.
#[derive(Debug)]
pub enum ServerBoundPluginEvent {
PluginLoaded,
@ -81,6 +89,8 @@ pub enum ServerBoundPluginEvent {
RequestPlayers(oneshot::Sender<PluginBoundPluginEvent>),
RequestPlayerIdentifiers((u8, oneshot::Sender<PluginBoundPluginEvent>)),
RequestPlayerVehicles((u8, oneshot::Sender<PluginBoundPluginEvent>)),
SendChatMessage((isize, String)),
}