Skip to main content

yog_abi/
lib.rs

1//! Yog stable C ABI — the ONLY types that cross the mod/runtime boundary.
2//!
3//! Rules this file must never break:
4//!  - Every type is `#[repr(C)]`.
5//!  - No Rust trait objects, no generics, no std types in public structs.
6//!  - New fields are appended only at the END of structs; increment `ABI_MINOR`.
7//!  - ABI_MAJOR bumps only when an existing field is removed or reordered.
8//!
9//! Mods and the runtime are compiled independently. They are compatible when
10//! `ABI_MAJOR` matches and `mod_ABI_MINOR <= runtime_ABI_MINOR`.
11
12use std::os::raw::c_void;
13
14// ── Version ──────────────────────────────────────────────────────────────────
15
16pub const ABI_MAJOR: u32 = 0;
17pub const ABI_MINOR: u32 = 27;
18/// `ABI_MAJOR * 10_000 + ABI_MINOR`.  Checked at mod load time.
19pub const ABI_VERSION: u32 = ABI_MAJOR * 10_000 + ABI_MINOR;
20
21// ── Primitive types ───────────────────────────────────────────────────────────
22
23/// Borrowed UTF-8 byte slice passed to a function. NOT null-terminated.
24/// Valid only for the duration of the call that provides it — never store.
25#[repr(C)]
26#[derive(Copy, Clone)]
27pub struct YogStr {
28    pub ptr: *const u8,
29    pub len: u32,
30}
31
32impl YogStr {
33    pub const EMPTY: Self = Self { ptr: std::ptr::null(), len: 0 };
34
35    #[inline]
36    pub fn from_str(s: &str) -> Self {
37        Self { ptr: s.as_ptr(), len: s.len() as u32 }
38    }
39
40    #[inline]
41    pub fn is_empty(self) -> bool { self.len == 0 || self.ptr.is_null() }
42
43    /// SAFETY: `ptr` must be valid UTF-8 of `len` bytes for at least the
44    /// duration of the call that provided this `YogStr`.
45    #[inline]
46    pub unsafe fn as_str<'a>(self) -> &'a str {
47        if self.ptr.is_null() || self.len == 0 {
48            return "";
49        }
50        std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, self.len as usize))
51    }
52}
53
54/// Heap-allocated UTF-8 string owned by the RUNTIME.
55/// `ptr == null` encodes `None` / "not found".
56/// When `ptr` is non-null the caller MUST free it via `YogServer::free_str`.
57#[repr(C)]
58#[derive(Copy, Clone)]
59pub struct YogOwnedStr {
60    pub ptr: *mut u8,
61    pub len: u32,
62}
63
64impl YogOwnedStr {
65    pub const NONE: Self = Self { ptr: std::ptr::null_mut(), len: 0 };
66
67    /// Allocate a new `YogOwnedStr` from a Rust `String`.
68    pub fn from_string(s: String) -> Self {
69        let len = s.len() as u32;
70        let ptr = Box::into_raw(s.into_bytes().into_boxed_slice()) as *mut u8;
71        Self { ptr, len }
72    }
73
74    #[inline]
75    pub fn is_none(self) -> bool { self.ptr.is_null() }
76}
77
78/// Integer 3-D block position.
79#[repr(C)]
80#[derive(Copy, Clone)]
81pub struct YogBlockPos {
82    pub x: i32,
83    pub y: i32,
84    pub z: i32,
85}
86
87/// Float 3-D vector (position, velocity, …).
88#[repr(C)]
89#[derive(Copy, Clone)]
90pub struct YogVec3 {
91    pub x: f64,
92    pub y: f64,
93    pub z: f64,
94}
95
96// ── Event structs (Java → Rust) ───────────────────────────────────────────────
97
98#[repr(C)]
99pub struct YogBlockBreakEvent {
100    pub player: YogStr,
101    pub block:  YogStr,
102    pub pos:    YogBlockPos,
103}
104
105#[repr(C)]
106pub struct YogChatEvent {
107    pub player:  YogStr,
108    pub message: YogStr,
109}
110
111/// Shared by player_join and player_leave.
112#[repr(C)]
113pub struct YogPlayerEvent {
114    pub player: YogStr,
115    pub uuid:   YogStr,
116}
117
118#[repr(C)]
119pub struct YogUseItemEvent {
120    pub player: YogStr,
121    pub item:   YogStr,
122    /// ABI minor 25: whether the player was sneaking (shift) during use.
123    pub sneaking: bool,
124}
125
126#[repr(C)]
127pub struct YogUseBlockEvent {
128    pub player: YogStr,
129    pub block:  YogStr,
130    pub pos:    YogBlockPos,
131}
132
133#[repr(C)]
134pub struct YogAttackEntityEvent {
135    pub player:      YogStr,
136    pub target_type: YogStr,
137    pub target_uuid: YogStr,
138}
139
140#[repr(C)]
141pub struct YogEntityDamageEvent {
142    pub entity_type: YogStr,
143    pub uuid:        YogStr,
144    pub amount:      f32,
145    pub source:      YogStr,
146}
147
148#[repr(C)]
149pub struct YogEntityDeathEvent {
150    pub entity_type: YogStr,
151    pub uuid:        YogStr,
152    pub source:      YogStr,
153}
154
155#[repr(C)]
156pub struct YogEntitySpawnEvent {
157    pub entity_type: YogStr,
158    pub uuid:        YogStr,
159    pub dimension:   YogStr,
160}
161
162/// Fired when a player dies (Pre: before death is processed; Post: after death).
163/// Pre phase — return false to prevent death (keep entity alive at 0.5 HP).
164#[repr(C)]
165pub struct YogPlayerDeathEvent {
166    pub player: YogStr,
167    pub uuid:   YogStr,
168    /// Damage source identifier, e.g. `"player"`, `"fall"`.
169    pub source: YogStr,
170}
171
172/// Fired when a player respawns after death.
173#[repr(C)]
174pub struct YogPlayerRespawnEvent {
175    pub player:    YogStr,
176    pub uuid:      YogStr,
177    /// True if respawning at a bed or anchor, false at world spawn.
178    pub at_anchor: bool,
179}
180
181/// Fired when a player earns an advancement (Post only).
182#[repr(C)]
183pub struct YogAdvancementEvent {
184    pub player:      YogStr,
185    pub uuid:        YogStr,
186    /// Namespaced id, e.g. `"minecraft:story/mine_stone"`.
187    pub advancement: YogStr,
188}
189
190/// Fired when a player right-clicks (interacts with) an entity (Pre: before; Post: after).
191/// Pre phase — return false to cancel the interaction.
192#[repr(C)]
193pub struct YogEntityInteractEvent {
194    pub player:      YogStr,
195    pub player_uuid: YogStr,
196    pub entity_type: YogStr,
197    pub entity_uuid: YogStr,
198    /// `"main_hand"` or `"off_hand"`.
199    pub hand:        YogStr,
200}
201
202/// Fired when a player takes a crafted item from a crafting output slot (Post only).
203#[repr(C)]
204pub struct YogCraftEvent {
205    pub player:       YogStr,
206    pub player_uuid:  YogStr,
207    pub result_item:  YogStr,
208    pub result_count: u32,
209}
210
211/// Fired when an explosion occurs in a world (Pre: before block destruction; Post: after).
212/// Pre phase — return false to cancel the explosion (block and entity damage suppressed).
213#[repr(C)]
214pub struct YogExplosionEvent {
215    pub dimension:    YogStr,
216    pub x:            f64,
217    pub y:            f64,
218    pub z:            f64,
219    pub power:        f32,
220    /// UUID of the entity that caused the explosion, or empty if world/tnt.
221    pub cause_uuid:   YogStr,
222}
223
224// ── ABI minor 9–10 event structs ──────────────────────────────────────────────
225
226/// Fired when a player picks up an item entity (Pre: cancellable; Post: informational).
227#[repr(C)]
228pub struct YogItemPickupEvent {
229    pub player:      YogStr,
230    pub player_uuid: YogStr,
231    /// Registry id of the item, e.g. `"minecraft:diamond"`.
232    pub item_id:     YogStr,
233    pub item_count:  u32,
234    /// UUID of the item entity that was picked up.
235    pub entity_uuid: YogStr,
236}
237
238/// Fired when a player sends a movement packet (Post only; very high frequency).
239#[repr(C)]
240pub struct YogPlayerMoveEvent {
241    pub player:      YogStr,
242    pub player_uuid: YogStr,
243    pub x: f64,
244    pub y: f64,
245    pub z: f64,
246    pub yaw:   f32,
247    pub pitch: f32,
248}
249
250/// Fired when a player opens a container screen (Pre: cancellable; Post: informational).
251/// `container_type` is the screen handler registry id, e.g. `"minecraft:chest"`.
252/// Empty string if the type is not in the registry (e.g. the player inventory).
253#[repr(C)]
254pub struct YogContainerOpenEvent {
255    pub player:         YogStr,
256    pub player_uuid:    YogStr,
257    pub container_type: YogStr,
258}
259
260/// Fired when a player closes a container screen (Post only).
261#[repr(C)]
262pub struct YogContainerCloseEvent {
263    pub player:      YogStr,
264    pub player_uuid: YogStr,
265}
266
267/// Fired when a persistent projectile (arrow, trident) hits a target (Pre: cancellable).
268/// Pre phase — return false to cancel the hit (projectile passes through).
269#[repr(C)]
270pub struct YogProjectileHitEvent {
271    /// Registry id of the projectile, e.g. `"minecraft:arrow"`.
272    pub projectile_type: YogStr,
273    pub projectile_uuid: YogStr,
274    /// UUID of the entity that shot/threw this projectile, or empty.
275    pub shooter_uuid:    YogStr,
276    /// `"block"` or `"entity"`.
277    pub hit_type:        YogStr,
278    /// UUID of the entity that was hit (empty for block hits).
279    pub hit_entity_uuid: YogStr,
280    pub x: f64,
281    pub y: f64,
282    pub z: f64,
283    pub dimension: YogStr,
284}
285
286/// Fired when a player places a block (Pre: before placement; Post: after).
287#[repr(C)]
288pub struct YogPlaceBlockEvent {
289    pub player: YogStr,
290    pub block:  YogStr,
291    pub pos:    YogBlockPos,
292}
293
294#[repr(C)]
295pub struct YogPacketEvent {
296    pub channel:     YogStr,
297    pub player:      YogStr, // empty string on client-received packets
298    pub payload:     *const u8,
299    pub payload_len: u32,
300}
301
302#[repr(C)]
303pub struct YogCommandEvent {
304    pub name:   YogStr,
305    pub args:   YogStr,
306    pub source: YogStr,
307    pub uuid:   YogStr,
308}
309
310/// A startup grant definition — items/books to give on first join.
311#[repr(C)]
312pub struct YogStartupGrantDef {
313    pub id:    YogStr,
314    pub items: YogStr, // '|'-separated item ids
315    pub book:  YogStr, // empty = none
316    pub command: YogStr, // empty = none
317}
318
319// ── Content definition structs (mod → runtime) ────────────────────────────────
320
321#[repr(C)]
322pub struct YogItemDef {
323    pub id:              YogStr,
324    pub max_stack:       u32,
325    pub name:            YogStr, // empty = no override
326    pub tooltip:         YogStr, // empty = none
327    pub max_damage:      u32,
328    pub fire_resistant:  bool,
329    pub fuel_ticks:      u32,
330    pub food_nutrition:  u32,    // 0 = not a food item
331    pub food_saturation: f32,
332    pub food_always_eat: bool,
333}
334
335#[repr(C)]
336pub struct YogBlockDef {
337    pub id:            YogStr,
338    pub hardness:      f32,
339    pub resistance:    f32,
340    pub name:          YogStr,
341    pub light_level:   u8,
342    pub sound:         YogStr,   // empty = default stone sound
343    pub requires_tool: bool,
344    pub no_collision:  bool,
345    pub slipperiness:  f32,
346    /// Bounding box in pixels: `[x1, y1, z1, x2, y2, z2]`. All zeros = full cube.
347    pub shape:         [f32; 6],
348    /// Fence/pipe-style dynamic arm growth toward compatible neighbors — see
349    /// `yog_registry::BlockDef::connects_to_neighbors`.
350    pub connects:      bool,
351    /// Comma-joined connection compatibility tags — see
352    /// `yog_registry::BlockDef::connect_groups`. Empty = no tags.
353    pub connect_groups: YogStr,
354    /// Id of a `YogInventoryDef` (registered via `register_inventory`) this
355    /// block is backed by — empty = no inventory (plain block, as before).
356    /// See `yog_inventory`'s DESIGN.md.
357    pub inventory_id: YogStr,
358}
359
360/// An inventory-backed screen definition — see `yog_inventory::InventoryDef`.
361#[repr(C)]
362pub struct YogInventoryDef {
363    pub id:         YogStr,
364    pub slot_count: u32,
365    /// `"x:y,x:y,..."` — one pair per slot, in slot-index order. Empty =
366    /// use the default vanilla-style grid (see `yog_inventory::InventoryDef::default_grid`).
367    pub layout:     YogStr,
368    pub include_player_inventory: bool,
369    pub player_inv_x: f32,
370    pub player_inv_y: f32,
371    /// Empty = default vanilla-style panel texture.
372    pub background_texture: YogStr,
373    pub title: YogStr,
374}
375
376// ── ABI minor 10 client event structs ─────────────────────────────────────────
377
378/// Key press / release / repeat from the keyboard (client-side only).
379#[repr(C)]
380#[derive(Copy, Clone)]
381pub struct YogKeyPressEvent {
382    /// GLFW key code (e.g. `GLFW_KEY_E = 69`).
383    pub key_code:  i32,
384    pub scan_code: i32,
385    /// 0 = release, 1 = press, 2 = repeat.
386    pub action:    i32,
387    /// Modifier bitmask: 1=shift, 2=ctrl, 4=alt, 8=super.
388    pub modifiers: i32,
389}
390
391// ── Handler function-pointer types ────────────────────────────────────────────
392//
393// All event handlers receive a `phase: u8` argument:
394//   0 = Pre  — fires before the action; return value matters (false = cancel).
395//   1 = Post — fires after the action; return value is ignored.
396//
397// This unified signature lets one registered closure handle both phases.
398//
399// Client-side handlers (minor 10) do NOT receive a `YogServer*` — they run on
400// the render thread and have no server context.
401
402pub type YogBlockBreakFn   = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogBlockBreakEvent,   u8) -> bool;
403pub type YogChatFn         = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogChatEvent,         u8) -> bool;
404pub type YogPlayerFn       = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerEvent,       u8) -> bool;
405pub type YogUseItemFn      = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogUseItemEvent,      u8) -> bool;
406pub type YogUseBlockFn     = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogUseBlockEvent,     u8) -> bool;
407pub type YogAttackEntityFn = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogAttackEntityEvent, u8) -> bool;
408pub type YogEntityDamageFn = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntityDamageEvent, u8) -> bool;
409pub type YogEntityDeathFn  = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntityDeathEvent,  u8) -> bool;
410pub type YogEntitySpawnFn   = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntitySpawnEvent,   u8) -> bool;
411pub type YogPlaceBlockFn    = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlaceBlockEvent,    u8) -> bool;
412pub type YogPlayerDeathFn   = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerDeathEvent,   u8) -> bool;
413pub type YogPlayerRespawnFn = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerRespawnEvent, u8) -> bool;
414pub type YogAdvancementFn      = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogAdvancementEvent,      u8) -> bool;
415pub type YogEntityInteractFn   = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntityInteractEvent,   u8) -> bool;
416pub type YogCraftFn            = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogCraftEvent,            u8) -> bool;
417pub type YogExplosionFn        = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogExplosionEvent,        u8) -> bool;
418pub type YogItemPickupFn       = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogItemPickupEvent,       u8) -> bool;
419pub type YogPlayerMoveFn       = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerMoveEvent,       u8) -> bool;
420pub type YogContainerOpenFn    = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogContainerOpenEvent,    u8) -> bool;
421pub type YogContainerCloseFn   = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogContainerCloseEvent,   u8) -> bool;
422pub type YogProjectileHitFn    = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogProjectileHitEvent,    u8) -> bool;
423
424/// Packet events — always Post, no phase.
425pub type YogPacketFn  = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPacketEvent);
426/// Server lifecycle / tick — no event struct, always fires.
427pub type YogServerFn  = unsafe extern "C" fn(*mut c_void, *const YogServer);
428/// Command handler.
429pub type YogCommandFn = unsafe extern "C" fn(
430    ud: *mut c_void,
431    srv: *const YogServer,
432    ev: *const YogCommandEvent,
433    reply_buf: *mut u8,
434    reply_cap: u32,
435    reply_len: *mut u32,
436);
437/// Scheduler handler (once or repeating).
438pub type YogScheduledFn = unsafe extern "C" fn(*mut c_void, *const YogServer);
439
440// ── ABI minor 10 — client-side function pointer types ────────────────────────
441
442/// Client tick — no event, no server context.
443pub type YogClientFn = unsafe extern "C" fn(ud: *mut c_void);
444/// HUD render — `gfx` is the graphics context for this frame; only valid for
445/// the call duration.  `draw2d_*` functions in `gfx` work here.
446pub type YogUIEventFn = unsafe extern "C" fn(ud: *mut c_void, ui_id: YogStr, event_id: YogStr);
447pub type YogHudRenderFn = unsafe extern "C" fn(ud: *mut c_void, gfx: *const YogGfxApi);
448/// World render — `gfx` contains `view_proj` and `camera_pos` for 3D rendering.
449/// Valid only for the call duration.
450pub type YogWorldRenderFn = unsafe extern "C" fn(ud: *mut c_void, gfx: *const YogGfxApi);
451/// Key press — return `false` to cancel (prevent Minecraft from processing the key).
452pub type YogKeyPressFn  = unsafe extern "C" fn(ud: *mut c_void, ev: *const YogKeyPressEvent) -> bool;
453/// Screen event — `screen_class` is the simple class name (e.g. `"InventoryScreen"`).
454/// For `on_screen_open` return `false` to prevent the screen from opening.
455pub type YogScreenFn    = unsafe extern "C" fn(ud: *mut c_void, screen_class: YogStr) -> bool;
456
457// ── ABI minor 14 — low-level GPU pipeline ────────────────────────────────────
458
459/// Low-level GPU context passed to render handlers.
460///
461/// Provides direct access to the OpenGL pipeline: buffer objects, vertex arrays,
462/// shader programs, textures, draw calls, and render state.
463///
464/// The per-frame fields (`screen_w/h`, `delta_tick`, `view_proj`, `camera_pos`)
465/// are filled by the runtime before calling the handler; the function pointers
466/// point to statically-allocated implementations.
467///
468/// Valid only for the duration of the render callback — never store the pointer.
469/// GPU resource **handles** (`u32`) may be stored between frames.
470///
471/// Colors are `0xAARRGGBB` (Minecraft convention).
472#[repr(C)]
473#[derive(Copy, Clone)]
474pub struct YogGfxApi {
475    // ── Per-frame context ─────────────────────────────────────────────────────
476    /// GUI-pixel screen width.
477    pub screen_w:   i32,
478    /// GUI-pixel screen height.
479    pub screen_h:   i32,
480    /// Partial-tick interpolation factor (0.0–1.0).
481    pub delta_tick:   f32,
482    /// GUI scale factor: physical pixels per GUI pixel (e.g. 2.0 for 2× GUI scale).
483    /// Useful for converting GUI-pixel coordinates to physical pixels for OpenGL calls.
484    pub scale_factor: f32,
485    /// View-projection matrix in camera-relative space (column-major, 16 × f32).
486    /// All zeros during `on_hud_render`; filled during `on_world_render`.
487    pub view_proj:  [f32; 16],
488    /// Camera world-space position.  All zeros during `on_hud_render`.
489    pub camera_pos:  [f32; 3],
490    /// Local player world-space position (eye height).  All zeros during `on_hud_render`.
491    /// Differs from `camera_pos` in third-person view.
492    pub player_pos:  [f32; 3],
493    pub _pad1:       f32,
494
495    // ── GPU buffers ───────────────────────────────────────────────────────────
496    /// Allocate a new GPU buffer (VBO / EBO). Returns 0 on failure.
497    pub buf_create:  unsafe extern "C" fn() -> u32,
498    /// Delete a buffer created by `buf_create`.
499    pub buf_delete:  unsafe extern "C" fn(handle: u32),
500    /// Upload `len` bytes from `bytes` into `handle`.
501    /// `dynamic`: hints frequent updates (`GL_DYNAMIC_DRAW` vs `GL_STATIC_DRAW`).
502    pub buf_data:    unsafe extern "C" fn(handle: u32, bytes: *const u8, len: u32, dynamic: bool),
503    /// Overwrite `len` bytes at `offset` in `handle`.
504    pub buf_subdata: unsafe extern "C" fn(handle: u32, offset: u32, bytes: *const u8, len: u32),
505
506    // ── Vertex arrays ─────────────────────────────────────────────────────────
507    /// Create a vertex array object. Returns 0 on failure.
508    pub vao_create: unsafe extern "C" fn() -> u32,
509    /// Delete a VAO created by `vao_create`.
510    pub vao_delete: unsafe extern "C" fn(handle: u32),
511    /// Declare one vertex attribute in `vao`, sourced from `vbo`.
512    /// `dtype`: 0=f32, 1=u8, 2=i32, 3=u32.
513    pub vao_attrib: unsafe extern "C" fn(
514        vao: u32, vbo: u32, index: u32, components: u8,
515        dtype: u8, normalized: bool, stride: u32, offset: u32,
516    ),
517    /// Bind an index buffer (EBO) to `vao`.
518    pub vao_set_ebo: unsafe extern "C" fn(vao: u32, ebo: u32),
519
520    // ── Shader programs ───────────────────────────────────────────────────────
521    /// Compile + link `vert_src` / `frag_src` (GLSL 150 core).
522    /// Writes the program handle to `*out`. Returns false and logs on error.
523    pub prog_create:       unsafe extern "C" fn(vert: YogStr, frag: YogStr, out: *mut u32) -> bool,
524    /// Delete a shader program.
525    pub prog_delete:       unsafe extern "C" fn(handle: u32),
526    pub prog_uniform_1i:   unsafe extern "C" fn(prog: u32, name: YogStr, v: i32),
527    pub prog_uniform_1f:   unsafe extern "C" fn(prog: u32, name: YogStr, v: f32),
528    pub prog_uniform_2f:   unsafe extern "C" fn(prog: u32, name: YogStr, x: f32, y: f32),
529    pub prog_uniform_3f:   unsafe extern "C" fn(prog: u32, name: YogStr, x: f32, y: f32, z: f32),
530    pub prog_uniform_4f:   unsafe extern "C" fn(prog: u32, name: YogStr, x: f32, y: f32, z: f32, w: f32),
531    /// Set a mat4 uniform from 16 column-major floats.
532    pub prog_uniform_mat4: unsafe extern "C" fn(prog: u32, name: YogStr, col_major: *const f32),
533
534    // ── Textures ──────────────────────────────────────────────────────────────
535    /// Upload RGBA8 pixel data as a new texture.
536    /// `linear`: `GL_LINEAR` if true, `GL_NEAREST` if false.
537    pub tex_create:  unsafe extern "C" fn(w: u32, h: u32, rgba: *const u8, linear: bool) -> u32,
538    /// Delete a texture created by `tex_create`.
539    pub tex_delete:  unsafe extern "C" fn(handle: u32),
540    /// Bind `handle` to texture unit `unit` (0–7).
541    pub tex_bind:    unsafe extern "C" fn(unit: u32, handle: u32),
542    /// Return the GL texture handle Minecraft uses for a namespaced resource
543    /// (e.g. `"minecraft:textures/gui/icons.png"`). Returns 0 if not found.
544    /// Do **not** delete handles obtained this way — Minecraft owns them.
545    pub tex_from_mc: unsafe extern "C" fn(id: YogStr) -> u32,
546
547    // ── Draw calls ────────────────────────────────────────────────────────────
548    /// Draw `count` primitives from `vao`, using shader `prog`.
549    /// `mode`: 0=Triangles, 1=Lines, 2=LineStrip, 3=TriangleStrip, 4=TriangleFan.
550    pub draw_arrays:   unsafe extern "C" fn(vao: u32, prog: u32, mode: u8, first: u32, count: u32),
551    /// Draw indexed primitives.  `ebo` must be bound to `vao` via `vao_set_ebo`.
552    /// `u32_idx`: `true` for `u32` indices, `false` for `u16` indices.
553    pub draw_elements: unsafe extern "C" fn(vao: u32, ebo: u32, prog: u32, mode: u8, count: u32, u32_idx: bool),
554
555    // ── Render state ──────────────────────────────────────────────────────────
556    /// Enable/disable blending. `src`/`dst` are raw GL blend factor enum values.
557    pub set_blend:    unsafe extern "C" fn(enabled: bool, src: u32, dst: u32),
558    /// Enable/disable depth testing and depth writes.
559    pub set_depth:    unsafe extern "C" fn(test: bool, write: bool),
560    /// Enable scissor clipping (GUI-pixel rectangle).
561    pub set_scissor:  unsafe extern "C" fn(x: i32, y: i32, w: i32, h: i32),
562    /// Disable scissor clipping.
563    pub clear_scissor: unsafe extern "C" fn(),
564    /// Set the GL viewport (physical pixel coordinates).
565    pub set_viewport:  unsafe extern "C" fn(x: i32, y: i32, w: i32, h: i32),
566
567    // ── 2D convenience (HUD-render only — uses MC's DrawContext) ─────────────
568    /// Filled rectangle. Only valid during `on_hud_render`.
569    pub draw2d_rect:     unsafe extern "C" fn(x1: f32, y1: f32, x2: f32, y2: f32, color: u32),
570    /// Vertical-gradient rectangle. Only valid during `on_hud_render`.
571    pub draw2d_gradient: unsafe extern "C" fn(x1: f32, y1: f32, x2: f32, y2: f32, top: u32, bottom: u32),
572    /// MC text renderer string. Only valid during `on_hud_render`.
573    pub draw2d_text:     unsafe extern "C" fn(text: YogStr, x: f32, y: f32, color: u32, shadow: bool),
574    /// Blit from a Minecraft-managed texture. Only valid during `on_hud_render`.
575    /// `(u0, v0)` in texels; `(w, h)` in pixels; `(tw, th)` full texture size.
576    pub draw2d_mc_tex:   unsafe extern "C" fn(id: YogStr, x: f32, y: f32, u0: f32, v0: f32, w: f32, h: f32, tw: f32, th: f32),
577
578    // ── appended in ABI minor 21 ──────────────────────────────────────────────
579    /// Render an item stack (3D block models included) via MC's item renderer,
580    /// like Patchouli's `renderItemStack`. `id` is a registry item id
581    /// ("minecraft:crafting_table"); `size` is the on-screen size in GUI px
582    /// (16 = inventory size). Only valid during `on_hud_render`.
583    pub draw2d_item:     unsafe extern "C" fn(id: YogStr, x: f32, y: f32, size: f32),
584}
585
586unsafe impl Send for YogGfxApi {}
587unsafe impl Sync for YogGfxApi {}
588
589// ── Server action table (runtime → mod direction is wrong; it's mod → runtime) ─
590
591/// All Minecraft-mutating calls available inside a handler.
592///
593/// `ctx` is an opaque pointer to the runtime's JNI state.  Every function takes
594/// it as its first argument.  The pointer is valid for the lifetime of the process.
595///
596/// Strings **returned** by functions in this table are heap-allocated by the
597/// runtime and must be freed with `free_str` after the caller has read them.
598#[repr(C)]
599pub struct YogServer {
600    pub ctx:         *mut c_void,
601    pub abi_version: u32,
602    /// `sizeof(YogServer)` at build time — allows mods compiled against an older
603    /// table to detect and skip fields they don't know about.
604    pub size:        u32,
605
606    /// Free a string returned by any function in this table.
607    pub free_str: unsafe extern "C" fn(ptr: *mut u8, len: u32),
608
609    // ── chat ─────────────────────────────────────────────────────────────────
610    pub broadcast: unsafe extern "C" fn(ctx: *mut c_void, msg: YogStr),
611
612    // ── world ────────────────────────────────────────────────────────────────
613    pub get_block:   unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> YogOwnedStr,
614    pub set_block:   unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, block: YogStr) -> bool,
615    pub world_time:  unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, out: *mut i64) -> bool,
616    pub set_time:    unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, time: i64) -> bool,
617    pub is_raining:  unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr) -> bool,
618    pub set_weather: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, raining: bool, dur: i32) -> bool,
619
620    // ── player ───────────────────────────────────────────────────────────────
621    pub give_item:         unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, item: YogStr, count: u32) -> bool,
622    pub player_teleport:   unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, pos: YogVec3) -> bool,
623    pub send_to_player:    unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, channel: YogStr, data: *const u8, len: u32) -> bool,
624    pub send_to_server:    unsafe extern "C" fn(ctx: *mut c_void, channel: YogStr, data: *const u8, len: u32) -> bool,
625    pub kick_player:       unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, reason: YogStr) -> bool,
626    pub set_gamemode:      unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, mode: YogStr) -> bool,
627    pub send_title:        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, title: YogStr, sub: YogStr, fi: i32, stay: i32, fo: i32) -> bool,
628    pub send_actionbar:    unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, msg: YogStr) -> bool,
629    pub play_sound:        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogVec3, sound: YogStr, vol: f32, pitch: f32) -> bool,
630    pub play_sound_player: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, sound: YogStr, vol: f32, pitch: f32) -> bool,
631
632    // ── entity ───────────────────────────────────────────────────────────────
633    pub entity_teleport:      unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, pos: YogVec3) -> bool,
634    pub entity_position:      unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut YogVec3) -> bool,
635    pub entity_health:        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut f32) -> bool,
636    pub entity_set_health:    unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, hp: f32) -> bool,
637    pub entity_kill:          unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> bool,
638    pub spawn_entity:         unsafe extern "C" fn(ctx: *mut c_void, type_id: YogStr, dim: YogStr, pos: YogVec3) -> YogOwnedStr,
639    pub entity_add_effect:    unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, fx: YogStr, dur: i32, amp: u8, particles: bool) -> bool,
640    pub entity_remove_effect: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, fx: YogStr) -> bool,
641    pub entity_clear_effects: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> bool,
642    pub entity_velocity:      unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut YogVec3) -> bool,
643    pub entity_set_velocity:  unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, vel: YogVec3) -> bool,
644    pub entity_add_velocity:  unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, vel: YogVec3) -> bool,
645
646    // ── tags & loot ──────────────────────────────────────────────────────────
647    pub has_item_tag:  unsafe extern "C" fn(ctx: *mut c_void, item: YogStr, tag: YogStr) -> bool,
648    pub has_block_tag: unsafe extern "C" fn(ctx: *mut c_void, block: YogStr, tag: YogStr) -> bool,
649    pub drop_loot:     unsafe extern "C" fn(ctx: *mut c_void, table: YogStr, dim: YogStr, pos: YogVec3) -> bool,
650
651    // ── scoreboard ───────────────────────────────────────────────────────────
652    pub scoreboard_get: unsafe extern "C" fn(ctx: *mut c_void, obj: YogStr, player: YogStr, out: *mut i32) -> bool,
653    pub scoreboard_set: unsafe extern "C" fn(ctx: *mut c_void, obj: YogStr, player: YogStr, score: i32) -> bool,
654    pub scoreboard_add: unsafe extern "C" fn(ctx: *mut c_void, obj: YogStr, player: YogStr, delta: i32, out: *mut i32) -> bool,
655
656    // ── boss bar ─────────────────────────────────────────────────────────────
657    pub bossbar_create:        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, title: YogStr, color: YogStr, style: YogStr) -> bool,
658    pub bossbar_remove:        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr) -> bool,
659    pub bossbar_set_title:     unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, title: YogStr) -> bool,
660    pub bossbar_set_progress:  unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, progress: f32) -> bool,
661    pub bossbar_set_color:     unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, color: YogStr) -> bool,
662    pub bossbar_add_player:    unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, player: YogStr) -> bool,
663    pub bossbar_remove_player: unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, player: YogStr) -> bool,
664    pub bossbar_set_visible:   unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, visible: bool) -> bool,
665
666    // ── misc ─────────────────────────────────────────────────────────────────
667    pub game_dir: unsafe extern "C" fn(ctx: *mut c_void) -> YogOwnedStr,
668
669    // ── player query (ABI minor 4) ────────────────────────────────────────────
670    /// Newline-separated list of online player names, or NONE if server not up.
671    pub online_players: unsafe extern "C" fn(ctx: *mut c_void) -> YogOwnedStr,
672
673    // ── block entity (NBT, ABI minor 3) ──────────────────────────────────────
674    /// SNBT string of the block entity at `pos`, or NONE if there is none.
675    pub get_block_nbt: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> YogOwnedStr,
676    /// Write SNBT into the block entity at `pos`. Returns false if no block entity exists.
677    pub set_block_nbt: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, snbt: YogStr) -> bool,
678
679    // ── inventory (ABI minor 3) ───────────────────────────────────────────────
680    /// Tab/newline-encoded inventory: one line per occupied slot, `slot\titem_id\tcount`.
681    pub player_inventory: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
682    /// Set (or clear when count==0) a specific inventory slot.
683    pub player_set_slot:  unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, slot: u32, item_id: YogStr, count: u32) -> bool,
684
685    // ── inventory-backed block slots (ABI minor 25, yog-inventory) ──────────
686    /// `"item_id\tcount"` for the given slot of the inventory-backed block at
687    /// `pos`, or NONE if the slot is empty / there is no such inventory there.
688    pub get_inventory_slot: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, slot: u32) -> YogOwnedStr,
689    /// Set (or clear when count==0) a specific slot of the inventory-backed
690    /// block at `pos`. Returns false if there is no such inventory there.
691    pub set_inventory_slot: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, slot: u32, item_id: YogStr, count: u32) -> bool,
692
693    // ── cross-dimension teleport (ABI minor 3) ────────────────────────────────
694    pub player_teleport_dim: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, dim: YogStr, pos: YogVec3) -> bool,
695    pub entity_teleport_dim: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, dim: YogStr, pos: YogVec3) -> bool,
696
697    // ── entity counting ───────────────────────────────────────────────────────
698    /// Count loaded instances of `entity_type` in `dimension`. Returns -1 on error.
699    pub world_entity_count: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, entity_type: YogStr) -> i32,
700
701    // ── entity NBT (ABI minor 6) ──────────────────────────────────────────────
702    /// SNBT of the entity's persistent data, or NONE if entity not found.
703    pub entity_get_nbt: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> YogOwnedStr,
704    /// Merge SNBT data into the entity. Returns false if entity not found.
705    pub entity_set_nbt: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, snbt: YogStr) -> bool,
706
707    // ── particles (ABI minor 6) ───────────────────────────────────────────────
708    /// Spawn `count` particles at `pos` in `dim`.
709    /// `dx/dy/dz` control spread, `speed` controls particle speed.
710    /// Returns false if the dimension or particle type is unknown.
711    pub spawn_particles: unsafe extern "C" fn(
712        ctx: *mut c_void,
713        dim: YogStr,
714        pos: YogVec3,
715        particle_type: YogStr,
716        count: i32,
717        dx: f64, dy: f64, dz: f64,
718        speed: f64,
719    ) -> bool,
720
721    // ── attributes (ABI minor 7) ──────────────────────────────────────────────
722    /// Get the base value of an attribute on a living entity.
723    /// `attribute_id` is a registry id, e.g. `"minecraft:generic.max_health"`.
724    /// Returns `f64::NAN` if entity or attribute is not found.
725    pub entity_attribute_get: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, attribute_id: YogStr) -> f64,
726    /// Set the base value of an attribute. Returns false if entity or attribute is not found.
727    pub entity_attribute_set: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, attribute_id: YogStr, value: f64) -> bool,
728
729    // ── held item NBT (ABI minor 11) ─────────────────────────────────────────
730    /// SNBT of the item currently held in the player's main hand.
731    /// Returns NONE if the player is offline or holding air.
732    pub get_held_item_nbt: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
733    /// Merge `snbt` data into the NBT of the player's held main-hand item in-place.
734    /// Returns false if the player is offline or holding air.
735    pub set_held_item_nbt: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, snbt: YogStr) -> bool,
736
737    // ── item stack query (ABI minor 12) ──────────────────────────────────────
738    /// SNBT of the item in the player's off hand, or NONE if offline / holding air.
739    pub get_offhand_item_nbt: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
740    /// Merge `snbt` into the NBT of the player's off-hand item.
741    /// Returns false if offline or holding air.
742    pub set_offhand_item_nbt: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, snbt: YogStr) -> bool,
743    /// Full item stack at inventory `slot`: tab-separated `item_id\tcount\tsnbt`.
744    /// `snbt` is `{}` when the item has no NBT. Returns NONE if offline or slot empty.
745    pub get_slot_item: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, slot: u32) -> YogOwnedStr,
746    /// Replace inventory `slot` with an item stack. `snbt` may be empty to clear NBT.
747    /// Pass `count == 0` to clear the slot (ignores `item_id` and `snbt`).
748    pub set_slot_item: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, slot: u32, item_id: YogStr, count: u32, snbt: YogStr) -> bool,
749
750    // ── entity rotation (ABI minor 25) ───────────────────────────────────────
751    /// Yaw and pitch (degrees) of an entity by UUID. Returns false if the
752    /// entity does not exist. `out` receives x=yaw, y=pitch, z=0.
753    pub entity_rotation: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut YogVec3) -> bool,
754}
755
756// ctx = *mut JavaVM which is global/stable. All fn ptrs are pure C-ABI.
757unsafe impl Send for YogServer {}
758unsafe impl Sync for YogServer {}
759
760// ── Registration table (passed to yog_mod_register) ──────────────────────────
761
762/// Passed to `yog_mod_register`. Call the function pointers here to register
763/// handlers, commands, content, and schedulers.
764///
765/// When mods compiled against ABI `N` load on a runtime with ABI `M > N`:
766/// fields beyond `size` are not present in the mod's view — check `size` before
767/// accessing fields added in later minor versions.
768#[repr(C)]
769pub struct YogApi {
770    pub abi_version: u32,
771    /// `sizeof(YogApi)` at the runtime's build time.
772    pub size:        u32,
773    /// Opaque pointer to runtime handler storage.
774    pub ctx:         *mut c_void,
775    /// Stable server action table — pass to handlers.
776    pub server:      *const YogServer,
777
778    // ── events — all handlers receive (ud, srv, event, phase: u8) → bool ────────
779    // phase 0 = Pre (return false to cancel), phase 1 = Post (return ignored).
780    pub on_block_break:       unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogBlockBreakFn),
781    pub on_chat:              unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogChatFn),
782    pub on_player_join:       unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerFn),
783    pub on_player_leave:      unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerFn),
784    pub on_use_item:          unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogUseItemFn),
785    pub on_use_block:         unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogUseBlockFn),
786    pub on_attack_entity:     unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogAttackEntityFn),
787    pub on_entity_damage:     unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntityDamageFn),
788    pub on_entity_death:      unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntityDeathFn),
789    pub on_entity_spawn:       unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntitySpawnFn),
790    pub on_player_place_block: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlaceBlockFn),
791    pub on_player_death:       unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerDeathFn),
792    pub on_player_respawn:     unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerRespawnFn),
793    pub on_advancement:        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogAdvancementFn),
794    // ── ABI minor 8 ──────────────────────────────────────────────────────────
795    pub on_entity_interact:    unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntityInteractFn),
796    pub on_item_craft:         unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogCraftFn),
797    pub on_explosion:          unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogExplosionFn),
798    // ── ABI minor 9 ──────────────────────────────────────────────────────────
799    pub on_item_pickup:        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogItemPickupFn),
800    pub on_player_move:        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerMoveFn),
801    pub on_container_open:     unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogContainerOpenFn),
802    pub on_container_close:    unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogContainerCloseFn),
803    pub on_projectile_hit:     unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogProjectileHitFn),
804    pub on_server_tick:       unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogServerFn),
805    pub on_server_started:    unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogServerFn),
806    pub on_server_stopping:   unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogServerFn),
807
808    // ── networking ───────────────────────────────────────────────────────────
809    pub on_packet:        unsafe extern "C" fn(ctx: *mut c_void, channel: YogStr, ud: *mut c_void, h: YogPacketFn),
810    pub on_client_packet: unsafe extern "C" fn(ctx: *mut c_void, channel: YogStr, ud: *mut c_void, h: YogPacketFn),
811
812    // ── commands ─────────────────────────────────────────────────────────────
813    pub register_command: unsafe extern "C" fn(ctx: *mut c_void, name: YogStr, ud: *mut c_void, h: YogCommandFn),
814    pub register_typed_command: unsafe extern "C" fn(ctx: *mut c_void, name: YogStr, schema: YogStr, ud: *mut c_void, h: YogCommandFn),
815
816    // ── recipes ──────────────────────────────────────────────────────────────
817    /// Register a recipe by supplying Minecraft JSON (`data/` format).
818    /// `namespace` + `name` form the file path: `data/{ns}/recipes/{name}.json`.
819    pub register_recipe_json: unsafe extern "C" fn(ctx: *mut c_void, namespace: YogStr, name: YogStr, json: YogStr),
820
821    // ── content ──────────────────────────────────────────────────────────────
822    pub register_item:  unsafe extern "C" fn(ctx: *mut c_void, def: *const YogItemDef),
823    pub register_block: unsafe extern "C" fn(ctx: *mut c_void, def: *const YogBlockDef),
824
825    // ── scheduler ────────────────────────────────────────────────────────────
826    pub schedule_once:      unsafe extern "C" fn(ctx: *mut c_void, delay_ticks: u64, ud: *mut c_void, h: YogScheduledFn),
827    pub schedule_repeating: unsafe extern "C" fn(ctx: *mut c_void, period_ticks: u64, ud: *mut c_void, h: YogScheduledFn),
828
829    // ── ABI minor 10 — client-side events ────────────────────────────────────
830    pub on_client_tick:  unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogClientFn),
831    pub on_hud_render:   unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogHudRenderFn),
832    pub on_key_press:    unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogKeyPressFn),
833    pub on_screen_open:  unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogScreenFn),
834    pub on_screen_close: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogScreenFn),
835
836    // ── ABI minor 14 — world render ──────────────────────────────────────────
837    /// Register a handler that fires after world geometry is rendered.
838    /// `gfx.view_proj` and `gfx.camera_pos` are filled; use them to project
839    /// custom 3D geometry into clip space.
840    pub on_world_render: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogWorldRenderFn),
841
842    // ── ABI minor 16 — startup grants ────────────────────────────────────────
843    pub register_startup_grant: unsafe extern "C" fn(ctx: *mut c_void, grant: *const YogStartupGrantDef),
844
845    // ── ABI minor 18 — books ─────────────────────────────────────────────────
846    pub register_book: unsafe extern "C" fn(ctx: *mut c_void, book_id: YogStr, book_json: YogStr),
847    
848    // ── ABI minor 19 — UI system ──────────────────────────────────────────────
849    /// Register a UI tree. `ui_id` is the unique identifier (e.g. "mymod:menu").
850    /// `layout_json` is the serialized layout tree.
851    /// `handler` is called when an interactive element is clicked/keyed.
852    pub register_ui: unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr, layout_json: YogStr, ud: *mut c_void, h: YogUIEventFn),
853
854    // ── ABI minor 20 — per-UI screen renderer ────────────────────────────────
855    /// Register a render callback that fires during `YogUIScreen.render()` for a
856    /// specific UI id — i.e. AFTER the screen darkening, unlike `on_hud_render`.
857    /// Reuses `YogHudRenderFn` (`fn(ud, gfx)`); `gfx.screen_w/h` are set.
858    /// Clicks are forwarded as `"click:X:Y"` events to the `register_ui` handler
859    /// so mods can do their own hit-testing with their stored layout.
860    pub on_ui_render: unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr, ud: *mut c_void, h: YogHudRenderFn),
861
862    // ── ABI minor 22 — menu entry registration ──────────────────────────────
863    /// Register a button/link that the host renders on vanilla screens
864    /// (TitleScreen on Fabric, ModListScreen on Forge/NeoForge).
865    /// `label` is the human-readable button text (e.g. "Yog Mods").
866    /// `ui_id` is the Yog UI to open when clicked (e.g. "yog:modlist").
867    pub register_menu_entry: unsafe extern "C" fn(ctx: *mut c_void, label: YogStr, ui_id: YogStr),
868
869    // ── ABI minor 23 — installed mods listing ───────────────────────────────
870    /// All installed mods as TSV, one per line:
871    /// `source \t id \t name \t version \t authors \t description`
872    /// where `source` is `yog` (a .yog mod) or `platform` (a loader mod, e.g.
873    /// a Fabric/Forge jar). Tabs and newlines inside fields become spaces.
874    /// Callable at any time after registration (also client-side).
875    pub mods_list: unsafe extern "C" fn(ctx: *mut c_void) -> YogOwnedStr,
876    /// Free a `YogOwnedStr` returned by an api-table call (same allocator as
877    /// `YogServer::free_str`).
878    pub free_str: unsafe extern "C" fn(ptr: *mut u8, len: u32),
879
880    // ── ABI minor 24 — open a Yog UI screen ─────────────────────────────────
881    /// Open the Yog UI registered as `ui_id` on the client (schedules onto the
882    /// render thread). Client-side only; a no-op on dedicated servers.
883    /// `modal` blocks game input; `pause` pauses a singleplayer game.
884    pub ui_open: unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr, modal: bool, pause: bool),
885
886    // ── ABI minor 25 — inventory framework (yog-inventory) ──────────────────
887    /// Register a real Container/Menu inventory screen — see `yog_inventory`.
888    pub register_inventory: unsafe extern "C" fn(ctx: *mut c_void, def: *const YogInventoryDef),
889
890    // ── ABI minor 26 — inter-mod communication ─────────────────────────────
891    /// Export a function pointer under `symbol` for the calling mod (`mod_id`).
892    /// Other mods can import it via `interop_import`.
893    pub interop_export: unsafe extern "C" fn(ctx: *mut c_void, mod_id: YogStr, symbol: YogStr, ptr: *const c_void),
894    /// Import a function pointer exported by `mod_id` under `symbol`.
895    /// Returns null if the symbol is not (yet) registered.
896    pub interop_import: unsafe extern "C" fn(ctx: *mut c_void, mod_id: YogStr, symbol: YogStr) -> *const c_void,
897}
898
899unsafe impl Send for YogApi {}
900unsafe impl Sync for YogApi {}