Skip to main content

yog_api/nanite/
added.rs

1//! Members a mod adds to a game class (`docs/design/nanites.md`): fields
2//! (`added_field!`, the mod's own state on the object — Mixin's `@Unique`),
3//! methods (`#[add_method]`, their bodies the mod's handlers) and interfaces
4//! (`implement!`). Declared before the game's classes load, as injections are.
5
6use std::marker::PhantomData;
7
8use super::{Java, Member, Nanite, Reply};
9
10/// A field a mod added to class `O`, of type `T`: named
11/// `yog$<crate>$<name>` on it (`yog_ids::nanite_added`).
12pub struct Added<O, T> {
13    member: Member,
14    _types: PhantomData<fn() -> (O, T)>,
15}
16
17impl<O: Nanite, T: Java + Reply> Added<O, T> {
18    /// The field `name` (the full one) of type `T` on `O`.
19    pub const fn new(name: &'static str) -> Self {
20        Added {
21            member: Member::new(O::CLASS, name, <T as Java>::desc),
22            _types: PhantomData,
23        }
24    }
25
26    /// Its member (what the host adds).
27    pub fn member(&'static self) -> &'static Member {
28        &self.member
29    }
30
31    /// Its value on `object` (its type's default before it's set).
32    pub fn get(&self, object: &O) -> T {
33        <T as Reply>::from_reply(self.member.get(object.handle().to_value()))
34    }
35
36    /// Sets it on `object`; whether it was.
37    pub fn set(&self, object: &O, value: T) -> bool {
38        self.member
39            .set(object.handle().to_value(), value.to_value())
40    }
41}
42
43/// `added_field!(LivingEntity, pub CHARGE: i32);` — a field on every
44/// `LivingEntity`, the mod's own (`CHARGE.get(&e)`, `CHARGE.set(&e, 3)`).
45#[macro_export]
46macro_rules! added_field {
47    ($owner:ty, $vis:vis $name:ident : $ty:ty) => {
48        $vis static $name: $crate::nanite::Added<$owner, $ty> = $crate::nanite::Added::new(
49            $crate::yog_ids::concatcp!(
50                $crate::yog_ids::nanite_added::PREFIX,
51                ::core::env!("CARGO_PKG_NAME"),
52                $crate::yog_ids::nanite_added::SEP,
53                ::core::stringify!($name),
54            ),
55        );
56
57        const _: () = {
58            // Runs when this mod's library loads: declared before the game loads.
59            #[$crate::ctor::ctor(unsafe, crate_path = $crate::ctor)]
60            fn declare() {
61                $crate::nanite::__declare(
62                    $crate::yog_ids::nanite_kind::ADD_FIELD,
63                    $name.member(),
64                    "",
65                );
66            }
67        };
68    };
69}
70
71/// `implement!(LivingEntity, "net.minecraft.world.entity.OwnableEntity");` —
72/// the class made to implement the interface (its methods `#[add_method]`s).
73#[macro_export]
74macro_rules! implement {
75    ($owner:ty, $interface:expr) => {
76        const _: () = {
77            static CLASS: $crate::nanite::Member = $crate::nanite::Member::new(
78                <$owner as $crate::nanite::Nanite>::CLASS,
79                "",
80                ::std::string::String::new,
81            );
82
83            #[$crate::ctor::ctor(unsafe, crate_path = $crate::ctor)]
84            fn declare() {
85                $crate::nanite::__declare(
86                    $crate::yog_ids::nanite_kind::IMPLEMENT,
87                    &CLASS,
88                    $interface,
89                );
90            }
91        };
92    };
93}