use yog_data::{Ref, Value};
use yog_event::nanite::{Call, Get, Release, Resolve, Set};
use yog_ids::{kind, nanite_ref};
use yog_sync::{Arc, OnceLock};
mod added;
mod inject;
mod java;
pub use added::Added;
pub use inject::{__declare, __yog_nanite_registry, __yog_nanites, Hook, InjectEntry};
pub use java::{Java, Reply};
#[doc(hidden)]
pub use inject::subscribe as __subscribe;
#[derive(Clone, Debug)]
pub enum Handle {
Object(Arc<Held>),
Entity(String),
}
#[derive(Debug)]
pub struct Held(u64);
impl Drop for Held {
fn drop(&mut self) {
crate::call(&Release {
objects: vec![self.0],
});
}
}
impl Handle {
pub fn entity(uuid: impl Into<String>) -> Handle {
Handle::Entity(uuid.into())
}
pub fn to_value(&self) -> Value {
match self {
Handle::Object(held) => Value::Ref(Ref::new(nanite_ref::OBJECT, held.0.to_string())),
Handle::Entity(uuid) => Value::Ref(Ref::new(kind::ENTITY, uuid.clone())),
}
}
pub fn from_value(v: Value) -> Option<Handle> {
let Value::Ref(r) = v else { return None };
match r.kind.as_str() {
nanite_ref::OBJECT => r.id.parse().ok().map(|n| Handle::Object(Arc::new(Held(n)))),
kind::ENTITY => Some(Handle::Entity(r.id)),
_ => None,
}
}
}
pub trait Nanite: Sized {
const CLASS: &'static str;
fn from_handle(handle: Handle) -> Self;
fn handle(&self) -> &Handle;
fn of(entity: &yog_event::Entity) -> Self {
Self::from_handle(Handle::entity(entity.uuid.clone()))
}
}
pub struct Member {
class: &'static str,
name: &'static str,
desc: fn() -> String,
id: OnceLock<Option<u32>>,
}
pub const CONSTRUCTOR: &str = "<init>";
impl Member {
pub const fn new(class: &'static str, name: &'static str, desc: fn() -> String) -> Member {
Member {
class,
name,
desc,
id: OnceLock::new(),
}
}
pub fn class(&self) -> &'static str {
self.class
}
pub fn signature(&self) -> (&'static str, String) {
(self.name, (self.desc)())
}
pub fn id(&self) -> Option<u32> {
*self.id.get_or_init(|| {
crate::call(&Resolve {
class: self.class.to_owned(),
name: self.name.to_owned(),
desc: (self.desc)(),
})
.flatten()
})
}
pub fn call(&self, target: Value, args: Vec<Value>) -> Option<Value> {
let member = self.id()?;
crate::call(&Call {
member,
target,
args,
})
.flatten()
}
pub fn get(&self, target: Value) -> Option<Value> {
let member = self.id()?;
crate::call(&Get { member, target }).flatten()
}
pub fn set(&self, target: Value, value: Value) -> bool {
let Some(member) = self.id() else {
return false;
};
crate::call(&Set {
member,
target,
value,
})
.unwrap_or(false)
}
}
pub fn method_desc(params: &[String], ret: &str) -> String {
format!("({}){ret}", params.concat())
}
#[cfg(test)]
mod tests;