mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-03 16:25: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<()>,
|
connect_runtime_handle: JoinHandle<()>,
|
||||||
|
|
||||||
chat_queue: Vec<(u8, String, String, Option<oneshot::Receiver<Argument>>, usize)>,
|
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>,
|
config: Arc<Config>,
|
||||||
|
|
||||||
@ -307,8 +308,8 @@ impl Server {
|
|||||||
debug!("Client acception runtime started!");
|
debug!("Client acception runtime started!");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tcp_listener: tcp_listener,
|
tcp_listener,
|
||||||
udp_socket: udp_socket,
|
udp_socket,
|
||||||
|
|
||||||
clients_incoming_rx,
|
clients_incoming_rx,
|
||||||
clients_queue: Vec::new(),
|
clients_queue: Vec::new(),
|
||||||
@ -318,6 +319,7 @@ impl Server {
|
|||||||
connect_runtime_handle: connect_runtime_handle,
|
connect_runtime_handle: connect_runtime_handle,
|
||||||
|
|
||||||
chat_queue: Vec::new(),
|
chat_queue: Vec::new(),
|
||||||
|
veh_spawn_queue: Vec::new(),
|
||||||
|
|
||||||
config: config,
|
config: config,
|
||||||
|
|
||||||
@ -455,8 +457,7 @@ impl Server {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: I don't think this can return an error lol
|
async fn process_chat_messages(&mut self) {
|
||||||
async fn process_chat_messages(&mut self) -> anyhow::Result<()> {
|
|
||||||
let mut new_queue = Vec::new();
|
let mut new_queue = Vec::new();
|
||||||
let mut to_send = Vec::new();
|
let mut to_send = Vec::new();
|
||||||
for (pid, pname, mut message, resp, mut next_plugin_id) in self.chat_queue.drain(..) {
|
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 {
|
for packet in to_send {
|
||||||
self.broadcast(Packet::Raw(packet), None).await;
|
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<()> {
|
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)) => {
|
ServerBoundPluginEvent::SendChatMessage((pid, msg)) => {
|
||||||
let pid = if pid >= 0 { Some(pid as u8) } else { None };
|
let pid = if pid >= 0 { Some(pid as u8) } else { None };
|
||||||
self.send_chat_message(&msg, pid).await;
|
self.send_chat_message(&msg, pid).await;
|
||||||
@ -555,7 +627,8 @@ impl Server {
|
|||||||
|
|
||||||
pub async fn process(&mut self) -> anyhow::Result<()> {
|
pub async fn process(&mut self) -> anyhow::Result<()> {
|
||||||
self.process_authenticated_clients().await?;
|
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?;
|
self.process_lua_events().await?;
|
||||||
|
|
||||||
// I'm sorry for this code :(
|
// I'm sorry for this code :(
|
||||||
@ -989,8 +1062,25 @@ impl Server {
|
|||||||
car_json_str
|
car_json_str
|
||||||
);
|
);
|
||||||
let response = RawPacket::from_str(&packet_data);
|
let response = RawPacket::from_str(&packet_data);
|
||||||
self.broadcast(Packet::Raw(response), None).await;
|
// self.broadcast(Packet::Raw(response), None).await;
|
||||||
info!("Spawned car for client #{}!", client_id);
|
// 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 {
|
} else {
|
||||||
let packet_data = format!(
|
let packet_data = format!(
|
||||||
"Os:{}:{}:{}-{}:{}",
|
"Os:{}:{}:{}-{}:{}",
|
||||||
|
@ -81,7 +81,6 @@ impl UserData for Context {
|
|||||||
error!("Failed to send packet: {:?}", e);
|
error!("Failed to send packet: {:?}", e);
|
||||||
}
|
}
|
||||||
let message = rx.blocking_recv();
|
let message = rx.blocking_recv();
|
||||||
trace!("received player info");
|
|
||||||
if let Ok(message) = message {
|
if let Ok(message) = message {
|
||||||
if let PluginBoundPluginEvent::Players(players) = message {
|
if let PluginBoundPluginEvent::Players(players) = message {
|
||||||
let table = lua.create_table()?;
|
let table = lua.create_table()?;
|
||||||
@ -126,7 +125,6 @@ impl UserData for Context {
|
|||||||
error!("Failed to send packet: {:?}", e);
|
error!("Failed to send packet: {:?}", e);
|
||||||
}
|
}
|
||||||
let message = rx.blocking_recv();
|
let message = rx.blocking_recv();
|
||||||
trace!("received player info");
|
|
||||||
if let Ok(message) = message {
|
if let Ok(message) = message {
|
||||||
if let PluginBoundPluginEvent::Players(players) = message {
|
if let PluginBoundPluginEvent::Players(players) = message {
|
||||||
let mut name = None;
|
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)| {
|
methods.add_function("SendChatMessage", |lua, (id, msg): (isize, String)| {
|
||||||
let me: Context = lua.globals().get("MP")?;
|
let me: Context = lua.globals().get("MP")?;
|
||||||
if let Err(e) = me.tx.blocking_send(ServerBoundPluginEvent::SendChatMessage((id, msg))) {
|
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::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)]),
|
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 },
|
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 },
|
OnChatMessage { pid: u8, name: String, message: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +75,12 @@ pub enum PluginBoundPluginEvent {
|
|||||||
PlayerCount(usize),
|
PlayerCount(usize),
|
||||||
Players(HashMap<u8, String>),
|
Players(HashMap<u8, String>),
|
||||||
PlayerIdentifiers(PlayerIdentifiers),
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum ServerBoundPluginEvent {
|
pub enum ServerBoundPluginEvent {
|
||||||
PluginLoaded,
|
PluginLoaded,
|
||||||
@ -81,6 +89,8 @@ pub enum ServerBoundPluginEvent {
|
|||||||
RequestPlayers(oneshot::Sender<PluginBoundPluginEvent>),
|
RequestPlayers(oneshot::Sender<PluginBoundPluginEvent>),
|
||||||
RequestPlayerIdentifiers((u8, oneshot::Sender<PluginBoundPluginEvent>)),
|
RequestPlayerIdentifiers((u8, oneshot::Sender<PluginBoundPluginEvent>)),
|
||||||
|
|
||||||
|
RequestPlayerVehicles((u8, oneshot::Sender<PluginBoundPluginEvent>)),
|
||||||
|
|
||||||
SendChatMessage((isize, String)),
|
SendChatMessage((isize, String)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user