mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-03 08:15:35 +00:00
cancellable vehicle spawns
This commit is contained in:
parent
adfda5a8cb
commit
452a4c5e16
@ -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:{}:{}:{}-{}:{}",
|
||||
|
@ -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)]),
|
||||
};
|
||||
|
||||
|
@ -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)),
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user