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