Skip to main content

yog_api/
lib.rs

1//! Yog API — the single crate mod authors depend on.
2//!
3//! A facade that re-exports every Yog domain plus the central [`Registry`] hub.
4//! Add a new domain crate, re-export it here, and mods pick it up via
5//! `yog_api::*`. Items are available both flat (`yog_api::Registry`) and
6//! namespaced by domain (`yog_api::world::World`).
7
8mod interop;
9mod registry;
10
11pub use interop::Interop;
12pub use registry::{installed_mods, open_ui, server, CServer, Mod, ModInfo, Registry};
13pub use yog_gfx::{GfxContext, core as gfx_core, gl as gfx_gl, draw2d as gfx_draw2d};
14
15/// Stable C ABI — re-exported so mods don't need a direct `yog-abi` dependency.
16pub use yog_abi::{ABI_VERSION, YogApi};
17
18/// Inter-mod communication proc-macros.
19pub use yog_interop::{yog_export, import};
20
21#[doc(hidden)]
22pub use std::os::raw::c_void as __c_void;
23
24/// Export a [`Mod`] as a dynamically loadable Yog mod.
25///
26/// Generates the two C-ABI entry points the runtime looks up:
27/// - `yog_abi_version() -> u32`  — version check before loading
28/// - `yog_mod_register(*const YogApi, *const c_char)` — registration entry point,
29///   receives the mod's `id` from its manifest
30///
31/// Put this once at the crate root of a `cdylib` mod:
32///
33/// ```ignore
34/// yog_api::export_mod!(MyMod);
35/// ```
36#[macro_export]
37macro_rules! export_mod {
38    ($mod_ty:ty) => {
39        #[no_mangle]
40        pub extern "C" fn yog_abi_version() -> u32 {
41            $crate::ABI_VERSION
42        }
43
44        #[no_mangle]
45        pub unsafe extern "C" fn yog_mod_register(
46            api: *const $crate::YogApi,
47            mod_id_ptr: *const ::std::os::raw::c_char,
48        ) {
49            // Parse mod_id from the C string passed by the runtime.
50            let mod_id: &str = if mod_id_ptr.is_null() {
51                "unknown"
52            } else {
53                match ::std::ffi::CStr::from_ptr(mod_id_ptr).to_str() {
54                    Ok(s) => s,
55                    Err(_) => "unknown",
56                }
57            };
58            // Store for interop use (yog_api::interop::current_mod_id()).
59            $crate::__set_current_mod_id(mod_id);
60
61            // Catch panics so they never unwind across this `extern "C"` boundary
62            // back into the runtime (which would be undefined behaviour).
63            let outcome = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
64                // SAFETY: the runtime passes a valid YogApi pointer, verified via
65                // yog_abi_version() and abi_version/size checks before this call.
66                let mut registry = unsafe { $crate::Registry::from_raw(api) };
67                <$mod_ty as $crate::Mod>::register(&mut registry);
68
69                // Auto-register all #[yog_export] functions.
70                for (name, ptr) in $crate::__yog_export_registry().lock().unwrap().iter() {
71                    registry.interop().export(name, *ptr as *const ::std::os::raw::c_void);
72                }
73            }));
74            if outcome.is_err() {
75                $crate::error!("mod {} panicked during register", ::core::stringify!($mod_ty));
76            }
77        }
78    };
79}
80
81/// Internal: set by `export_mod!` before calling `Mod::register`.
82/// Used by `yog_api::interop::current_mod_id()` so `Interop::export` knows
83/// which mod is calling.
84#[doc(hidden)]
85pub fn __set_current_mod_id(id: &str) {
86    CURRENT_MOD_ID.with(|cell| cell.replace(Some(id.to_string())));
87}
88
89/// Internal: the current mod's id, set during `yog_mod_register`.
90#[doc(hidden)]
91pub fn __current_mod_id() -> Option<String> {
92    CURRENT_MOD_ID.with(|cell| cell.borrow().clone())
93}
94
95std::thread_local! {
96    static CURRENT_MOD_ID: std::cell::RefCell<Option<String>> = std::cell::RefCell::new(None);
97}
98
99// ── Auto-export registry (used by #[yog_export] proc-macro) ──────────────
100
101/// Global registry of `#[yog_export]` functions.
102/// Populated by static initializers before `yog_mod_register` runs.
103#[doc(hidden)]
104pub fn __yog_export_registry() -> &'static std::sync::Mutex<Vec<(&'static str, usize)>> {
105    static REG: std::sync::LazyLock<std::sync::Mutex<Vec<(&'static str, usize)>>> =
106        std::sync::LazyLock::new(|| std::sync::Mutex::new(Vec::new()));
107    &REG
108}
109
110pub use yog_command::CommandContext;
111pub use yog_core::{BlockPos, Server};
112pub use yog_event::{
113    AdvancementEvent, AttackEntityEvent, BlockBreakEvent, ChatEvent, ClientTickEvent,
114    ContainerCloseEvent, ContainerOpenEvent, CraftEvent, EntityDamageEvent, EntityDeathEvent,
115    EntityInteractEvent, EntitySpawnEvent, EventPhase, ExplosionEvent,
116    ItemPickupEvent, KeyPressEvent, PlaceBlockEvent, PlayerDeathEvent, PlayerJoinEvent,
117    PlayerLeaveEvent, PlayerMoveEvent, PlayerRespawnEvent, ProjectileHitEvent, ScreenEvent,
118    UseBlockEvent, UseItemEvent,
119};
120pub use yog_entity::Entity;
121pub use yog_network::{Packet, PacketEvent, PacketField};
122#[doc(inline)]
123pub use yog_network::packet;
124pub use yog_player::Player;
125pub use yog_registry::{BlockDef, FoodDef, FurnaceRecipe, ItemDef, ShapedRecipe, ShapelessRecipe, BookRecipe, ItemModifier, AdvancementReward, StartupGrant};
126pub use yog_config::Config;
127pub use yog_storage::{Storage, StorageScope, Value};
128pub use yog_world::World;
129pub use yog_book::{Book, BookCategory, BookEntry, BookPage, BookMacro, BookRegistry};
130pub use yog_book::{BookRenderer, BookFontRegistry};
131pub use yog_book::{text_page, text_page_titled, spotlight_page, crafting_page, smelting_page, image_page, entity_page, relations_page, pattern_page};
132pub use yog_ui::{UiRoot, LayoutNode, Rect, widget, Align, FlexDir, Dock, FocusStyle};
133pub use yog_inventory::{InventoryDef, SlotLayout};
134
135/// Logging macros (`yog_api::info!`, `warn!`, `error!`).
136pub use yog_logging::{error, info, warn};
137
138/// Core types and handles.
139pub mod core {
140    pub use yog_core::*;
141}
142
143/// Events and the subscription registry.
144pub mod event {
145    pub use yog_event::*;
146}
147
148/// World access (block get/set, dimensions).
149pub mod world {
150    pub use yog_world::*;
151}
152
153/// Entity access (teleport, position, health, ... by UUID).
154pub mod entity {
155    pub use yog_entity::*;
156}
157
158/// Player access (give item, teleport).
159pub mod player {
160    pub use yog_player::*;
161}
162
163/// Content registration (custom items / blocks / food).
164pub mod content {
165    pub use yog_registry::*;
166}
167
168/// Networking (raw-byte packets over channels).
169pub mod network {
170    pub use yog_network::*;
171}
172
173/// Commands.
174pub mod command {
175    pub use yog_command::*;
176}
177
178/// Persistent key-value storage for mod data.
179pub mod storage {
180    pub use yog_storage::*;
181}
182
183/// Mod configuration (typed key/value files).
184pub mod config {
185    pub use yog_config::*;
186}
187
188/// In-game book/documentation system (Patchouli-like).
189pub mod book {
190    pub use yog_book::*;
191}
192
193/// UI framework — flexbox layout + widgets on top of yog-gfx.
194pub mod ui {
195    pub use yog_ui::*;
196}
197
198/// Inventory framework — real Container/Menu screens (BlockEntity-backed),
199/// as opposed to `ui`'s HUD-drawn overlays. See `yog-inventory`'s DESIGN.md.
200pub mod inventory {
201    pub use yog_inventory::*;
202}