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; the runtime loads a mod
10//! only when its `ABI_VERSION` is exactly the runtime's.
11
12use std::os::raw::c_void;
13
14// ── Version ──────────────────────────────────────────────────────────────────
15
16pub const ABI_MAJOR: u32 = 1;
17pub const ABI_MINOR: u32 = 5;
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 {
34        ptr: std::ptr::null(),
35        len: 0,
36    };
37
38    /// Borrow `s` — not `FromStr`, which can't return a borrowing value.
39    #[allow(clippy::should_implement_trait)]
40    #[inline]
41    pub fn from_str(s: &str) -> Self {
42        Self {
43            ptr: s.as_ptr(),
44            len: s.len() as u32,
45        }
46    }
47
48    #[inline]
49    pub fn is_empty(self) -> bool {
50        self.len == 0 || self.ptr.is_null()
51    }
52
53    /// # Safety
54    ///
55    /// `ptr` must be valid UTF-8 of `len` bytes for at least the duration of
56    /// the call that provided this `YogStr`.
57    #[inline]
58    pub unsafe fn as_str<'a>(self) -> &'a str {
59        unsafe {
60            if self.ptr.is_null() || self.len == 0 {
61                return "";
62            }
63            std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, self.len as usize))
64        }
65    }
66}
67
68/// Heap-allocated UTF-8 string owned by the RUNTIME.
69/// `ptr == null` encodes `None` / "not found".
70/// When `ptr` is non-null the caller MUST free it via `YogServer::free_str`.
71#[repr(C)]
72#[derive(Copy, Clone)]
73pub struct YogOwnedStr {
74    pub ptr: *mut u8,
75    pub len: u32,
76}
77
78impl YogOwnedStr {
79    pub const NONE: Self = Self {
80        ptr: std::ptr::null_mut(),
81        len: 0,
82    };
83
84    /// Allocate a new `YogOwnedStr` from a Rust `String`.
85    pub fn from_string(s: String) -> Self {
86        let len = s.len() as u32;
87        let ptr = Box::into_raw(s.into_bytes().into_boxed_slice()) as *mut u8;
88        Self { ptr, len }
89    }
90
91    #[inline]
92    pub fn is_none(self) -> bool {
93        self.ptr.is_null()
94    }
95}
96
97/// Integer 3-D block position.
98#[repr(C)]
99#[derive(Copy, Clone)]
100pub struct YogBlockPos {
101    pub x: i32,
102    pub y: i32,
103    pub z: i32,
104}
105
106/// Float 3-D vector (position, velocity, …).
107#[repr(C)]
108#[derive(Copy, Clone)]
109pub struct YogVec3 {
110    pub x: f64,
111    pub y: f64,
112    pub z: f64,
113}
114
115// ── Event structs (Java → Rust) ───────────────────────────────────────────────
116
117#[repr(C)]
118pub struct YogBlockBreakEvent {
119    pub player: YogStr,
120    pub block: YogStr,
121    pub pos: YogBlockPos,
122    /// Dimension the block was broken in, e.g. `minecraft:overworld`.
123    pub dimension: YogStr,
124}
125
126#[repr(C)]
127pub struct YogChatEvent {
128    pub player: YogStr,
129    pub message: YogStr,
130    pub dimension: YogStr,
131}
132
133/// Shared by player_join and player_leave.
134#[repr(C)]
135pub struct YogPlayerEvent {
136    pub player: YogStr,
137    pub uuid: YogStr,
138    pub dimension: YogStr,
139}
140
141#[repr(C)]
142pub struct YogUseItemEvent {
143    pub player: YogStr,
144    pub item: YogStr,
145    /// ABI minor 25: whether the player was sneaking (shift) during use.
146    pub sneaking: bool,
147    pub dimension: YogStr,
148}
149
150#[repr(C)]
151pub struct YogUseBlockEvent {
152    pub player: YogStr,
153    pub block: YogStr,
154    pub pos: YogBlockPos,
155    pub dimension: YogStr,
156}
157
158#[repr(C)]
159pub struct YogAttackEntityEvent {
160    pub player: YogStr,
161    pub target_type: YogStr,
162    pub target_uuid: YogStr,
163    pub dimension: YogStr,
164}
165
166#[repr(C)]
167pub struct YogEntityDamageEvent {
168    pub entity_type: YogStr,
169    pub uuid: YogStr,
170    pub amount: f32,
171    pub source: YogStr,
172    pub dimension: YogStr,
173}
174
175#[repr(C)]
176pub struct YogEntityDeathEvent {
177    pub entity_type: YogStr,
178    pub uuid: YogStr,
179    pub source: YogStr,
180    pub dimension: YogStr,
181}
182
183#[repr(C)]
184pub struct YogEntitySpawnEvent {
185    pub entity_type: YogStr,
186    pub uuid: YogStr,
187    pub dimension: YogStr,
188}
189
190/// Fired when a player dies (Pre: before death is processed; Post: after death).
191/// Pre phase — return false to prevent death (keep entity alive at 0.5 HP).
192#[repr(C)]
193pub struct YogPlayerDeathEvent {
194    pub player: YogStr,
195    pub uuid: YogStr,
196    /// Damage source identifier, e.g. `"player"`, `"fall"`.
197    pub source: YogStr,
198    pub dimension: YogStr,
199}
200
201/// Fired when a player respawns after death.
202#[repr(C)]
203pub struct YogPlayerRespawnEvent {
204    pub player: YogStr,
205    pub uuid: YogStr,
206    /// True if respawning at a bed or anchor, false at world spawn.
207    pub at_anchor: bool,
208    /// Dimension respawned into (may differ from where the player died).
209    pub dimension: YogStr,
210}
211
212/// Fired when a player earns an advancement (Post only).
213#[repr(C)]
214pub struct YogAdvancementEvent {
215    pub player: YogStr,
216    pub uuid: YogStr,
217    /// Namespaced id, e.g. `"minecraft:story/mine_stone"`.
218    pub advancement: YogStr,
219    pub dimension: YogStr,
220}
221
222/// Fired when a player right-clicks (interacts with) an entity (Pre: before; Post: after).
223/// Pre phase — return false to cancel the interaction.
224#[repr(C)]
225pub struct YogEntityInteractEvent {
226    pub player: YogStr,
227    pub player_uuid: YogStr,
228    pub entity_type: YogStr,
229    pub entity_uuid: YogStr,
230    /// `"main_hand"` or `"off_hand"`.
231    pub hand: YogStr,
232    pub dimension: YogStr,
233}
234
235/// Fired when a player takes a crafted item from a crafting output slot (Post only).
236#[repr(C)]
237pub struct YogCraftEvent {
238    pub player: YogStr,
239    pub player_uuid: YogStr,
240    pub result_item: YogStr,
241    pub result_count: u32,
242    pub dimension: YogStr,
243}
244
245/// Fired when an explosion occurs in a world (Pre: before block destruction; Post: after).
246/// Pre phase — return false to cancel the explosion (block and entity damage suppressed).
247#[repr(C)]
248pub struct YogExplosionEvent {
249    pub dimension: YogStr,
250    pub x: f64,
251    pub y: f64,
252    pub z: f64,
253    pub power: f32,
254    /// UUID of the entity that caused the explosion, or empty if world/tnt.
255    pub cause_uuid: YogStr,
256}
257
258// ── ABI minor 9–10 event structs ──────────────────────────────────────────────
259
260/// Fired when a player picks up an item entity (Pre: cancellable; Post: informational).
261#[repr(C)]
262pub struct YogItemPickupEvent {
263    pub player: YogStr,
264    pub player_uuid: YogStr,
265    /// Registry id of the item, e.g. `"minecraft:diamond"`.
266    pub item_id: YogStr,
267    pub item_count: u32,
268    /// UUID of the item entity that was picked up.
269    pub entity_uuid: YogStr,
270    pub dimension: YogStr,
271}
272
273/// Fired when a player sends a movement packet (Post only; very high frequency).
274#[repr(C)]
275pub struct YogPlayerMoveEvent {
276    pub player: YogStr,
277    pub player_uuid: YogStr,
278    pub x: f64,
279    pub y: f64,
280    pub z: f64,
281    pub yaw: f32,
282    pub pitch: f32,
283    pub dimension: YogStr,
284}
285
286/// Fired when a player opens a container screen (Pre: cancellable; Post: informational).
287/// `container_type` is the screen handler registry id, e.g. `"minecraft:chest"`.
288/// Empty string if the type is not in the registry (e.g. the player inventory).
289#[repr(C)]
290pub struct YogContainerOpenEvent {
291    pub player: YogStr,
292    pub player_uuid: YogStr,
293    pub container_type: YogStr,
294    pub dimension: YogStr,
295}
296
297/// Fired when a player closes a container screen (Post only).
298#[repr(C)]
299pub struct YogContainerCloseEvent {
300    pub player: YogStr,
301    pub player_uuid: YogStr,
302    pub dimension: YogStr,
303}
304
305/// Fired when a persistent projectile (arrow, trident) hits a target (Pre: cancellable).
306/// Pre phase — return false to cancel the hit (projectile passes through).
307#[repr(C)]
308pub struct YogProjectileHitEvent {
309    /// Registry id of the projectile, e.g. `"minecraft:arrow"`.
310    pub projectile_type: YogStr,
311    pub projectile_uuid: YogStr,
312    /// UUID of the entity that shot/threw this projectile, or empty.
313    pub shooter_uuid: YogStr,
314    /// `"block"` or `"entity"`.
315    pub hit_type: YogStr,
316    /// UUID of the entity that was hit (empty for block hits).
317    pub hit_entity_uuid: YogStr,
318    pub x: f64,
319    pub y: f64,
320    pub z: f64,
321    pub dimension: YogStr,
322}
323
324/// Fired when a player places a block (Pre: before placement; Post: after).
325#[repr(C)]
326pub struct YogPlaceBlockEvent {
327    pub player: YogStr,
328    pub block: YogStr,
329    pub pos: YogBlockPos,
330    pub dimension: YogStr,
331}
332
333#[repr(C)]
334pub struct YogPacketEvent {
335    pub channel: YogStr,
336    pub player: YogStr, // empty string on client-received packets
337    pub payload: *const u8,
338    pub payload_len: u32,
339}
340
341#[repr(C)]
342pub struct YogCommandEvent {
343    pub name: YogStr,
344    pub args: YogStr,
345    pub source: YogStr,
346    pub uuid: YogStr,
347    /// Empty for console-run commands (no world).
348    pub dimension: YogStr,
349}
350
351/// A startup grant definition — items/books to give on first join.
352#[repr(C)]
353pub struct YogStartupGrantDef {
354    pub id: YogStr,
355    pub items: YogStr,   // '|'-separated item ids
356    pub book: YogStr,    // empty = none
357    pub command: YogStr, // empty = none
358}
359
360// ── Content definition structs (mod → runtime) ────────────────────────────────
361
362#[repr(C)]
363pub struct YogItemDef {
364    pub id: YogStr,
365    pub max_stack: u32,
366    pub name: YogStr,    // empty = no override
367    pub tooltip: YogStr, // empty = none
368    pub max_damage: u32,
369    pub fire_resistant: bool,
370    pub fuel_ticks: u32,
371    pub food_nutrition: u32, // 0 = not a food item
372    pub food_saturation: f32,
373    pub food_always_eat: bool,
374}
375
376#[repr(C)]
377pub struct YogBlockDef {
378    pub id: YogStr,
379    pub hardness: f32,
380    pub resistance: f32,
381    pub name: YogStr,
382    pub light_level: u8,
383    pub sound: YogStr, // empty = default stone sound
384    pub requires_tool: bool,
385    pub no_collision: bool,
386    pub slipperiness: f32,
387    /// Bounding box in pixels: `[x1, y1, z1, x2, y2, z2]`. All zeros = full cube.
388    pub shape: [f32; 6],
389    /// Fence/pipe-style dynamic arm growth toward compatible neighbors — see
390    /// `yog_registry::BlockDef::connects_to_neighbors`.
391    pub connects: bool,
392    /// Comma-joined connection compatibility tags — see
393    /// `yog_registry::BlockDef::connect_groups`. Empty = no tags.
394    pub connect_groups: YogStr,
395    /// Id of a `YogInventoryDef` (registered via `register_inventory`) this
396    /// block is backed by — empty = no inventory (plain block, as before).
397    /// See `yog_inventory`'s DESIGN.md.
398    pub inventory_id: YogStr,
399    /// ABI minor 3: gives off redstone power (`Server::set_redstone_output`).
400    pub redstone_source: bool,
401}
402
403/// An inventory-backed screen definition — see `yog_inventory::InventoryDef`.
404#[repr(C)]
405pub struct YogInventoryDef {
406    pub id: YogStr,
407    pub slot_count: u32,
408    /// `"x:y,x:y,..."` — one pair per slot, in slot-index order. Empty =
409    /// use the default vanilla-style grid (see `yog_inventory::InventoryDef::default_grid`).
410    pub layout: YogStr,
411    pub include_player_inventory: bool,
412    pub player_inv_x: f32,
413    pub player_inv_y: f32,
414    /// Empty = default vanilla-style panel texture.
415    pub background_texture: YogStr,
416    pub title: YogStr,
417    /// Screen size to center the container on — `0.0` (either field) means
418    /// "use the vanilla default (176×166)". Set this to whatever a custom
419    /// `on_ui_render` overlay actually occupies so the real vanilla `Slot`s
420    /// (positioned by `layout`/`player_inv_x/y` relative to `guiLeft`/`guiTop`)
421    /// land under the matching decoration the overlay draws, instead of the
422    /// two disagreeing about where the container's top-left corner is.
423    pub background_w: f32,
424    pub background_h: f32,
425}
426
427// ── ABI minor 10 client event structs ─────────────────────────────────────────
428
429/// Key press / release / repeat from the keyboard (client-side only).
430#[repr(C)]
431#[derive(Copy, Clone)]
432pub struct YogKeyPressEvent {
433    /// GLFW key code (e.g. `GLFW_KEY_E = 69`).
434    pub key_code: i32,
435    pub scan_code: i32,
436    /// 0 = release, 1 = press, 2 = repeat.
437    pub action: i32,
438    /// Modifier bitmask: 1=shift, 2=ctrl, 4=alt, 8=super.
439    pub modifiers: i32,
440}
441
442// ── Handler function-pointer types ────────────────────────────────────────────
443//
444// All event handlers receive a `phase: u8` argument:
445//   0 = Pre  — fires before the action; return value matters (false = cancel).
446//   1 = Post — fires after the action; return value is ignored.
447//
448// This unified signature lets one registered closure handle both phases.
449//
450// Client-side handlers (minor 10) do NOT receive a `YogServer*` — they run on
451// the render thread and have no server context.
452
453pub type YogBlockBreakFn =
454    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogBlockBreakEvent, u8) -> bool;
455pub type YogChatFn =
456    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogChatEvent, u8) -> bool;
457pub type YogPlayerFn =
458    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerEvent, u8) -> bool;
459pub type YogUseItemFn =
460    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogUseItemEvent, u8) -> bool;
461pub type YogUseBlockFn =
462    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogUseBlockEvent, u8) -> bool;
463pub type YogAttackEntityFn =
464    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogAttackEntityEvent, u8) -> bool;
465pub type YogEntityDamageFn =
466    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntityDamageEvent, u8) -> bool;
467pub type YogEntityDeathFn =
468    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntityDeathEvent, u8) -> bool;
469pub type YogEntitySpawnFn =
470    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntitySpawnEvent, u8) -> bool;
471pub type YogPlaceBlockFn =
472    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlaceBlockEvent, u8) -> bool;
473pub type YogPlayerDeathFn =
474    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerDeathEvent, u8) -> bool;
475pub type YogPlayerRespawnFn =
476    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerRespawnEvent, u8) -> bool;
477pub type YogAdvancementFn =
478    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogAdvancementEvent, u8) -> bool;
479pub type YogEntityInteractFn =
480    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogEntityInteractEvent, u8) -> bool;
481pub type YogCraftFn =
482    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogCraftEvent, u8) -> bool;
483pub type YogExplosionFn =
484    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogExplosionEvent, u8) -> bool;
485pub type YogItemPickupFn =
486    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogItemPickupEvent, u8) -> bool;
487pub type YogPlayerMoveFn =
488    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPlayerMoveEvent, u8) -> bool;
489pub type YogContainerOpenFn =
490    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogContainerOpenEvent, u8) -> bool;
491pub type YogContainerCloseFn =
492    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogContainerCloseEvent, u8) -> bool;
493pub type YogProjectileHitFn =
494    unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogProjectileHitEvent, u8) -> bool;
495
496/// Packet events — always Post, no phase.
497pub type YogPacketFn = unsafe extern "C" fn(*mut c_void, *const YogServer, *const YogPacketEvent);
498/// Server lifecycle / tick — no event struct, always fires.
499pub type YogServerFn = unsafe extern "C" fn(*mut c_void, *const YogServer);
500/// Command handler.
501pub type YogCommandFn = unsafe extern "C" fn(
502    ud: *mut c_void,
503    srv: *const YogServer,
504    ev: *const YogCommandEvent,
505    reply_buf: *mut u8,
506    reply_cap: u32,
507    reply_len: *mut u32,
508);
509/// Scheduler handler (once or repeating).
510pub type YogScheduledFn = unsafe extern "C" fn(*mut c_void, *const YogServer);
511
512// ── ABI minor 10 — client-side function pointer types ────────────────────────
513
514/// Client tick — no event, no server context.
515pub type YogClientFn = unsafe extern "C" fn(ud: *mut c_void);
516/// UI event for a `register_ui` screen. `event_id` is one of
517/// `click:X:Y`, `drag:X:Y`, `release:X:Y`, `scroll:DY` and (ABI minor 33)
518/// `key:KEY:MODS` — a GLFW key code pressed or repeating, with GLFW modifier
519/// bits — and `char:CODEPOINT` — a typed character (Unicode scalar value).
520/// Call `YogApi::ui_consume_event` while handling `key:`/`char:` to stop the
521/// host's default handling of that key (Esc closing the screen, ...).
522pub type YogUIEventFn = unsafe extern "C" fn(ud: *mut c_void, ui_id: YogStr, event_id: YogStr);
523/// HUD render — `gfx` is the graphics context for this frame; only valid for
524/// the call duration.  `draw2d_*` functions in `gfx` work here.
525pub type YogHudRenderFn = unsafe extern "C" fn(ud: *mut c_void, gfx: *const YogGfxApi);
526/// World render — `gfx` contains `view_proj` and `camera_pos` for 3D rendering.
527/// Valid only for the call duration.
528pub type YogWorldRenderFn = unsafe extern "C" fn(ud: *mut c_void, gfx: *const YogGfxApi);
529/// Key press — return `false` to cancel (prevent Minecraft from processing the key).
530pub type YogKeyPressFn = unsafe extern "C" fn(ud: *mut c_void, ev: *const YogKeyPressEvent) -> bool;
531/// Screen event — `screen_class` is the simple class name (e.g. `"InventoryScreen"`).
532/// For `on_screen_open` return `false` to prevent the screen from opening.
533pub type YogScreenFn = unsafe extern "C" fn(ud: *mut c_void, screen_class: YogStr) -> bool;
534
535// ── ABI minor 14 — low-level GPU pipeline ────────────────────────────────────
536
537/// Low-level GPU context passed to render handlers.
538///
539/// Provides direct access to the OpenGL pipeline: buffer objects, vertex arrays,
540/// shader programs, textures, draw calls, and render state.
541///
542/// The per-frame fields (`screen_w/h`, `delta_tick`, `view_proj`, `camera_pos`)
543/// are filled by the runtime before calling the handler; the function pointers
544/// point to statically-allocated implementations.
545///
546/// Valid only for the duration of the render callback — never store the pointer.
547/// GPU resource **handles** (`u32`) may be stored between frames.
548///
549/// Colors are `0xAARRGGBB` (Minecraft convention).
550#[repr(C)]
551#[derive(Copy, Clone)]
552pub struct YogGfxApi {
553    // ── Per-frame context ─────────────────────────────────────────────────────
554    /// GUI-pixel screen width.
555    pub screen_w: i32,
556    /// GUI-pixel screen height.
557    pub screen_h: i32,
558    /// Partial-tick interpolation factor (0.0–1.0).
559    pub delta_tick: f32,
560    /// GUI scale factor: physical pixels per GUI pixel (e.g. 2.0 for 2× GUI scale).
561    /// Useful for converting GUI-pixel coordinates to physical pixels for OpenGL calls.
562    pub scale_factor: f32,
563    /// View-projection matrix in camera-relative space (column-major, 16 × f32).
564    /// All zeros during `on_hud_render`; filled during `on_world_render`.
565    pub view_proj: [f32; 16],
566    /// Camera world-space position.  All zeros during `on_hud_render`.
567    pub camera_pos: [f32; 3],
568    /// Local player world-space position (eye height).  All zeros during `on_hud_render`.
569    /// Differs from `camera_pos` in third-person view.
570    pub player_pos: [f32; 3],
571    pub _pad1: f32,
572
573    // ── GPU buffers ───────────────────────────────────────────────────────────
574    /// Allocate a new GPU buffer (VBO / EBO). Returns 0 on failure.
575    pub buf_create: unsafe extern "C" fn() -> u32,
576    /// Delete a buffer created by `buf_create`.
577    pub buf_delete: unsafe extern "C" fn(handle: u32),
578    /// Upload `len` bytes from `bytes` into `handle`.
579    /// `dynamic`: hints frequent updates (`GL_DYNAMIC_DRAW` vs `GL_STATIC_DRAW`).
580    pub buf_data: unsafe extern "C" fn(handle: u32, bytes: *const u8, len: u32, dynamic: bool),
581    /// Overwrite `len` bytes at `offset` in `handle`.
582    pub buf_subdata: unsafe extern "C" fn(handle: u32, offset: u32, bytes: *const u8, len: u32),
583
584    // ── Vertex arrays ─────────────────────────────────────────────────────────
585    /// Create a vertex array object. Returns 0 on failure.
586    pub vao_create: unsafe extern "C" fn() -> u32,
587    /// Delete a VAO created by `vao_create`.
588    pub vao_delete: unsafe extern "C" fn(handle: u32),
589    /// Declare one vertex attribute in `vao`, sourced from `vbo`.
590    /// `dtype`: 0=f32, 1=u8, 2=i32, 3=u32.
591    pub vao_attrib: unsafe extern "C" fn(
592        vao: u32,
593        vbo: u32,
594        index: u32,
595        components: u8,
596        dtype: u8,
597        normalized: bool,
598        stride: u32,
599        offset: u32,
600    ),
601    /// Bind an index buffer (EBO) to `vao`.
602    pub vao_set_ebo: unsafe extern "C" fn(vao: u32, ebo: u32),
603
604    // ── Shader programs ───────────────────────────────────────────────────────
605    /// Compile + link `vert_src` / `frag_src` (GLSL 150 core).
606    /// Writes the program handle to `*out`. Returns false and logs on error.
607    pub prog_create: unsafe extern "C" fn(vert: YogStr, frag: YogStr, out: *mut u32) -> bool,
608    /// Delete a shader program.
609    pub prog_delete: unsafe extern "C" fn(handle: u32),
610    pub prog_uniform_1i: unsafe extern "C" fn(prog: u32, name: YogStr, v: i32),
611    pub prog_uniform_1f: unsafe extern "C" fn(prog: u32, name: YogStr, v: f32),
612    pub prog_uniform_2f: unsafe extern "C" fn(prog: u32, name: YogStr, x: f32, y: f32),
613    pub prog_uniform_3f: unsafe extern "C" fn(prog: u32, name: YogStr, x: f32, y: f32, z: f32),
614    pub prog_uniform_4f:
615        unsafe extern "C" fn(prog: u32, name: YogStr, x: f32, y: f32, z: f32, w: f32),
616    /// Set a mat4 uniform from 16 column-major floats.
617    pub prog_uniform_mat4: unsafe extern "C" fn(prog: u32, name: YogStr, col_major: *const f32),
618
619    // ── Textures ──────────────────────────────────────────────────────────────
620    /// Upload RGBA8 pixel data as a new texture.
621    /// `linear`: `GL_LINEAR` if true, `GL_NEAREST` if false.
622    pub tex_create: unsafe extern "C" fn(w: u32, h: u32, rgba: *const u8, linear: bool) -> u32,
623    /// Delete a texture created by `tex_create`.
624    pub tex_delete: unsafe extern "C" fn(handle: u32),
625    /// Bind `handle` to texture unit `unit` (0–7).
626    pub tex_bind: unsafe extern "C" fn(unit: u32, handle: u32),
627    /// Return the GL texture handle Minecraft uses for a namespaced resource
628    /// (e.g. `"minecraft:textures/gui/icons.png"`). Returns 0 if not found.
629    /// Do **not** delete handles obtained this way — Minecraft owns them.
630    pub tex_from_mc: unsafe extern "C" fn(id: YogStr) -> u32,
631
632    // ── Draw calls ────────────────────────────────────────────────────────────
633    /// Draw `count` primitives from `vao`, using shader `prog`.
634    /// `mode`: 0=Triangles, 1=Lines, 2=LineStrip, 3=TriangleStrip, 4=TriangleFan.
635    pub draw_arrays: unsafe extern "C" fn(vao: u32, prog: u32, mode: u8, first: u32, count: u32),
636    /// Draw indexed primitives.  `ebo` must be bound to `vao` via `vao_set_ebo`.
637    /// `u32_idx`: `true` for `u32` indices, `false` for `u16` indices.
638    pub draw_elements:
639        unsafe extern "C" fn(vao: u32, ebo: u32, prog: u32, mode: u8, count: u32, u32_idx: bool),
640
641    // ── Render state ──────────────────────────────────────────────────────────
642    /// Enable/disable blending. `src`/`dst` are raw GL blend factor enum values.
643    pub set_blend: unsafe extern "C" fn(enabled: bool, src: u32, dst: u32),
644    /// Enable/disable depth testing and depth writes.
645    pub set_depth: unsafe extern "C" fn(test: bool, write: bool),
646    /// Enable scissor clipping (GUI-pixel rectangle).
647    pub set_scissor: unsafe extern "C" fn(x: i32, y: i32, w: i32, h: i32),
648    /// Disable scissor clipping.
649    pub clear_scissor: unsafe extern "C" fn(),
650    /// Set the GL viewport (physical pixel coordinates).
651    pub set_viewport: unsafe extern "C" fn(x: i32, y: i32, w: i32, h: i32),
652
653    // ── 2D convenience (HUD-render only — uses MC's DrawContext) ─────────────
654    /// Filled rectangle. Only valid during `on_hud_render`.
655    pub draw2d_rect: unsafe extern "C" fn(x1: f32, y1: f32, x2: f32, y2: f32, color: u32),
656    /// Vertical-gradient rectangle. Only valid during `on_hud_render`.
657    pub draw2d_gradient:
658        unsafe extern "C" fn(x1: f32, y1: f32, x2: f32, y2: f32, top: u32, bottom: u32),
659    /// MC text renderer string. Only valid during `on_hud_render`.
660    pub draw2d_text: unsafe extern "C" fn(text: YogStr, x: f32, y: f32, color: u32, shadow: bool),
661
662    // ── appended in ABI minor 21 ──────────────────────────────────────────────
663    /// Render an item stack (3D block models included) via MC's item renderer,
664    /// like Patchouli's `renderItemStack`. `id` is a registry item id
665    /// ("minecraft:crafting_table"); `size` is the on-screen size in GUI px
666    /// (16 = inventory size). Only valid during `on_hud_render`.
667    pub draw2d_item: unsafe extern "C" fn(id: YogStr, x: f32, y: f32, size: f32),
668
669    // ── appended in ABI minor 33 ──────────────────────────────────────────────
670    /// `draw2d_text` in the font `font` — a font id such as
671    /// `"minecraft:default"`, `"minecraft:uniform"`, `"minecraft:alt"` or a
672    /// resource-pack font (`"mymod:fancy"`); empty = the default font. Only
673    /// valid during a render callback.
674    pub draw2d_text_font:
675        unsafe extern "C" fn(text: YogStr, font: YogStr, x: f32, y: f32, color: u32, shadow: bool),
676    /// Width in GUI pixels of `text` drawn in `font` (empty = default), as the
677    /// host's text renderer measures it. Callable from the render thread at
678    /// any time (render callbacks and UI event handlers); the pointer stays
679    /// valid for the life of the process.
680    pub text_width: unsafe extern "C" fn(text: YogStr, font: YogStr) -> f32,
681
682    // ── appended in ABI minor 34 ──────────────────────────────────────────────
683    /// Draw the image `source` — a Yog image source (`item:apple`,
684    /// `block:stone`, `sprite:button`, `mymod:gui/logo`, ...; see
685    /// `yog_gfx::image`), resolved by the host for its Minecraft version —
686    /// scaled into `(x, y, w, h)` (GUI pixels, nearest-neighbour). `(u, v,
687    /// uw, vh)` is the part of the image to draw, in the image's own pixels;
688    /// `uw <= 0` or `vh <= 0` = the whole image (items and sprites are
689    /// always whole). `tint` multiplies the colors (`0xAARRGGBB`;
690    /// `0xFFFFFFFF` = none; items ignore it). Only valid during a render
691    /// callback.
692    pub draw2d_image: unsafe extern "C" fn(
693        source: YogStr,
694        x: f32,
695        y: f32,
696        w: f32,
697        h: f32,
698        u: f32,
699        v: f32,
700        uw: f32,
701        vh: f32,
702        tint: u32,
703    ),
704    /// Natural size in GUI pixels of the image `source` (16×16 for items, a
705    /// texture's pixel size, ...) into `*w`/`*h`. `false` (outputs untouched)
706    /// when the source can't be resolved. Callable from the render thread at
707    /// any time; the pointer stays valid for the life of the process.
708    pub image_size: unsafe extern "C" fn(source: YogStr, w: *mut f32, h: *mut f32) -> bool,
709
710    // ── ABI 1.4 ──────────────────────────────────────────────────────────────
711    /// Draws the SVG document `data` scaled into `(x, y, w, h)` GUI pixels
712    /// (rasterized by the host at the screen's resolution, cached).
713    pub draw2d_svg: unsafe extern "C" fn(data: YogStr, x: f32, y: f32, w: f32, h: f32),
714    /// Draws a living entity of type `entity` (`minecraft:zombie`) standing
715    /// in `(x, y, w, h)` GUI pixels, as big as fits, turned `yaw` degrees
716    /// (0 = facing the viewer) and tilted `pitch` degrees.
717    pub draw2d_entity:
718        unsafe extern "C" fn(entity: YogStr, x: f32, y: f32, w: f32, h: f32, yaw: f32, pitch: f32),
719
720    // ── ABI 1.5 ──────────────────────────────────────────────────────────────
721    /// Draws `text` in `font` (empty = default) at `(x, y)`, `scale` times
722    /// its size.
723    pub draw2d_text_scaled: unsafe extern "C" fn(
724        text: YogStr,
725        font: YogStr,
726        x: f32,
727        y: f32,
728        scale: f32,
729        color: u32,
730        shadow: bool,
731    ),
732    /// Draws blocks in 3D, as big as fits in `(x, y, w, h)`: `blocks` is one
733    /// `x y z state` line per block (`0 0 0 minecraft:furnace[facing=north]`),
734    /// turned `yaw` degrees about the vertical and tilted `pitch` degrees.
735    pub draw2d_blocks:
736        unsafe extern "C" fn(blocks: YogStr, x: f32, y: f32, w: f32, h: f32, yaw: f32, pitch: f32),
737}
738
739unsafe impl Send for YogGfxApi {}
740unsafe impl Sync for YogGfxApi {}
741
742// ── Server action table (runtime → mod direction is wrong; it's mod → runtime) ─
743
744/// All Minecraft-mutating calls available inside a handler.
745///
746/// `ctx` is an opaque pointer to the runtime's JNI state.  Every function takes
747/// it as its first argument.  The pointer is valid for the lifetime of the process.
748///
749/// Strings **returned** by functions in this table are heap-allocated by the
750/// runtime and must be freed with `free_str` after the caller has read them.
751#[repr(C)]
752pub struct YogServer {
753    pub ctx: *mut c_void,
754    pub abi_version: u32,
755    /// `sizeof(YogServer)` at build time — allows mods compiled against an older
756    /// table to detect and skip fields they don't know about.
757    pub size: u32,
758
759    /// Free a string returned by any function in this table.
760    pub free_str: unsafe extern "C" fn(ptr: *mut u8, len: u32),
761
762    // ── chat ─────────────────────────────────────────────────────────────────
763    pub broadcast: unsafe extern "C" fn(ctx: *mut c_void, msg: YogStr),
764
765    // ── world ────────────────────────────────────────────────────────────────
766    pub get_block:
767        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> YogOwnedStr,
768    pub set_block: unsafe extern "C" fn(
769        ctx: *mut c_void,
770        dim: YogStr,
771        pos: YogBlockPos,
772        block: YogStr,
773    ) -> bool,
774    pub world_time: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, out: *mut i64) -> bool,
775    pub set_time: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, time: i64) -> bool,
776    pub is_raining: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr) -> bool,
777    pub set_weather:
778        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, raining: bool, dur: i32) -> bool,
779
780    // ── player ───────────────────────────────────────────────────────────────
781    pub give_item:
782        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, item: YogStr, count: u32) -> bool,
783    pub player_teleport:
784        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, pos: YogVec3) -> bool,
785    pub send_to_player: unsafe extern "C" fn(
786        ctx: *mut c_void,
787        player: YogStr,
788        channel: YogStr,
789        data: *const u8,
790        len: u32,
791    ) -> bool,
792    pub send_to_server:
793        unsafe extern "C" fn(ctx: *mut c_void, channel: YogStr, data: *const u8, len: u32) -> bool,
794    pub kick_player: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, reason: YogStr) -> bool,
795    pub set_gamemode: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, mode: YogStr) -> bool,
796    pub send_title: unsafe extern "C" fn(
797        ctx: *mut c_void,
798        player: YogStr,
799        title: YogStr,
800        sub: YogStr,
801        fi: i32,
802        stay: i32,
803        fo: i32,
804    ) -> bool,
805    pub send_actionbar: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, msg: YogStr) -> bool,
806    pub play_sound: unsafe extern "C" fn(
807        ctx: *mut c_void,
808        dim: YogStr,
809        pos: YogVec3,
810        sound: YogStr,
811        vol: f32,
812        pitch: f32,
813    ) -> bool,
814    pub play_sound_player: unsafe extern "C" fn(
815        ctx: *mut c_void,
816        player: YogStr,
817        sound: YogStr,
818        vol: f32,
819        pitch: f32,
820    ) -> bool,
821
822    // ── entity ───────────────────────────────────────────────────────────────
823    pub entity_teleport: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, pos: YogVec3) -> bool,
824    pub entity_position:
825        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut YogVec3) -> bool,
826    pub entity_health: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut f32) -> bool,
827    pub entity_set_health: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, hp: f32) -> bool,
828    pub entity_kill: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> bool,
829    pub spawn_entity: unsafe extern "C" fn(
830        ctx: *mut c_void,
831        type_id: YogStr,
832        dim: YogStr,
833        pos: YogVec3,
834    ) -> YogOwnedStr,
835    pub entity_add_effect: unsafe extern "C" fn(
836        ctx: *mut c_void,
837        uuid: YogStr,
838        fx: YogStr,
839        dur: i32,
840        amp: u8,
841        particles: bool,
842    ) -> bool,
843    pub entity_remove_effect:
844        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, fx: YogStr) -> bool,
845    pub entity_clear_effects: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> bool,
846    pub entity_velocity:
847        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut YogVec3) -> bool,
848    pub entity_set_velocity:
849        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, vel: YogVec3) -> bool,
850    pub entity_add_velocity:
851        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, vel: YogVec3) -> bool,
852
853    // ── tags & loot ──────────────────────────────────────────────────────────
854    pub has_item_tag: unsafe extern "C" fn(ctx: *mut c_void, item: YogStr, tag: YogStr) -> bool,
855    pub has_block_tag: unsafe extern "C" fn(ctx: *mut c_void, block: YogStr, tag: YogStr) -> bool,
856    pub drop_loot:
857        unsafe extern "C" fn(ctx: *mut c_void, table: YogStr, dim: YogStr, pos: YogVec3) -> bool,
858
859    // ── scoreboard ───────────────────────────────────────────────────────────
860    pub scoreboard_get:
861        unsafe extern "C" fn(ctx: *mut c_void, obj: YogStr, player: YogStr, out: *mut i32) -> bool,
862    pub scoreboard_set:
863        unsafe extern "C" fn(ctx: *mut c_void, obj: YogStr, player: YogStr, score: i32) -> bool,
864    pub scoreboard_add: unsafe extern "C" fn(
865        ctx: *mut c_void,
866        obj: YogStr,
867        player: YogStr,
868        delta: i32,
869        out: *mut i32,
870    ) -> bool,
871
872    // ── boss bar ─────────────────────────────────────────────────────────────
873    pub bossbar_create: unsafe extern "C" fn(
874        ctx: *mut c_void,
875        id: YogStr,
876        title: YogStr,
877        color: YogStr,
878        style: YogStr,
879    ) -> bool,
880    pub bossbar_remove: unsafe extern "C" fn(ctx: *mut c_void, id: YogStr) -> bool,
881    pub bossbar_set_title:
882        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, title: YogStr) -> bool,
883    pub bossbar_set_progress:
884        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, progress: f32) -> bool,
885    pub bossbar_set_color:
886        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, color: YogStr) -> bool,
887    pub bossbar_add_player:
888        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, player: YogStr) -> bool,
889    pub bossbar_remove_player:
890        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, player: YogStr) -> bool,
891    pub bossbar_set_visible:
892        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, visible: bool) -> bool,
893
894    // ── misc ─────────────────────────────────────────────────────────────────
895    pub game_dir: unsafe extern "C" fn(ctx: *mut c_void) -> YogOwnedStr,
896
897    // ── player query (ABI minor 4) ────────────────────────────────────────────
898    /// Newline-separated list of online player names, or NONE if server not up.
899    pub online_players: unsafe extern "C" fn(ctx: *mut c_void) -> YogOwnedStr,
900
901    // ── block entity (NBT, ABI minor 3) ──────────────────────────────────────
902    /// SNBT string of the block entity at `pos`, or NONE if there is none.
903    pub get_block_nbt:
904        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> YogOwnedStr,
905    /// Write SNBT into the block entity at `pos`. Returns false if no block entity exists.
906    pub set_block_nbt:
907        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, snbt: YogStr) -> bool,
908
909    // ── inventory (ABI minor 3) ───────────────────────────────────────────────
910    /// Tab/newline-encoded inventory: one line per occupied slot, `slot\titem_id\tcount`.
911    pub player_inventory: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
912    /// Set (or clear when count==0) a specific inventory slot.
913    pub player_set_slot: unsafe extern "C" fn(
914        ctx: *mut c_void,
915        player: YogStr,
916        slot: u32,
917        item_id: YogStr,
918        count: u32,
919    ) -> bool,
920
921    // ── inventory-backed block slots (ABI minor 25, yog-inventory) ──────────
922    /// `"item_id\tcount\tsnbt"` for the given slot of the block container
923    /// at `pos`, or NONE if the slot is empty / there's no container there.
924    pub get_inventory_slot: unsafe extern "C" fn(
925        ctx: *mut c_void,
926        dim: YogStr,
927        pos: YogBlockPos,
928        slot: u32,
929    ) -> YogOwnedStr,
930    /// Set (or clear when count==0) a slot of the block container at `pos`;
931    /// `item_id` may carry the item's SNBT after a tab. Returns false if
932    /// there's no container there.
933    pub set_inventory_slot: unsafe extern "C" fn(
934        ctx: *mut c_void,
935        dim: YogStr,
936        pos: YogBlockPos,
937        slot: u32,
938        item_id: YogStr,
939        count: u32,
940    ) -> bool,
941
942    // ── cross-dimension teleport (ABI minor 3) ────────────────────────────────
943    pub player_teleport_dim:
944        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, dim: YogStr, pos: YogVec3) -> bool,
945    pub entity_teleport_dim:
946        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, dim: YogStr, pos: YogVec3) -> bool,
947
948    // ── entity counting ───────────────────────────────────────────────────────
949    /// Count loaded instances of `entity_type` in `dimension`. Returns -1 on error.
950    pub world_entity_count:
951        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, entity_type: YogStr) -> i32,
952
953    // ── entity NBT (ABI minor 6) ──────────────────────────────────────────────
954    /// SNBT of the entity's persistent data, or NONE if entity not found.
955    pub entity_get_nbt: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> YogOwnedStr,
956    /// Merge SNBT data into the entity. Returns false if entity not found.
957    pub entity_set_nbt: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, snbt: YogStr) -> bool,
958
959    // ── particles (ABI minor 6) ───────────────────────────────────────────────
960    /// Spawn `count` particles at `pos` in `dim`.
961    /// `dx/dy/dz` control spread, `speed` controls particle speed.
962    /// Returns false if the dimension or particle type is unknown.
963    pub spawn_particles: unsafe extern "C" fn(
964        ctx: *mut c_void,
965        dim: YogStr,
966        pos: YogVec3,
967        particle_type: YogStr,
968        count: i32,
969        dx: f64,
970        dy: f64,
971        dz: f64,
972        speed: f64,
973    ) -> bool,
974
975    // ── attributes (ABI minor 7) ──────────────────────────────────────────────
976    /// Get the base value of an attribute on a living entity.
977    /// `attribute_id` is a registry id, e.g. `"minecraft:generic.max_health"`.
978    /// Returns `f64::NAN` if entity or attribute is not found.
979    pub entity_attribute_get:
980        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, attribute_id: YogStr) -> f64,
981    /// Set the base value of an attribute. Returns false if entity or attribute is not found.
982    pub entity_attribute_set: unsafe extern "C" fn(
983        ctx: *mut c_void,
984        uuid: YogStr,
985        attribute_id: YogStr,
986        value: f64,
987    ) -> bool,
988
989    // ── held item NBT (ABI minor 11) ─────────────────────────────────────────
990    /// SNBT of the item currently held in the player's main hand.
991    /// Returns NONE if the player is offline or holding air.
992    pub get_held_item_nbt: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
993    /// Merge `snbt` data into the NBT of the player's held main-hand item in-place.
994    /// Returns false if the player is offline or holding air.
995    pub set_held_item_nbt:
996        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, snbt: YogStr) -> bool,
997
998    // ── item stack query (ABI minor 12) ──────────────────────────────────────
999    /// SNBT of the item in the player's off hand, or NONE if offline / holding air.
1000    pub get_offhand_item_nbt: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
1001    /// Merge `snbt` into the NBT of the player's off-hand item.
1002    /// Returns false if offline or holding air.
1003    pub set_offhand_item_nbt:
1004        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, snbt: YogStr) -> bool,
1005    /// Full item stack at inventory `slot`: tab-separated `item_id\tcount\tsnbt`.
1006    /// `snbt` is `{}` when the item has no NBT. Returns NONE if offline or slot empty.
1007    pub get_slot_item:
1008        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, slot: u32) -> YogOwnedStr,
1009    /// Replace inventory `slot` with an item stack. `snbt` may be empty to clear NBT.
1010    /// Pass `count == 0` to clear the slot (ignores `item_id` and `snbt`).
1011    pub set_slot_item: unsafe extern "C" fn(
1012        ctx: *mut c_void,
1013        player: YogStr,
1014        slot: u32,
1015        item_id: YogStr,
1016        count: u32,
1017        snbt: YogStr,
1018    ) -> bool,
1019
1020    // ── entity rotation (ABI minor 25) ───────────────────────────────────────
1021    /// Yaw and pitch (degrees) of an entity by UUID. Returns false if the
1022    /// entity does not exist. `out` receives x=yaw, y=pitch, z=0.
1023    pub entity_rotation:
1024        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, out: *mut YogVec3) -> bool,
1025
1026    // ── world queries & effects (ABI minor 1) ────────────────────────────────
1027    // Records come back as one tab-separated line; `yog_core`'s `EntityInfo`,
1028    // `BlockHit`, `BlockInfo` and `PlayerInfo` document and decode them.
1029    /// `EntityInfo` line of a loaded entity, or NONE.
1030    pub entity_info: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> YogOwnedStr,
1031    /// Newline-separated uuids of the entities touching the box.
1032    pub entities_in_box: unsafe extern "C" fn(
1033        ctx: *mut c_void,
1034        dim: YogStr,
1035        min: YogVec3,
1036        max: YogVec3,
1037    ) -> YogOwnedStr,
1038    /// `BlockHit` line of the first block on the segment, or NONE.
1039    pub raycast_block: unsafe extern "C" fn(
1040        ctx: *mut c_void,
1041        dim: YogStr,
1042        from: YogVec3,
1043        to: YogVec3,
1044    ) -> YogOwnedStr,
1045    /// Uuid of the nearest entity on the segment (not `exclude`), or NONE.
1046    pub raycast_entity: unsafe extern "C" fn(
1047        ctx: *mut c_void,
1048        dim: YogStr,
1049        from: YogVec3,
1050        to: YogVec3,
1051        exclude: YogStr,
1052    ) -> YogOwnedStr,
1053    /// `BlockInfo` line of the block at `pos`, or NONE.
1054    pub block_info:
1055        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> YogOwnedStr,
1056    pub break_block: unsafe extern "C" fn(
1057        ctx: *mut c_void,
1058        dim: YogStr,
1059        pos: YogBlockPos,
1060        drop: bool,
1061        breaker: YogStr,
1062    ) -> bool,
1063    pub place_block_from_slot: unsafe extern "C" fn(
1064        ctx: *mut c_void,
1065        player: YogStr,
1066        slot: u32,
1067        dim: YogStr,
1068        pos: YogBlockPos,
1069    ) -> bool,
1070    pub bonemeal: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> bool,
1071    pub explode: unsafe extern "C" fn(
1072        ctx: *mut c_void,
1073        dim: YogStr,
1074        pos: YogVec3,
1075        power: f32,
1076        fire: bool,
1077        source: YogStr,
1078    ) -> bool,
1079    /// `json` is a JSON text component (the `/tellraw` format).
1080    pub tellraw: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, json: YogStr) -> bool,
1081    pub entity_damage: unsafe extern "C" fn(
1082        ctx: *mut c_void,
1083        uuid: YogStr,
1084        amount: f32,
1085        damage_type: YogStr,
1086        attacker: YogStr,
1087    ) -> bool,
1088    pub entity_set_fire_ticks:
1089        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, ticks: i32) -> bool,
1090    pub player_add_xp: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, amount: i32) -> bool,
1091    pub player_set_may_fly:
1092        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, may_fly: bool) -> bool,
1093    /// `PlayerInfo` line of an online player, or NONE.
1094    pub player_info: unsafe extern "C" fn(ctx: *mut c_void, player: YogStr) -> YogOwnedStr,
1095    /// Uuid of the dropped item entity, or NONE.
1096    pub spawn_item: unsafe extern "C" fn(
1097        ctx: *mut c_void,
1098        dim: YogStr,
1099        pos: YogVec3,
1100        vel: YogVec3,
1101        item_id: YogStr,
1102        count: u32,
1103        snbt: YogStr,
1104    ) -> YogOwnedStr,
1105    /// `item_id\tcount\tsnbt` of a dropped item entity, or NONE.
1106    pub item_entity_stack: unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr) -> YogOwnedStr,
1107    pub item_entity_set_stack: unsafe extern "C" fn(
1108        ctx: *mut c_void,
1109        uuid: YogStr,
1110        item_id: YogStr,
1111        count: u32,
1112        snbt: YogStr,
1113    ) -> bool,
1114    // ── ABI minor 2 ──
1115    /// `json` is a JSON text component.
1116    pub actionbar_json:
1117        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, json: YogStr) -> bool,
1118    /// `face` is a `Direction` ordinal (down, up, north, south, west, east).
1119    pub use_item_on_block: unsafe extern "C" fn(
1120        ctx: *mut c_void,
1121        dim: YogStr,
1122        pos: YogBlockPos,
1123        face: u8,
1124        item_id: YogStr,
1125        player: YogStr,
1126    ) -> bool,
1127    pub pour_fluid: unsafe extern "C" fn(
1128        ctx: *mut c_void,
1129        dim: YogStr,
1130        pos: YogBlockPos,
1131        bucket_item_id: YogStr,
1132    ) -> bool,
1133    pub has_entity_tag:
1134        unsafe extern "C" fn(ctx: *mut c_void, entity_type: YogStr, tag_id: YogStr) -> bool,
1135    /// The block id a block item places, or NONE.
1136    pub item_block: unsafe extern "C" fn(ctx: *mut c_void, item_id: YogStr) -> YogOwnedStr,
1137    pub place_feature: unsafe extern "C" fn(
1138        ctx: *mut c_void,
1139        dim: YogStr,
1140        pos: YogBlockPos,
1141        feature_id: YogStr,
1142    ) -> bool,
1143
1144    // ── ABI minor 3 ──────────────────────────────────────────────────────────
1145    pub set_item_cooldown:
1146        unsafe extern "C" fn(ctx: *mut c_void, player: YogStr, item_id: YogStr, ticks: i32) -> bool,
1147    pub entity_teleport_with_passengers:
1148        unsafe extern "C" fn(ctx: *mut c_void, uuid: YogStr, dim: YogStr, pos: YogVec3) -> bool,
1149    /// Received redstone power 0–15, or -1 (no such dimension).
1150    pub redstone_power: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> i32,
1151    pub set_redstone_output:
1152        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, level: i32) -> bool,
1153    /// `"ns:id[prop=value,...]"`, or NONE.
1154    pub get_block_state: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos) -> YogOwnedStr,
1155    pub set_block_state:
1156        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, pos: YogBlockPos, state: YogStr) -> bool,
1157    pub world_is_thundering: unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr) -> bool,
1158    pub world_set_thunder:
1159        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, thundering: bool, duration_ticks: i32) -> bool,
1160    /// Sets every block of the box `from..=to` to `state`; how many changed, or -1.
1161    pub fill_region: unsafe extern "C" fn(
1162        ctx: *mut c_void,
1163        dim: YogStr,
1164        from: YogBlockPos,
1165        to: YogBlockPos,
1166        state: YogStr,
1167    ) -> i32,
1168    /// The non-air blocks of the box `from..=to`: `"x y z state"` lines, or NONE.
1169    pub scan_region:
1170        unsafe extern "C" fn(ctx: *mut c_void, dim: YogStr, from: YogBlockPos, to: YogBlockPos) -> YogOwnedStr,
1171}
1172
1173// ctx = *mut JavaVM which is global/stable. All fn ptrs are pure C-ABI.
1174unsafe impl Send for YogServer {}
1175unsafe impl Sync for YogServer {}
1176
1177// ── Chunk generator callback (ABI minor 29) ───────────────────────────────────
1178
1179/// Per-callback context handed to a registered chunk generator (see
1180/// `YogApi::register_chunk_generator`) — mirrors `YogGfxApi`'s pattern of
1181/// bundling per-call context with the function pointer(s) needed to act on
1182/// it. Valid only for the duration of the generator callback.
1183#[repr(C)]
1184#[derive(Copy, Clone)]
1185pub struct YogChunkWriterApi {
1186    /// Chunk X coordinate (in chunks, not blocks).
1187    pub chunk_x: i32,
1188    /// Chunk Z coordinate (in chunks, not blocks).
1189    pub chunk_z: i32,
1190    /// Minimum build height (world Y) for this dimension.
1191    pub min_y: i32,
1192    /// Total world height for this dimension.
1193    pub height: i32,
1194    /// Opaque host-side handle for the chunk currently being generated.
1195    pub ctx: *mut c_void,
1196    /// Set a block within this chunk column. `x`/`z` are local (0..16)
1197    /// chunk-relative coordinates; `y` is world-absolute.
1198    pub set_block:
1199        unsafe extern "C" fn(ctx: *mut c_void, x: i32, y: i32, z: i32, block_id: YogStr) -> bool,
1200}
1201
1202unsafe impl Send for YogChunkWriterApi {}
1203unsafe impl Sync for YogChunkWriterApi {}
1204
1205/// Called by the host once per chunk column that needs generating in the
1206/// registered dimension. `writer` is valid only for the duration of the call.
1207pub type YogChunkGeneratorFn =
1208    unsafe extern "C" fn(ud: *mut c_void, writer: *const YogChunkWriterApi);
1209
1210// ── Registration table (passed to yog_mod_register) ──────────────────────────
1211
1212/// Passed to `yog_mod_register`. Call the function pointers here to register
1213/// handlers, commands, content, and schedulers.
1214///
1215/// When mods compiled against ABI `N` load on a runtime with ABI `M > N`:
1216/// fields beyond `size` are not present in the mod's view — check `size` before
1217/// accessing fields added in later minor versions.
1218#[repr(C)]
1219pub struct YogApi {
1220    pub abi_version: u32,
1221    /// `sizeof(YogApi)` at the runtime's build time.
1222    pub size: u32,
1223    /// Opaque pointer to runtime handler storage.
1224    pub ctx: *mut c_void,
1225    /// Stable server action table — pass to handlers.
1226    pub server: *const YogServer,
1227
1228    // ── events — all handlers receive (ud, srv, event, phase: u8) → bool ────────
1229    // phase 0 = Pre (return false to cancel), phase 1 = Post (return ignored).
1230    pub on_block_break: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogBlockBreakFn),
1231    pub on_chat: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogChatFn),
1232    pub on_player_join: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerFn),
1233    pub on_player_leave: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerFn),
1234    pub on_use_item: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogUseItemFn),
1235    pub on_use_block: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogUseBlockFn),
1236    pub on_attack_entity:
1237        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogAttackEntityFn),
1238    pub on_entity_damage:
1239        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntityDamageFn),
1240    pub on_entity_death:
1241        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntityDeathFn),
1242    pub on_entity_spawn:
1243        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntitySpawnFn),
1244    pub on_player_place_block:
1245        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlaceBlockFn),
1246    pub on_player_death:
1247        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerDeathFn),
1248    pub on_player_respawn:
1249        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerRespawnFn),
1250    pub on_advancement:
1251        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogAdvancementFn),
1252    // ── ABI minor 8 ──────────────────────────────────────────────────────────
1253    pub on_entity_interact:
1254        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogEntityInteractFn),
1255    pub on_item_craft: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogCraftFn),
1256    pub on_explosion: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogExplosionFn),
1257    // ── ABI minor 9 ──────────────────────────────────────────────────────────
1258    pub on_item_pickup: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogItemPickupFn),
1259    pub on_player_move: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogPlayerMoveFn),
1260    pub on_container_open:
1261        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogContainerOpenFn),
1262    pub on_container_close:
1263        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogContainerCloseFn),
1264    pub on_projectile_hit:
1265        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogProjectileHitFn),
1266    pub on_server_tick: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogServerFn),
1267    pub on_server_started: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogServerFn),
1268    pub on_server_stopping: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogServerFn),
1269
1270    // ── networking ───────────────────────────────────────────────────────────
1271    pub on_packet:
1272        unsafe extern "C" fn(ctx: *mut c_void, channel: YogStr, ud: *mut c_void, h: YogPacketFn),
1273    pub on_client_packet:
1274        unsafe extern "C" fn(ctx: *mut c_void, channel: YogStr, ud: *mut c_void, h: YogPacketFn),
1275
1276    // ── commands ─────────────────────────────────────────────────────────────
1277    pub register_command:
1278        unsafe extern "C" fn(ctx: *mut c_void, name: YogStr, ud: *mut c_void, h: YogCommandFn),
1279    pub register_typed_command: unsafe extern "C" fn(
1280        ctx: *mut c_void,
1281        name: YogStr,
1282        schema: YogStr,
1283        ud: *mut c_void,
1284        h: YogCommandFn,
1285    ),
1286
1287    // ── recipes ──────────────────────────────────────────────────────────────
1288    /// Register a recipe by supplying Minecraft JSON (`data/` format).
1289    /// `namespace` + `name` form the file path: `data/{ns}/recipes/{name}.json`.
1290    pub register_recipe_json:
1291        unsafe extern "C" fn(ctx: *mut c_void, namespace: YogStr, name: YogStr, json: YogStr),
1292
1293    // ── content ──────────────────────────────────────────────────────────────
1294    pub register_item: unsafe extern "C" fn(ctx: *mut c_void, def: *const YogItemDef),
1295    pub register_block: unsafe extern "C" fn(ctx: *mut c_void, def: *const YogBlockDef),
1296
1297    // ── scheduler ────────────────────────────────────────────────────────────
1298    pub schedule_once: unsafe extern "C" fn(
1299        ctx: *mut c_void,
1300        delay_ticks: u64,
1301        ud: *mut c_void,
1302        h: YogScheduledFn,
1303    ),
1304    pub schedule_repeating: unsafe extern "C" fn(
1305        ctx: *mut c_void,
1306        period_ticks: u64,
1307        ud: *mut c_void,
1308        h: YogScheduledFn,
1309    ),
1310
1311    // ── ABI minor 10 — client-side events ────────────────────────────────────
1312    pub on_client_tick: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogClientFn),
1313    pub on_hud_render: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogHudRenderFn),
1314    pub on_key_press: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogKeyPressFn),
1315    pub on_screen_open: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogScreenFn),
1316    pub on_screen_close: unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogScreenFn),
1317
1318    // ── ABI minor 14 — world render ──────────────────────────────────────────
1319    /// Register a handler that fires after world geometry is rendered.
1320    /// `gfx.view_proj` and `gfx.camera_pos` are filled; use them to project
1321    /// custom 3D geometry into clip space.
1322    pub on_world_render:
1323        unsafe extern "C" fn(ctx: *mut c_void, ud: *mut c_void, h: YogWorldRenderFn),
1324
1325    // ── ABI minor 16 — startup grants ────────────────────────────────────────
1326    pub register_startup_grant:
1327        unsafe extern "C" fn(ctx: *mut c_void, grant: *const YogStartupGrantDef),
1328
1329    // ── ABI minor 18 — books ─────────────────────────────────────────────────
1330    pub register_book: unsafe extern "C" fn(ctx: *mut c_void, book_id: YogStr, book_json: YogStr),
1331
1332    // ── ABI minor 19 — UI system ──────────────────────────────────────────────
1333    /// Register a UI tree. `ui_id` is the unique identifier (e.g. "mymod:menu").
1334    /// `layout_json` is the serialized layout tree.
1335    /// `handler` is called when an interactive element is clicked/keyed.
1336    pub register_ui: unsafe extern "C" fn(
1337        ctx: *mut c_void,
1338        ui_id: YogStr,
1339        layout_json: YogStr,
1340        ud: *mut c_void,
1341        h: YogUIEventFn,
1342    ),
1343
1344    // ── ABI minor 20 — per-UI screen renderer ────────────────────────────────
1345    /// Register a render callback that fires during `YogUIScreen.render()` for a
1346    /// specific UI id — i.e. AFTER the screen darkening, unlike `on_hud_render`.
1347    /// Reuses `YogHudRenderFn` (`fn(ud, gfx)`); `gfx.screen_w/h` are set.
1348    /// Clicks are forwarded as `"click:X:Y"` events to the `register_ui` handler
1349    /// so mods can do their own hit-testing with their stored layout.
1350    pub on_ui_render:
1351        unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr, ud: *mut c_void, h: YogHudRenderFn),
1352
1353    // ── ABI minor 22 — menu entry registration ──────────────────────────────
1354    /// Register a button/link that the host renders on vanilla screens
1355    /// (TitleScreen on Fabric, ModListScreen on Forge/NeoForge).
1356    /// `label` is the human-readable button text (e.g. "Yog Mods").
1357    /// `ui_id` is the Yog UI to open when clicked (e.g. "example:menu").
1358    pub register_menu_entry: unsafe extern "C" fn(ctx: *mut c_void, label: YogStr, ui_id: YogStr),
1359
1360    // ── ABI minor 23 — installed mods listing ───────────────────────────────
1361    /// All installed mods as TSV, one per line:
1362    /// `source \t id \t name \t version \t authors \t description`
1363    /// where `source` is `yog` (a .yog mod) or `platform` (a loader mod, e.g.
1364    /// a Fabric/Forge jar). Tabs and newlines inside fields become spaces.
1365    /// Callable at any time after registration (also client-side).
1366    pub mods_list: unsafe extern "C" fn(ctx: *mut c_void) -> YogOwnedStr,
1367    /// Free a `YogOwnedStr` returned by an api-table call (same allocator as
1368    /// `YogServer::free_str`).
1369    pub free_str: unsafe extern "C" fn(ptr: *mut u8, len: u32),
1370
1371    // ── ABI minor 24 — open a Yog UI screen ─────────────────────────────────
1372    /// Open the Yog UI registered as `ui_id` on the client (schedules onto the
1373    /// render thread). Client-side only; a no-op on dedicated servers.
1374    /// `modal` blocks game input; `pause` pauses a singleplayer game.
1375    pub ui_open: unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr, modal: bool, pause: bool),
1376
1377    // ── ABI minor 25 — inventory framework (yog-inventory) ──────────────────
1378    /// Register a real Container/Menu inventory screen — see `yog_inventory`.
1379    pub register_inventory: unsafe extern "C" fn(ctx: *mut c_void, def: *const YogInventoryDef),
1380
1381    // ── ABI minor 26 — inter-mod communication ─────────────────────────────
1382    /// Export a function pointer under `symbol` for the calling mod (`mod_id`).
1383    /// Other mods can import it via `interop_import`.
1384    pub interop_export:
1385        unsafe extern "C" fn(ctx: *mut c_void, mod_id: YogStr, symbol: YogStr, ptr: *const c_void),
1386    /// Import a function pointer exported by `mod_id` under `symbol`.
1387    /// Returns null if the symbol is not (yet) registered.
1388    pub interop_import:
1389        unsafe extern "C" fn(ctx: *mut c_void, mod_id: YogStr, symbol: YogStr) -> *const c_void,
1390
1391    // ── ABI minor 29 — custom dimensions ────────────────────────────────────
1392    /// Register a dimension-type definition (id + `YogDimensionTypeDef` JSON).
1393    /// Must be called at mod-init time (same window as blocks/items) — the
1394    /// host registers a `LevelStem`/`DimensionType` entry before the
1395    /// registry freezes. See `yog-dimensions` crate.
1396    pub register_dimension_json: unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, json: YogStr),
1397    /// Register a chunk generator for a previously-declared dimension `id`.
1398    /// `handler` is called once per chunk column that needs generating —
1399    /// see `YogChunkWriterApi`/`YogChunkGeneratorFn`.
1400    pub register_chunk_generator:
1401        unsafe extern "C" fn(ctx: *mut c_void, id: YogStr, ud: *mut c_void, h: YogChunkGeneratorFn),
1402
1403    // ── ABI minor 33 — closing Yog UI screens, consuming UI key events ──────
1404    /// Close the Yog UI screen showing `ui_id` (empty = whichever Yog UI
1405    /// screen is open). Scheduled onto the render thread, so it's safe to
1406    /// call from that screen's own event handler. Client-side only.
1407    pub ui_close: unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr),
1408    /// Called from inside a `register_ui` handler while it handles a `key:`
1409    /// or `char:` event: the mod used the key, so the host skips its default
1410    /// handling (Esc closing the screen, Tab focus navigation, ...).
1411    pub ui_consume_event: unsafe extern "C" fn(ctx: *mut c_void),
1412
1413    // ── ABI minor 33 — translations ─────────────────────────────────────────
1414    /// The text of translation key `key` (e.g. `mymod.screen.title`) in the
1415    /// game's current language, from the loaded lang files — resource packs
1416    /// and `.yog` mods' `assets/<ns>/lang/*.json` (compiled from `.yres`).
1417    /// `YogOwnedStr::NONE` when no language defines the key. Format
1418    /// specifiers (`%s`, `%1$s`) come back as-is. Free with `free_str`.
1419    /// Client-side; a dedicated server only knows `en_us`.
1420    pub translate: unsafe extern "C" fn(ctx: *mut c_void, key: YogStr) -> YogOwnedStr,
1421
1422    // ── ABI minor 1 — client: screen flags, sounds, held items, keys ────────
1423    /// Like `ui_open`, with [`ui_flags`] bits: `MODAL`, `PAUSE`,
1424    /// `NO_BACKGROUND` (no dimmed/blurred world behind the screen).
1425    /// Client-side only.
1426    pub ui_open_flags: unsafe extern "C" fn(ctx: *mut c_void, ui_id: YogStr, flags: u32),
1427    /// Play sound event `sound_id` for the local player only: at the
1428    /// player's position, or (`looping`) as a loop that follows the player
1429    /// until `client_stop_sound`. Returns a handle (0 = failed).
1430    pub client_play_sound: unsafe extern "C" fn(
1431        ctx: *mut c_void,
1432        sound_id: YogStr,
1433        volume: f32,
1434        pitch: f32,
1435        looping: bool,
1436    ) -> u32,
1437    /// Stop a sound started by `client_play_sound` (0 or unknown: no-op).
1438    pub client_stop_sound: unsafe extern "C" fn(ctx: *mut c_void, handle: u32),
1439    /// Item id in the local player's main hand (`off_hand` false) or off
1440    /// hand, `YogOwnedStr::NONE` for air or no player. Free with `free_str`.
1441    pub client_held_item: unsafe extern "C" fn(ctx: *mut c_void, off_hand: bool) -> YogOwnedStr,
1442    /// Whether GLFW key `key` is held down right now (client window).
1443    pub client_key_down: unsafe extern "C" fn(ctx: *mut c_void, key: i32) -> bool,
1444}
1445
1446/// Flag bits for [`YogApi::ui_open_flags`].
1447pub mod ui_flags {
1448    /// Blocks game input (what `ui_open`'s `modal` does).
1449    pub const MODAL: u32 = 1;
1450    /// Pauses a singleplayer game.
1451    pub const PAUSE: u32 = 1 << 1;
1452    /// Draws no background behind the screen: the world stays visible.
1453    pub const NO_BACKGROUND: u32 = 1 << 2;
1454}
1455
1456unsafe impl Send for YogApi {}
1457unsafe impl Sync for YogApi {}