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