#[cfg(test)]
#[path = "../tests/net/events.rs"]
mod tests;
use crate::interfaces::game_event::GameEvent;
use crate::interfaces::game_server::GameClient;
use crate::net::incoming::HookTargetError;
use crate::server::{Server, ServerBinding};
use sdk_raw::net::events as raw;
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::ptr::NonNull;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Delivery {
#[default]
Deliver,
Withhold,
}
pub fn hook_target(
server: Server<'_>,
) -> Result<NonNull<sys::IGameEventListener2>, HookTargetError> {
let client = server
.valve_engine()?
.game_server()
.ok_or(HookTargetError::NoServer)?
.client(0)
.ok_or(HookTargetError::NotReady)?;
let client = NonNull::new(client.as_ptr()).ok_or(HookTargetError::NotReady)?;
Ok(unsafe { raw::listener_of_client(client) }?)
}
pub unsafe fn route_event(
binding: &ServerBinding,
this: NonNull<sys::IGameEventListener2>,
event: NonNull<sys::IGameEvent>,
callback: impl for<'s> FnOnce(Server<'s>, GameClient<'s>, GameEvent<'s>) -> Delivery,
) -> Delivery {
let Some(client) = (unsafe { raw::client_of_listener(this) }) else {
return Delivery::Deliver;
};
let scope = ();
let server = unsafe { binding.server(&scope) };
let client = unsafe { GameClient::from_raw(client) };
let event = unsafe { GameEvent::from_raw(event) };
catch_unwind(AssertUnwindSafe(|| callback(server, client, event))).unwrap_or(Delivery::Deliver)
}