use std::os::raw::c_void;
use yog_abi::{YogBytes, YogReply, YogStatus, status};
use yog_event::{Event, Message, Service, client, keyed, log, player, server};
use super::{Handler, ROUTER};
use yog_abi::priority::{FIRST, LAST};
unsafe extern "C" fn run<E: Event>(
ud: *mut c_void,
payload: YogBytes,
_reply: *const YogReply,
) -> YogStatus {
let f: fn(&E) = unsafe { std::mem::transmute::<*mut c_void, fn(&E)>(ud) };
match E::from_bytes(unsafe { payload.as_slice() }) {
Some(e) => {
crate::jni::util::guard(std::any::type_name::<E>(), || f(&e));
status::OK
}
None => status::BAD_PAYLOAD,
}
}
unsafe extern "C" fn serve<S: Service>(
ud: *mut c_void,
payload: YogBytes,
reply: *const YogReply,
) -> YogStatus {
let f: fn(&S) -> S::Reply =
unsafe { std::mem::transmute::<*mut c_void, fn(&S) -> S::Reply>(ud) };
let Some(request) = S::from_bytes(unsafe { payload.as_slice() }) else {
return status::BAD_PAYLOAD;
};
let mut answer = None;
crate::jni::util::guard(std::any::type_name::<S>(), || answer = Some(f(&request)));
match answer {
Some(a) => {
unsafe { YogReply::send(reply, &a.to_bytes()) };
status::OK
}
None => status::FAILED,
}
}
pub(crate) fn provide<S: Service>(f: fn(&S) -> S::Reply) {
let at = ROUTER.resolve(S::ADDRESS);
ROUTER.provide(
at,
Handler::Native {
owner: None,
ud: f as usize,
f: serve::<S>,
},
);
}
unsafe extern "C" fn run_change<E: Event>(
ud: *mut c_void,
payload: YogBytes,
reply: *const YogReply,
) -> YogStatus {
let f: fn(&mut E) = unsafe { std::mem::transmute::<*mut c_void, fn(&mut E)>(ud) };
let Some(mut e) = E::from_bytes(unsafe { payload.as_slice() }) else {
return status::BAD_PAYLOAD;
};
crate::jni::util::guard(std::any::type_name::<E>(), || f(&mut e));
unsafe { YogReply::send(reply, &e.to_bytes()) };
status::OK
}
fn change<E: Event>(priority: i32, f: fn(&mut E)) {
subscribe(E::ADDRESS, priority, f as usize, run_change::<E>);
}
fn after<E: Event>(priority: i32, f: fn(&E)) {
listen(E::ADDRESS, priority, f);
}
fn listen<E: Event>(address: &str, priority: i32, f: fn(&E)) {
subscribe(address, priority, f as usize, run::<E>);
}
fn subscribe(address: &str, priority: i32, ud: usize, run: yog_abi::YogHandlerFn) {
let at = ROUTER.resolve(address);
ROUTER.on(
at,
priority,
Handler::Native {
owner: None,
ud,
f: run,
},
);
}
pub(crate) fn register() {
after::<server::life::Started>(FIRST, |_| {
crate::mods::handlers::handlers()
.pending_grants
.lock()
.clear()
});
after::<player::session::Join>(LAST, |e| {
crate::game::ticks::queue_startup_grants(&e.player_name, &e.uuid)
});
after::<server::game::Tick>(LAST, |_| {
crate::game::ticks::after_tick();
crate::game::mirrors::after_tick(yog_mirror::Clock::Server);
});
after::<client::game::Tick>(LAST, |_| {
crate::game::mirrors::after_tick(yog_mirror::Clock::Client);
crate::video::ambient::sweep();
});
after::<server::life::Stopping>(LAST, |_| crate::game::entity_data::server_stopped());
super::declared::register();
super::describe::register();
super::own::register();
crate::game::entity_data::register();
crate::game::mirrors::register();
change::<client::render::Camera>(FIRST, |c| c.out = yog_body::CameraOut::default());
change::<client::render::Body>(FIRST, |b| {
crate::game::entity_data::fill_frame(&mut b.frame)
});
change::<client::render::Body>(LAST, |b| {
crate::video::ambient::body_textures(&mut b.ops.draws)
});
after::<log::Record>(LAST, |r| {
crate::logging::host_log(yog_logging::Level::from_u32(r.level), &r.message)
});
listen::<client::net::Packet>(
&keyed(
client::net::Packet::ADDRESS,
crate::game::entity_data::ENTITY_DATA,
),
FIRST,
|p| crate::game::entity_data::receive(&p.payload),
);
}