Skip to main content

yog_api/
java.rs

1//! Other mods — Yog's and Java ones — from a Yog mod: whether one is
2//! loaded ([`crate::mod_loaded`]), and calls into a Java mod's API by
3//! reflection ([`call`]).
4//!
5//! ```ignore
6//! use yog_api::java;
7//! use yog_api::yog_data::Value;
8//! if yog_api::mod_loaded("pehkui") {
9//!     let entity = Value::Ref(yog_api::yog_data::Ref::new("entity", uuid));
10//!     let scale = java::call("virtuoel.pehkui.api.ScaleTypes.BASE.getScaleData($0).getScale()", &[entity])
11//!         .and_then(|v| v.as_f64());
12//! }
13//! ```
14
15use yog_abi::YogStr;
16use yog_data::Value;
17
18use crate::registry::global_api;
19
20/// Whether mod `id` is loaded: a Yog mod, or a Java mod in Fabric's,
21/// Forge's or NeoForge's mod list. Content and code for another mod —
22/// an optional integration — go behind it.
23pub fn mod_loaded(id: &str) -> bool {
24    let api = global_api();
25    if api.is_null() {
26        return false;
27    }
28    unsafe { ((*api).is_mod_loaded)((*api).ctx, YogStr::from_str(id)) }
29}
30
31/// Calls a Java mod's API: `expr` is a chain from a class —
32/// `virtuoel.pehkui.api.ScaleTypes.BASE.getScaleData($0).getScale()` —
33/// fields and methods, `$n` the `n`-th of `args`. Numbers, strings,
34/// booleans and null cross as they are; an entity is
35/// `Value::Ref(Ref::new("entity", uuid))` both ways. `None` when the call
36/// failed (the log says why). For other mods' APIs only: Minecraft's own
37/// classes are renamed at run time on some loaders.
38pub fn call(expr: &str, args: &[Value]) -> Option<Value> {
39    let api = global_api();
40    if api.is_null() {
41        return None;
42    }
43    let args = yog_data::text::to_string(&Value::List(args.to_vec()));
44    let owned = unsafe { ((*api).java_call)((*api).ctx, YogStr::from_str(expr), YogStr::from_str(&args)) };
45    let text = crate::registry::take_owned(unsafe { (*api).free_str }, owned)?;
46    yog_data::text::parse_value(&text).ok()
47}