1use std::os::raw::c_void;
11
12use yog_abi::{
13 YogAdvancementEvent, YogApi, YogAttackEntityEvent, YogBlockBreakEvent, YogBlockDef,
14 YogChatEvent, YogCommandEvent, YogContainerCloseEvent, YogContainerOpenEvent, YogCraftEvent,
15 YogEntityDamageEvent, YogEntityDeathEvent, YogEntityInteractEvent, YogEntitySpawnEvent,
16 YogExplosionEvent, YogGfxApi, YogItemDef, YogItemPickupEvent, YogKeyPressEvent,
17 YogPacketEvent, YogPlaceBlockEvent, YogPlayerDeathEvent, YogPlayerEvent, YogPlayerMoveEvent,
18 YogPlayerRespawnEvent, YogProjectileHitEvent, YogServer, YogStr, YogStartupGrantDef,
19 YogUseBlockEvent, YogUseItemEvent,
20};
21use yog_book::Book;
22use yog_gfx::GfxContext;
23use yog_command::CommandContext;
24use yog_core::Server;
25use yog_event::{
26 AdvancementEvent, AttackEntityEvent, BlockBreakEvent, ChatEvent, ClientTickEvent,
27 ContainerCloseEvent, ContainerOpenEvent, CraftEvent, EntityDamageEvent, EntityDeathEvent,
28 EntityInteractEvent, EntitySpawnEvent, EventPhase, ExplosionEvent,
29 ItemPickupEvent, KeyPressEvent, PlaceBlockEvent, PlayerDeathEvent, PlayerJoinEvent,
30 PlayerLeaveEvent, PlayerMoveEvent, PlayerRespawnEvent, ProjectileHitEvent, ScreenEvent,
31 UseBlockEvent, UseItemEvent,
32};
33use yog_network::{Packet, PacketEvent};
34use yog_registry::{BlockDef, FurnaceRecipe, ItemDef, ShapedRecipe, ShapelessRecipe, StartupGrant};
35
36pub struct CServer(pub *const YogServer);
41
42unsafe impl Send for CServer {}
43unsafe impl Sync for CServer {}
44
45macro_rules! srv {
46 ($self:ident) => { unsafe { &*$self.0 } };
47}
48
49impl Server for CServer {
50 fn broadcast(&self, message: &str) {
51 let s = srv!(self);
52 unsafe { (s.broadcast)(s.ctx, YogStr::from_str(message)) }
53 }
54
55 fn get_block(&self, dimension: &str, pos: yog_core::BlockPos) -> Option<String> {
56 let s = srv!(self);
57 let owned = unsafe {
58 (s.get_block)(s.ctx, YogStr::from_str(dimension),
59 yog_abi::YogBlockPos { x: pos.x, y: pos.y, z: pos.z })
60 };
61 if owned.is_none() { return None; }
62 let result = unsafe {
63 String::from_utf8(
64 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
65 ).ok()
66 };
67 unsafe { (s.free_str)(owned.ptr, owned.len) };
68 result
69 }
70
71 fn set_block(&self, dimension: &str, pos: yog_core::BlockPos, block_id: &str) -> bool {
72 let s = srv!(self);
73 unsafe {
74 (s.set_block)(s.ctx, YogStr::from_str(dimension),
75 yog_abi::YogBlockPos { x: pos.x, y: pos.y, z: pos.z },
76 YogStr::from_str(block_id))
77 }
78 }
79
80 fn give_item(&self, player: &str, item_id: &str, count: u32) -> bool {
81 let s = srv!(self);
82 unsafe { (s.give_item)(s.ctx, YogStr::from_str(player), YogStr::from_str(item_id), count) }
83 }
84
85 fn teleport(&self, player: &str, x: f64, y: f64, z: f64) -> bool {
86 let s = srv!(self);
87 unsafe { (s.player_teleport)(s.ctx, YogStr::from_str(player), yog_abi::YogVec3 { x, y, z }) }
88 }
89
90 fn send_to_player(&self, player: &str, channel: &str, payload: &[u8]) -> bool {
91 let s = srv!(self);
92 unsafe {
93 (s.send_to_player)(s.ctx, YogStr::from_str(player), YogStr::from_str(channel),
94 payload.as_ptr(), payload.len() as u32)
95 }
96 }
97
98 fn send_to_server(&self, channel: &str, payload: &[u8]) -> bool {
99 let s = srv!(self);
100 unsafe {
101 (s.send_to_server)(s.ctx, YogStr::from_str(channel),
102 payload.as_ptr(), payload.len() as u32)
103 }
104 }
105
106 fn entity_teleport(&self, uuid: &str, x: f64, y: f64, z: f64) -> bool {
107 let s = srv!(self);
108 unsafe { (s.entity_teleport)(s.ctx, YogStr::from_str(uuid), yog_abi::YogVec3 { x, y, z }) }
109 }
110
111 fn entity_position(&self, uuid: &str) -> Option<(f64, f64, f64)> {
112 let s = srv!(self);
113 let mut out = yog_abi::YogVec3 { x: 0.0, y: 0.0, z: 0.0 };
114 if unsafe { (s.entity_position)(s.ctx, YogStr::from_str(uuid), &mut out) } {
115 Some((out.x, out.y, out.z))
116 } else {
117 None
118 }
119 }
120
121 fn entity_health(&self, uuid: &str) -> Option<f32> {
122 let s = srv!(self);
123 let mut hp = 0f32;
124 if unsafe { (s.entity_health)(s.ctx, YogStr::from_str(uuid), &mut hp) } { Some(hp) } else { None }
125 }
126
127 fn entity_set_health(&self, uuid: &str, health: f32) -> bool {
128 let s = srv!(self);
129 unsafe { (s.entity_set_health)(s.ctx, YogStr::from_str(uuid), health) }
130 }
131
132 fn entity_kill(&self, uuid: &str) -> bool {
133 let s = srv!(self);
134 unsafe { (s.entity_kill)(s.ctx, YogStr::from_str(uuid)) }
135 }
136
137 fn spawn_entity(&self, entity_type: &str, dimension: &str, x: f64, y: f64, z: f64) -> Option<String> {
138 let s = srv!(self);
139 let owned = unsafe {
140 (s.spawn_entity)(s.ctx, YogStr::from_str(entity_type),
141 YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z })
142 };
143 if owned.is_none() { return None; }
144 let result = unsafe {
145 String::from_utf8(
146 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
147 ).ok()
148 };
149 unsafe { (s.free_str)(owned.ptr, owned.len) };
150 result
151 }
152
153 fn entity_add_effect(&self, uuid: &str, effect_id: &str, duration_ticks: i32, amplifier: u8, show_particles: bool) -> bool {
154 let s = srv!(self);
155 unsafe { (s.entity_add_effect)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(effect_id), duration_ticks, amplifier, show_particles) }
156 }
157
158 fn entity_remove_effect(&self, uuid: &str, effect_id: &str) -> bool {
159 let s = srv!(self);
160 unsafe { (s.entity_remove_effect)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(effect_id)) }
161 }
162
163 fn entity_clear_effects(&self, uuid: &str) -> bool {
164 let s = srv!(self);
165 unsafe { (s.entity_clear_effects)(s.ctx, YogStr::from_str(uuid)) }
166 }
167
168 fn drop_loot(&self, table_id: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool {
169 let s = srv!(self);
170 unsafe { (s.drop_loot)(s.ctx, YogStr::from_str(table_id), YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z }) }
171 }
172
173 fn has_item_tag(&self, item_id: &str, tag_id: &str) -> bool {
174 let s = srv!(self);
175 unsafe { (s.has_item_tag)(s.ctx, YogStr::from_str(item_id), YogStr::from_str(tag_id)) }
176 }
177
178 fn has_block_tag(&self, block_id: &str, tag_id: &str) -> bool {
179 let s = srv!(self);
180 unsafe { (s.has_block_tag)(s.ctx, YogStr::from_str(block_id), YogStr::from_str(tag_id)) }
181 }
182
183 fn world_time(&self, dimension: &str) -> Option<i64> {
184 let s = srv!(self);
185 let mut t = 0i64;
186 if unsafe { (s.world_time)(s.ctx, YogStr::from_str(dimension), &mut t) } { Some(t) } else { None }
187 }
188
189 fn world_set_time(&self, dimension: &str, time: i64) -> bool {
190 let s = srv!(self);
191 unsafe { (s.set_time)(s.ctx, YogStr::from_str(dimension), time) }
192 }
193
194 fn world_is_raining(&self, dimension: &str) -> bool {
195 let s = srv!(self);
196 unsafe { (s.is_raining)(s.ctx, YogStr::from_str(dimension)) }
197 }
198
199 fn world_set_weather(&self, dimension: &str, raining: bool, duration_ticks: i32) -> bool {
200 let s = srv!(self);
201 unsafe { (s.set_weather)(s.ctx, YogStr::from_str(dimension), raining, duration_ticks) }
202 }
203
204 fn entity_velocity(&self, uuid: &str) -> Option<(f64, f64, f64)> {
205 let s = srv!(self);
206 let mut v = yog_abi::YogVec3 { x: 0.0, y: 0.0, z: 0.0 };
207 if unsafe { (s.entity_velocity)(s.ctx, YogStr::from_str(uuid), &mut v) } {
208 Some((v.x, v.y, v.z))
209 } else {
210 None
211 }
212 }
213
214 fn entity_set_velocity(&self, uuid: &str, vx: f64, vy: f64, vz: f64) -> bool {
215 let s = srv!(self);
216 unsafe { (s.entity_set_velocity)(s.ctx, YogStr::from_str(uuid), yog_abi::YogVec3 { x: vx, y: vy, z: vz }) }
217 }
218
219 fn entity_add_velocity(&self, uuid: &str, vx: f64, vy: f64, vz: f64) -> bool {
220 let s = srv!(self);
221 unsafe { (s.entity_add_velocity)(s.ctx, YogStr::from_str(uuid), yog_abi::YogVec3 { x: vx, y: vy, z: vz }) }
222 }
223
224 fn scoreboard_get(&self, objective: &str, player: &str) -> Option<i32> {
225 let s = srv!(self);
226 let mut score = 0i32;
227 if unsafe { (s.scoreboard_get)(s.ctx, YogStr::from_str(objective), YogStr::from_str(player), &mut score) } { Some(score) } else { None }
228 }
229
230 fn scoreboard_set(&self, objective: &str, player: &str, score: i32) -> bool {
231 let s = srv!(self);
232 unsafe { (s.scoreboard_set)(s.ctx, YogStr::from_str(objective), YogStr::from_str(player), score) }
233 }
234
235 fn scoreboard_add(&self, objective: &str, player: &str, delta: i32) -> Option<i32> {
236 let s = srv!(self);
237 let mut new_score = 0i32;
238 if unsafe { (s.scoreboard_add)(s.ctx, YogStr::from_str(objective), YogStr::from_str(player), delta, &mut new_score) } { Some(new_score) } else { None }
239 }
240
241 fn game_dir(&self) -> String {
242 let s = srv!(self);
243 let owned = unsafe { (s.game_dir)(s.ctx) };
244 if owned.is_none() { return String::new(); }
245 let result = unsafe {
246 String::from_utf8(
247 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
248 ).unwrap_or_default()
249 };
250 unsafe { (s.free_str)(owned.ptr, owned.len) };
251 result
252 }
253
254 fn play_sound(&self, dimension: &str, x: f64, y: f64, z: f64, sound_id: &str, volume: f32, pitch: f32) -> bool {
255 let s = srv!(self);
256 unsafe { (s.play_sound)(s.ctx, YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z }, YogStr::from_str(sound_id), volume, pitch) }
257 }
258
259 fn play_sound_to_player(&self, player: &str, sound_id: &str, volume: f32, pitch: f32) -> bool {
260 let s = srv!(self);
261 unsafe { (s.play_sound_player)(s.ctx, YogStr::from_str(player), YogStr::from_str(sound_id), volume, pitch) }
262 }
263
264 fn send_title(&self, player: &str, title: &str, subtitle: &str, fadein: i32, stay: i32, fadeout: i32) -> bool {
265 let s = srv!(self);
266 unsafe { (s.send_title)(s.ctx, YogStr::from_str(player), YogStr::from_str(title), YogStr::from_str(subtitle), fadein, stay, fadeout) }
267 }
268
269 fn entity_rotation(&self, uuid: &str) -> Option<(f32, f32)> {
270 let s = srv!(self);
271 let mut out = yog_abi::YogVec3 { x: 0.0, y: 0.0, z: 0.0 };
272 let ok = unsafe { (s.entity_rotation)(s.ctx, YogStr::from_str(uuid), &mut out) };
273 if ok { Some((out.x as f32, out.y as f32)) } else { None }
274 }
275
276 fn send_actionbar(&self, player: &str, message: &str) -> bool {
277 let s = srv!(self);
278 unsafe { (s.send_actionbar)(s.ctx, YogStr::from_str(player), YogStr::from_str(message)) }
279 }
280
281 fn kick_player(&self, player: &str, reason: &str) -> bool {
282 let s = srv!(self);
283 unsafe { (s.kick_player)(s.ctx, YogStr::from_str(player), YogStr::from_str(reason)) }
284 }
285
286 fn set_gamemode(&self, player: &str, gamemode: &str) -> bool {
287 let s = srv!(self);
288 unsafe { (s.set_gamemode)(s.ctx, YogStr::from_str(player), YogStr::from_str(gamemode)) }
289 }
290
291 fn bossbar_create(&self, id: &str, title: &str, color: &str, style: &str) -> bool {
292 let s = srv!(self);
293 unsafe { (s.bossbar_create)(s.ctx, YogStr::from_str(id), YogStr::from_str(title), YogStr::from_str(color), YogStr::from_str(style)) }
294 }
295
296 fn bossbar_remove(&self, id: &str) -> bool {
297 let s = srv!(self);
298 unsafe { (s.bossbar_remove)(s.ctx, YogStr::from_str(id)) }
299 }
300
301 fn bossbar_set_title(&self, id: &str, title: &str) -> bool {
302 let s = srv!(self);
303 unsafe { (s.bossbar_set_title)(s.ctx, YogStr::from_str(id), YogStr::from_str(title)) }
304 }
305
306 fn bossbar_set_progress(&self, id: &str, progress: f32) -> bool {
307 let s = srv!(self);
308 unsafe { (s.bossbar_set_progress)(s.ctx, YogStr::from_str(id), progress) }
309 }
310
311 fn bossbar_set_color(&self, id: &str, color: &str) -> bool {
312 let s = srv!(self);
313 unsafe { (s.bossbar_set_color)(s.ctx, YogStr::from_str(id), YogStr::from_str(color)) }
314 }
315
316 fn bossbar_add_player(&self, id: &str, player: &str) -> bool {
317 let s = srv!(self);
318 unsafe { (s.bossbar_add_player)(s.ctx, YogStr::from_str(id), YogStr::from_str(player)) }
319 }
320
321 fn bossbar_remove_player(&self, id: &str, player: &str) -> bool {
322 let s = srv!(self);
323 unsafe { (s.bossbar_remove_player)(s.ctx, YogStr::from_str(id), YogStr::from_str(player)) }
324 }
325
326 fn bossbar_set_visible(&self, id: &str, visible: bool) -> bool {
327 let s = srv!(self);
328 unsafe { (s.bossbar_set_visible)(s.ctx, YogStr::from_str(id), visible) }
329 }
330
331 fn online_players(&self) -> Vec<String> {
332 let s = srv!(self);
333 let owned = unsafe { (s.online_players)(s.ctx) };
334 if owned.is_none() { return Vec::new(); }
335 let text = unsafe {
336 String::from_utf8(
337 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
338 ).unwrap_or_default()
339 };
340 unsafe { (s.free_str)(owned.ptr, owned.len) };
341 if text.is_empty() { Vec::new() } else { text.lines().map(str::to_owned).collect() }
342 }
343
344 fn get_block_nbt(&self, dimension: &str, pos: yog_core::BlockPos) -> Option<String> {
345 let s = srv!(self);
346 let owned = unsafe {
347 (s.get_block_nbt)(s.ctx, YogStr::from_str(dimension),
348 yog_abi::YogBlockPos { x: pos.x, y: pos.y, z: pos.z })
349 };
350 if owned.is_none() { return None; }
351 let result = unsafe {
352 String::from_utf8(
353 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
354 ).ok()
355 };
356 unsafe { (s.free_str)(owned.ptr, owned.len) };
357 result
358 }
359
360 fn set_block_nbt(&self, dimension: &str, pos: yog_core::BlockPos, snbt: &str) -> bool {
361 let s = srv!(self);
362 unsafe {
363 (s.set_block_nbt)(s.ctx, YogStr::from_str(dimension),
364 yog_abi::YogBlockPos { x: pos.x, y: pos.y, z: pos.z },
365 YogStr::from_str(snbt))
366 }
367 }
368
369 fn player_inventory(&self, player: &str) -> Vec<(u32, String, u32)> {
370 let s = srv!(self);
371 let owned = unsafe { (s.player_inventory)(s.ctx, YogStr::from_str(player)) };
372 if owned.is_none() { return Vec::new(); }
373 let text = unsafe {
374 String::from_utf8(
375 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
376 ).unwrap_or_default()
377 };
378 unsafe { (s.free_str)(owned.ptr, owned.len) };
379 text.lines().filter_map(|line| {
380 let mut it = line.split('\t');
381 let slot: u32 = it.next()?.parse().ok()?;
382 let item_id = it.next()?.to_owned();
383 let count: u32 = it.next()?.parse().ok()?;
384 Some((slot, item_id, count))
385 }).collect()
386 }
387
388 fn player_set_slot(&self, player: &str, slot: u32, item_id: &str, count: u32) -> bool {
389 let s = srv!(self);
390 unsafe {
391 (s.player_set_slot)(s.ctx, YogStr::from_str(player), slot, YogStr::from_str(item_id), count)
392 }
393 }
394
395 fn teleport_to_dim(&self, player: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool {
396 let s = srv!(self);
397 unsafe {
398 (s.player_teleport_dim)(s.ctx, YogStr::from_str(player),
399 YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z })
400 }
401 }
402
403 fn entity_teleport_to_dim(&self, uuid: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool {
404 let s = srv!(self);
405 unsafe {
406 (s.entity_teleport_dim)(s.ctx, YogStr::from_str(uuid),
407 YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z })
408 }
409 }
410
411 fn world_entity_count(&self, dimension: &str, entity_type: &str) -> i32 {
412 let s = srv!(self);
413 unsafe { (s.world_entity_count)(s.ctx, YogStr::from_str(dimension), YogStr::from_str(entity_type)) }
414 }
415
416 fn entity_get_nbt(&self, uuid: &str) -> Option<String> {
417 let s = srv!(self);
418 let owned = unsafe { (s.entity_get_nbt)(s.ctx, YogStr::from_str(uuid)) };
419 if owned.is_none() { return None; }
420 let result = unsafe {
421 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()).ok()
422 };
423 unsafe { (s.free_str)(owned.ptr, owned.len) };
424 result
425 }
426
427 fn entity_set_nbt(&self, uuid: &str, snbt: &str) -> bool {
428 let s = srv!(self);
429 unsafe { (s.entity_set_nbt)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(snbt)) }
430 }
431
432 fn spawn_particles(&self, dimension: &str, x: f64, y: f64, z: f64, particle_type: &str, count: i32, dx: f64, dy: f64, dz: f64, speed: f64) -> bool {
433 let s = srv!(self);
434 unsafe {
435 (s.spawn_particles)(s.ctx, YogStr::from_str(dimension),
436 yog_abi::YogVec3 { x, y, z }, YogStr::from_str(particle_type),
437 count, dx, dy, dz, speed)
438 }
439 }
440
441 fn entity_attribute_get(&self, uuid: &str, attribute_id: &str) -> Option<f64> {
442 let s = srv!(self);
443 let v = unsafe { (s.entity_attribute_get)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(attribute_id)) };
444 if v.is_nan() { None } else { Some(v) }
445 }
446
447 fn entity_attribute_set(&self, uuid: &str, attribute_id: &str, value: f64) -> bool {
448 let s = srv!(self);
449 unsafe { (s.entity_attribute_set)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(attribute_id), value) }
450 }
451
452 fn get_held_item_nbt(&self, player: &str) -> Option<String> {
453 let s = srv!(self);
454 let owned = unsafe { (s.get_held_item_nbt)(s.ctx, YogStr::from_str(player)) };
455 if owned.is_none() { return None; }
456 let result = unsafe {
457 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()).ok()
458 };
459 unsafe { (s.free_str)(owned.ptr, owned.len) };
460 result
461 }
462
463 fn set_held_item_nbt(&self, player: &str, snbt: &str) -> bool {
464 let s = srv!(self);
465 unsafe { (s.set_held_item_nbt)(s.ctx, YogStr::from_str(player), YogStr::from_str(snbt)) }
466 }
467
468 fn get_offhand_item_nbt(&self, player: &str) -> Option<String> {
469 let s = srv!(self);
470 let owned = unsafe { (s.get_offhand_item_nbt)(s.ctx, YogStr::from_str(player)) };
471 if owned.is_none() { return None; }
472 let result = unsafe {
473 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()).ok()
474 };
475 unsafe { (s.free_str)(owned.ptr, owned.len) };
476 result
477 }
478
479 fn set_offhand_item_nbt(&self, player: &str, snbt: &str) -> bool {
480 let s = srv!(self);
481 unsafe { (s.set_offhand_item_nbt)(s.ctx, YogStr::from_str(player), YogStr::from_str(snbt)) }
482 }
483
484 fn get_slot_item(&self, player: &str, slot: u32) -> Option<(String, u32, String)> {
485 let s = srv!(self);
486 let owned = unsafe { (s.get_slot_item)(s.ctx, YogStr::from_str(player), slot) };
487 if owned.is_none() { return None; }
488 let text = unsafe {
489 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec())
490 .unwrap_or_default()
491 };
492 unsafe { (s.free_str)(owned.ptr, owned.len) };
493 let mut it = text.splitn(3, '\t');
494 let item_id = it.next()?.to_owned();
495 let count: u32 = it.next()?.parse().ok()?;
496 let nbt = it.next().unwrap_or("{}").to_owned();
497 Some((item_id, count, nbt))
498 }
499
500 fn set_slot_item(&self, player: &str, slot: u32, item_id: &str, count: u32, snbt: &str) -> bool {
501 let s = srv!(self);
502 unsafe {
503 (s.set_slot_item)(s.ctx, YogStr::from_str(player), slot,
504 YogStr::from_str(item_id), count, YogStr::from_str(snbt))
505 }
506 }
507}
508
509macro_rules! trampoline_phased {
527 ($name:ident, $abi_ev:ty, $rust_ev:ty, |$ev:ident| $build:expr) => {
528 unsafe extern "C" fn $name<F>(
529 ud: *mut c_void, srv: *const YogServer, ev: *const $abi_ev, phase: u8,
530 ) -> bool
531 where F: Fn(&$rust_ev, EventPhase, &dyn Server) -> bool + Send + Sync,
532 {
533 let f = &*(ud as *const F);
534 let $ev = &*ev;
535 let rust_ev = $build;
536 let p = if phase == 0 { EventPhase::Pre } else { EventPhase::Post };
537 f(&rust_ev, p, &CServer(srv))
538 }
539 };
540}
541
542trampoline_phased!(trampoline_block_break, YogBlockBreakEvent, BlockBreakEvent, |ev| BlockBreakEvent {
543 player_name: ev.player.as_str().to_owned(),
544 block_id: ev.block.as_str().to_owned(),
545 pos: yog_core::BlockPos { x: ev.pos.x, y: ev.pos.y, z: ev.pos.z },
546});
547
548trampoline_phased!(trampoline_chat, YogChatEvent, ChatEvent, |ev| ChatEvent {
549 player_name: ev.player.as_str().to_owned(),
550 message: ev.message.as_str().to_owned(),
551});
552
553trampoline_phased!(trampoline_player_join, YogPlayerEvent, PlayerJoinEvent, |ev| PlayerJoinEvent {
554 player_name: ev.player.as_str().to_owned(),
555 uuid: ev.uuid.as_str().to_owned(),
556});
557
558trampoline_phased!(trampoline_player_leave, YogPlayerEvent, PlayerLeaveEvent, |ev| PlayerLeaveEvent {
559 player_name: ev.player.as_str().to_owned(),
560 uuid: ev.uuid.as_str().to_owned(),
561});
562
563trampoline_phased!(trampoline_use_item, YogUseItemEvent, UseItemEvent, |ev| UseItemEvent {
564 player_name: ev.player.as_str().to_owned(),
565 item_id: ev.item.as_str().to_owned(),
566 sneaking: ev.sneaking,
567});
568
569trampoline_phased!(trampoline_use_block, YogUseBlockEvent, UseBlockEvent, |ev| UseBlockEvent {
570 player_name: ev.player.as_str().to_owned(),
571 block_id: ev.block.as_str().to_owned(),
572 pos: yog_core::BlockPos { x: ev.pos.x, y: ev.pos.y, z: ev.pos.z },
573});
574
575trampoline_phased!(trampoline_attack_entity, YogAttackEntityEvent, AttackEntityEvent, |ev| AttackEntityEvent {
576 player_name: ev.player.as_str().to_owned(),
577 target_type: ev.target_type.as_str().to_owned(),
578 target_uuid: ev.target_uuid.as_str().to_owned(),
579});
580
581trampoline_phased!(trampoline_entity_damage, YogEntityDamageEvent, EntityDamageEvent, |ev| EntityDamageEvent {
582 entity_type: ev.entity_type.as_str().to_owned(),
583 uuid: ev.uuid.as_str().to_owned(),
584 amount: ev.amount,
585 source: ev.source.as_str().to_owned(),
586});
587
588trampoline_phased!(trampoline_entity_death, YogEntityDeathEvent, EntityDeathEvent, |ev| EntityDeathEvent {
589 entity_type: ev.entity_type.as_str().to_owned(),
590 uuid: ev.uuid.as_str().to_owned(),
591 source: ev.source.as_str().to_owned(),
592});
593
594trampoline_phased!(trampoline_entity_spawn, YogEntitySpawnEvent, EntitySpawnEvent, |ev| EntitySpawnEvent {
595 entity_type: ev.entity_type.as_str().to_owned(),
596 uuid: ev.uuid.as_str().to_owned(),
597 dimension: ev.dimension.as_str().to_owned(),
598});
599
600trampoline_phased!(trampoline_place_block, YogPlaceBlockEvent, PlaceBlockEvent, |ev| PlaceBlockEvent {
601 player_name: ev.player.as_str().to_owned(),
602 block_id: ev.block.as_str().to_owned(),
603 pos: yog_core::BlockPos { x: ev.pos.x, y: ev.pos.y, z: ev.pos.z },
604});
605
606trampoline_phased!(trampoline_player_death, YogPlayerDeathEvent, PlayerDeathEvent, |ev| PlayerDeathEvent {
607 player_name: ev.player.as_str().to_owned(),
608 uuid: ev.uuid.as_str().to_owned(),
609 source: ev.source.as_str().to_owned(),
610});
611
612trampoline_phased!(trampoline_player_respawn, YogPlayerRespawnEvent, PlayerRespawnEvent, |ev| PlayerRespawnEvent {
613 player_name: ev.player.as_str().to_owned(),
614 uuid: ev.uuid.as_str().to_owned(),
615 at_anchor: ev.at_anchor,
616});
617
618trampoline_phased!(trampoline_advancement, YogAdvancementEvent, AdvancementEvent, |ev| AdvancementEvent {
619 player_name: ev.player.as_str().to_owned(),
620 uuid: ev.uuid.as_str().to_owned(),
621 advancement_id: ev.advancement.as_str().to_owned(),
622});
623
624trampoline_phased!(trampoline_entity_interact, YogEntityInteractEvent, EntityInteractEvent, |ev| EntityInteractEvent {
625 player_name: ev.player.as_str().to_owned(),
626 player_uuid: ev.player_uuid.as_str().to_owned(),
627 entity_type: ev.entity_type.as_str().to_owned(),
628 entity_uuid: ev.entity_uuid.as_str().to_owned(),
629 hand: ev.hand.as_str().to_owned(),
630});
631
632trampoline_phased!(trampoline_craft, YogCraftEvent, CraftEvent, |ev| CraftEvent {
633 player_name: ev.player.as_str().to_owned(),
634 player_uuid: ev.player_uuid.as_str().to_owned(),
635 result_item: ev.result_item.as_str().to_owned(),
636 result_count: ev.result_count,
637});
638
639trampoline_phased!(trampoline_explosion, YogExplosionEvent, ExplosionEvent, |ev| ExplosionEvent {
640 dimension: ev.dimension.as_str().to_owned(),
641 x: ev.x,
642 y: ev.y,
643 z: ev.z,
644 power: ev.power,
645 cause_uuid: ev.cause_uuid.as_str().to_owned(),
646});
647
648trampoline_phased!(trampoline_item_pickup, YogItemPickupEvent, ItemPickupEvent, |ev| ItemPickupEvent {
649 player_name: ev.player.as_str().to_owned(),
650 player_uuid: ev.player_uuid.as_str().to_owned(),
651 item_id: ev.item_id.as_str().to_owned(),
652 item_count: ev.item_count,
653 entity_uuid: ev.entity_uuid.as_str().to_owned(),
654});
655
656trampoline_phased!(trampoline_player_move, YogPlayerMoveEvent, PlayerMoveEvent, |ev| PlayerMoveEvent {
657 player_name: ev.player.as_str().to_owned(),
658 player_uuid: ev.player_uuid.as_str().to_owned(),
659 x: ev.x,
660 y: ev.y,
661 z: ev.z,
662 yaw: ev.yaw,
663 pitch: ev.pitch,
664});
665
666trampoline_phased!(trampoline_container_open, YogContainerOpenEvent, ContainerOpenEvent, |ev| ContainerOpenEvent {
667 player_name: ev.player.as_str().to_owned(),
668 player_uuid: ev.player_uuid.as_str().to_owned(),
669 container_type: ev.container_type.as_str().to_owned(),
670});
671
672trampoline_phased!(trampoline_container_close, YogContainerCloseEvent, ContainerCloseEvent, |ev| ContainerCloseEvent {
673 player_name: ev.player.as_str().to_owned(),
674 player_uuid: ev.player_uuid.as_str().to_owned(),
675});
676
677trampoline_phased!(trampoline_projectile_hit, YogProjectileHitEvent, ProjectileHitEvent, |ev| ProjectileHitEvent {
678 projectile_type: ev.projectile_type.as_str().to_owned(),
679 projectile_uuid: ev.projectile_uuid.as_str().to_owned(),
680 shooter_uuid: ev.shooter_uuid.as_str().to_owned(),
681 hit_type: ev.hit_type.as_str().to_owned(),
682 hit_entity_uuid: ev.hit_entity_uuid.as_str().to_owned(),
683 x: ev.x,
684 y: ev.y,
685 z: ev.z,
686 dimension: ev.dimension.as_str().to_owned(),
687});
688
689unsafe extern "C" fn trampoline_server_fn<F>(ud: *mut c_void, srv: *const YogServer)
690where F: Fn(&dyn Server) + Send + Sync,
691{
692 let f = &*(ud as *const F);
693 f(&CServer(srv));
694}
695
696unsafe extern "C" fn trampoline_packet<F>(ud: *mut c_void, srv: *const YogServer, ev: *const YogPacketEvent)
697where F: Fn(&PacketEvent, &dyn Server) + Send + Sync,
698{
699 let f = &*(ud as *const F);
700 let ev = &*ev;
701 let rust_ev = PacketEvent {
702 channel: ev.channel.as_str().to_owned(),
703 player: ev.player.as_str().to_owned(),
704 payload: std::slice::from_raw_parts(ev.payload, ev.payload_len as usize).to_vec(),
705 };
706 f(&rust_ev, &CServer(srv));
707}
708
709unsafe extern "C" fn trampoline_command<F>(
710 ud: *mut c_void,
711 srv: *const YogServer,
712 ev: *const YogCommandEvent,
713 reply_buf: *mut u8,
714 reply_cap: u32,
715 reply_len: *mut u32,
716) where F: Fn(&CommandContext, &dyn Server) -> Option<String> + Send + Sync,
717{
718 let f = &*(ud as *const F);
719 let ev = &*ev;
720 let ctx = CommandContext {
721 name: ev.name.as_str().to_owned(),
722 args: ev.args.as_str().to_owned(),
723 source: ev.source.as_str().to_owned(),
724 uuid: ev.uuid.as_str().to_owned(),
725 };
726 *reply_len = 0;
727 if let Some(reply) = f(&ctx, &CServer(srv)) {
728 let bytes = reply.as_bytes();
729 let n = bytes.len().min(reply_cap as usize);
730 std::ptr::copy_nonoverlapping(bytes.as_ptr(), reply_buf, n);
731 *reply_len = n as u32;
732 }
733}
734
735unsafe extern "C" fn trampoline_scheduled<F>(ud: *mut c_void, srv: *const YogServer)
736where F: Fn(&dyn Server) + Send + Sync,
737{
738 let f = &*(ud as *const F);
739 f(&CServer(srv));
740}
741
742unsafe extern "C" fn trampoline_client_tick<F>(ud: *mut c_void)
745where F: Fn(&ClientTickEvent) + Send + Sync,
746{
747 let f = &*(ud as *const F);
748 f(&ClientTickEvent {});
749}
750
751unsafe extern "C" fn trampoline_hud_render<F>(ud: *mut c_void, gfx: *const YogGfxApi)
752where F: Fn(&GfxContext) + Send + Sync,
753{
754 let f = &*(ud as *const F);
755 f(&GfxContext::from_raw(gfx));
756}
757
758unsafe extern "C" fn trampoline_world_render<F>(ud: *mut c_void, gfx: *const YogGfxApi)
759where F: Fn(&GfxContext) + Send + Sync,
760{
761 let f = &*(ud as *const F);
762 f(&GfxContext::from_raw(gfx));
763}
764
765unsafe extern "C" fn trampoline_key_press<F>(
766 ud: *mut c_void,
767 ev: *const YogKeyPressEvent,
768) -> bool
769where F: Fn(&KeyPressEvent) -> bool + Send + Sync,
770{
771 let f = &*(ud as *const F);
772 let e = &*ev;
773 f(&KeyPressEvent {
774 key_code: e.key_code,
775 scan_code: e.scan_code,
776 action: e.action,
777 modifiers: e.modifiers,
778 })
779}
780
781unsafe extern "C" fn trampoline_screen<F>(ud: *mut c_void, screen_class: YogStr) -> bool
782where F: Fn(&ScreenEvent) + Send + Sync,
783{
784 let f = &*(ud as *const F);
785 f(&ScreenEvent { screen_class: screen_class.as_str().to_owned() });
786 true
787}
788
789static GLOBAL_API: std::sync::atomic::AtomicPtr<YogApi> =
800 std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());
801
802#[derive(Debug, Clone)]
804pub struct ModInfo {
805 pub source: String,
807 pub id: String,
808 pub name: String,
809 pub version: String,
810 pub authors: String,
812 pub description: String,
813}
814
815pub fn installed_mods() -> Vec<ModInfo> {
821 let api = GLOBAL_API.load(std::sync::atomic::Ordering::Acquire);
822 if api.is_null() { return Vec::new(); }
823 let owned = unsafe { ((*api).mods_list)((*api).ctx) };
824 if owned.is_none() { return Vec::new(); }
825 let text = unsafe {
826 String::from_utf8(
827 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
828 ).unwrap_or_default()
829 };
830 unsafe { ((*api).free_str)(owned.ptr, owned.len) };
831 text.lines()
832 .filter_map(|line| {
833 let mut f = line.split('\t');
834 Some(ModInfo {
835 source: f.next()?.to_string(),
836 id: f.next()?.to_string(),
837 name: f.next().unwrap_or_default().to_string(),
838 version: f.next().unwrap_or_default().to_string(),
839 authors: f.next().unwrap_or_default().to_string(),
840 description: f.next().unwrap_or_default().to_string(),
841 })
842 })
843 .collect()
844}
845
846pub fn open_ui(ui_id: &str, modal: bool, pause: bool) {
850 let api = GLOBAL_API.load(std::sync::atomic::Ordering::Acquire);
851 if api.is_null() { return; }
852 unsafe { ((*api).ui_open)((*api).ctx, YogStr::from_str(ui_id), modal, pause) }
853}
854
855pub fn server() -> Option<CServer> {
860 let api = GLOBAL_API.load(std::sync::atomic::Ordering::Acquire);
861 if api.is_null() { return None; }
862 let srv = unsafe { (*api).server };
863 if srv.is_null() { return None; }
864 Some(CServer(srv))
865}
866
867pub struct Registry {
868 api: *const YogApi,
869}
870
871unsafe impl Send for Registry {}
873unsafe impl Sync for Registry {}
874
875impl Registry {
876 pub unsafe fn from_raw(api: *const YogApi) -> Self {
878 GLOBAL_API.store(api as *mut YogApi, std::sync::atomic::Ordering::Release);
879 Self { api }
880 }
881
882 #[inline]
883 fn ctx(&self) -> *mut c_void { unsafe { (*self.api).ctx } }
884
885 fn leak<F: 'static>(f: F) -> *mut c_void {
888 Box::into_raw(Box::new(f)) as *mut c_void
889 }
890
891 pub fn on_block_break<F>(&mut self, handler: F)
899 where F: Fn(&BlockBreakEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
900 let ud = Self::leak(handler);
901 unsafe { ((*self.api).on_block_break)(self.ctx(), ud, trampoline_block_break::<F>) }
902 }
903
904 pub fn on_chat<F>(&mut self, handler: F)
905 where F: Fn(&ChatEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
906 let ud = Self::leak(handler);
907 unsafe { ((*self.api).on_chat)(self.ctx(), ud, trampoline_chat::<F>) }
908 }
909
910 pub fn on_player_join<F>(&mut self, handler: F)
911 where F: Fn(&PlayerJoinEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
912 let ud = Self::leak(handler);
913 unsafe { ((*self.api).on_player_join)(self.ctx(), ud, trampoline_player_join::<F>) }
914 }
915
916 pub fn on_player_leave<F>(&mut self, handler: F)
917 where F: Fn(&PlayerLeaveEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
918 let ud = Self::leak(handler);
919 unsafe { ((*self.api).on_player_leave)(self.ctx(), ud, trampoline_player_leave::<F>) }
920 }
921
922 pub fn on_use_item<F>(&mut self, handler: F)
923 where F: Fn(&UseItemEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
924 let ud = Self::leak(handler);
925 unsafe { ((*self.api).on_use_item)(self.ctx(), ud, trampoline_use_item::<F>) }
926 }
927
928 pub fn on_use_block<F>(&mut self, handler: F)
929 where F: Fn(&UseBlockEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
930 let ud = Self::leak(handler);
931 unsafe { ((*self.api).on_use_block)(self.ctx(), ud, trampoline_use_block::<F>) }
932 }
933
934 pub fn on_attack_entity<F>(&mut self, handler: F)
935 where F: Fn(&AttackEntityEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
936 let ud = Self::leak(handler);
937 unsafe { ((*self.api).on_attack_entity)(self.ctx(), ud, trampoline_attack_entity::<F>) }
938 }
939
940 pub fn on_entity_damage<F>(&mut self, handler: F)
941 where F: Fn(&EntityDamageEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
942 let ud = Self::leak(handler);
943 unsafe { ((*self.api).on_entity_damage)(self.ctx(), ud, trampoline_entity_damage::<F>) }
944 }
945
946 pub fn on_entity_death<F>(&mut self, handler: F)
947 where F: Fn(&EntityDeathEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
948 let ud = Self::leak(handler);
949 unsafe { ((*self.api).on_entity_death)(self.ctx(), ud, trampoline_entity_death::<F>) }
950 }
951
952 pub fn on_entity_spawn<F>(&mut self, handler: F)
953 where F: Fn(&EntitySpawnEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
954 let ud = Self::leak(handler);
955 unsafe { ((*self.api).on_entity_spawn)(self.ctx(), ud, trampoline_entity_spawn::<F>) }
956 }
957
958 pub fn on_player_place_block<F>(&mut self, handler: F)
959 where F: Fn(&PlaceBlockEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
960 let ud = Self::leak(handler);
961 unsafe { ((*self.api).on_player_place_block)(self.ctx(), ud, trampoline_place_block::<F>) }
962 }
963
964 pub fn on_player_death<F>(&mut self, handler: F)
965 where F: Fn(&PlayerDeathEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
966 let ud = Self::leak(handler);
967 unsafe { ((*self.api).on_player_death)(self.ctx(), ud, trampoline_player_death::<F>) }
968 }
969
970 pub fn on_player_respawn<F>(&mut self, handler: F)
971 where F: Fn(&PlayerRespawnEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
972 let ud = Self::leak(handler);
973 unsafe { ((*self.api).on_player_respawn)(self.ctx(), ud, trampoline_player_respawn::<F>) }
974 }
975
976 pub fn on_advancement<F>(&mut self, handler: F)
977 where F: Fn(&AdvancementEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
978 let ud = Self::leak(handler);
979 unsafe { ((*self.api).on_advancement)(self.ctx(), ud, trampoline_advancement::<F>) }
980 }
981
982 pub fn on_entity_interact<F>(&mut self, handler: F)
983 where F: Fn(&EntityInteractEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
984 let ud = Self::leak(handler);
985 unsafe { ((*self.api).on_entity_interact)(self.ctx(), ud, trampoline_entity_interact::<F>) }
986 }
987
988 pub fn on_item_craft<F>(&mut self, handler: F)
989 where F: Fn(&CraftEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
990 let ud = Self::leak(handler);
991 unsafe { ((*self.api).on_item_craft)(self.ctx(), ud, trampoline_craft::<F>) }
992 }
993
994 pub fn on_explosion<F>(&mut self, handler: F)
995 where F: Fn(&ExplosionEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
996 let ud = Self::leak(handler);
997 unsafe { ((*self.api).on_explosion)(self.ctx(), ud, trampoline_explosion::<F>) }
998 }
999
1000 pub fn on_item_pickup<F>(&mut self, handler: F)
1001 where F: Fn(&ItemPickupEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
1002 let ud = Self::leak(handler);
1003 unsafe { ((*self.api).on_item_pickup)(self.ctx(), ud, trampoline_item_pickup::<F>) }
1004 }
1005
1006 pub fn on_player_move<F>(&mut self, handler: F)
1007 where F: Fn(&PlayerMoveEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
1008 let ud = Self::leak(handler);
1009 unsafe { ((*self.api).on_player_move)(self.ctx(), ud, trampoline_player_move::<F>) }
1010 }
1011
1012 pub fn on_container_open<F>(&mut self, handler: F)
1013 where F: Fn(&ContainerOpenEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
1014 let ud = Self::leak(handler);
1015 unsafe { ((*self.api).on_container_open)(self.ctx(), ud, trampoline_container_open::<F>) }
1016 }
1017
1018 pub fn on_container_close<F>(&mut self, handler: F)
1019 where F: Fn(&ContainerCloseEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
1020 let ud = Self::leak(handler);
1021 unsafe { ((*self.api).on_container_close)(self.ctx(), ud, trampoline_container_close::<F>) }
1022 }
1023
1024 pub fn on_projectile_hit<F>(&mut self, handler: F)
1025 where F: Fn(&ProjectileHitEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
1026 let ud = Self::leak(handler);
1027 unsafe { ((*self.api).on_projectile_hit)(self.ctx(), ud, trampoline_projectile_hit::<F>) }
1028 }
1029
1030 pub fn on_tick<F>(&mut self, listener: F)
1031 where F: Fn(&dyn Server) + Send + Sync + 'static {
1032 let ud = Self::leak(listener);
1033 unsafe { ((*self.api).on_server_tick)(self.ctx(), ud, trampoline_server_fn::<F>) }
1034 }
1035
1036 pub fn on_server_started<F>(&mut self, listener: F)
1037 where F: Fn(&dyn Server) + Send + Sync + 'static {
1038 let ud = Self::leak(listener);
1039 unsafe { ((*self.api).on_server_started)(self.ctx(), ud, trampoline_server_fn::<F>) }
1040 }
1041
1042 pub fn on_server_stopping<F>(&mut self, listener: F)
1043 where F: Fn(&dyn Server) + Send + Sync + 'static {
1044 let ud = Self::leak(listener);
1045 unsafe { ((*self.api).on_server_stopping)(self.ctx(), ud, trampoline_server_fn::<F>) }
1046 }
1047
1048 pub fn on_command<F>(&mut self, name: impl AsRef<str>, handler: F)
1051 where F: Fn(&CommandContext, &dyn Server) -> Option<String> + Send + Sync + 'static {
1052 let name_ys = YogStr::from_str(name.as_ref());
1053 let ud = Self::leak(handler);
1054 unsafe { ((*self.api).register_command)(self.ctx(), name_ys, ud, trampoline_command::<F>) }
1055 }
1056
1057 pub fn on_typed_command<F>(&mut self, name: impl AsRef<str>, schema: impl AsRef<str>, handler: F)
1064 where F: Fn(&CommandContext, &dyn Server) -> Option<String> + Send + Sync + 'static {
1065 let name_ys = YogStr::from_str(name.as_ref());
1066 let schema_ys = YogStr::from_str(schema.as_ref());
1067 let ud = Self::leak(handler);
1068 unsafe { ((*self.api).register_typed_command)(self.ctx(), name_ys, schema_ys, ud, trampoline_command::<F>) }
1069 }
1070
1071 pub fn on_packet<F>(&mut self, channel: impl AsRef<str>, handler: F)
1074 where F: Fn(&PacketEvent, &dyn Server) + Send + Sync + 'static {
1075 let ch = YogStr::from_str(channel.as_ref());
1076 let ud = Self::leak(handler);
1077 unsafe { ((*self.api).on_packet)(self.ctx(), ch, ud, trampoline_packet::<F>) }
1078 }
1079
1080 pub fn on_client_packet<F>(&mut self, channel: impl AsRef<str>, handler: F)
1081 where F: Fn(&PacketEvent, &dyn Server) + Send + Sync + 'static {
1082 let ch = YogStr::from_str(channel.as_ref());
1083 let ud = Self::leak(handler);
1084 unsafe { ((*self.api).on_client_packet)(self.ctx(), ch, ud, trampoline_packet::<F>) }
1085 }
1086
1087 pub fn on_typed_packet<P, F>(&mut self, channel: impl AsRef<str>, handler: F)
1092 where
1093 P: Packet + Send + Sync + 'static,
1094 F: Fn(&P, &dyn Server) + Send + Sync + 'static,
1095 {
1096 self.on_packet(channel, move |ev, srv| {
1097 if let Some(pkt) = P::decode(&ev.payload) {
1098 handler(&pkt, srv);
1099 }
1100 });
1101 }
1102
1103 fn recipe(&mut self, ns: &str, name: &str, json: &str) {
1106 unsafe {
1107 ((*self.api).register_recipe_json)(
1108 self.ctx(),
1109 YogStr::from_str(ns), YogStr::from_str(name), YogStr::from_str(json),
1110 )
1111 }
1112 }
1113
1114 pub fn add_shaped_recipe(&mut self, recipe: ShapedRecipe) {
1116 let json = recipe.to_json();
1117 let (ns, name) = recipe.ns_name();
1118 self.recipe(ns, name, &json);
1119 }
1120
1121 pub fn add_shapeless_recipe(&mut self, recipe: ShapelessRecipe) {
1123 let json = recipe.to_json();
1124 let (ns, name) = recipe.ns_name();
1125 self.recipe(ns, name, &json);
1126 }
1127
1128 pub fn add_furnace_recipe(&mut self, recipe: FurnaceRecipe) {
1130 let json = recipe.to_json();
1131 let (ns, name) = recipe.ns_name();
1132 self.recipe(ns, name, &json);
1133 }
1134
1135 pub fn register_item(&mut self, def: ItemDef) {
1138 let food_nutrition = def.food.as_ref().map_or(0, |f| f.nutrition);
1142 let food_saturation = def.food.as_ref().map_or(0.0, |f| f.saturation);
1143 let food_always_eat = def.food.as_ref().map_or(false, |f| f.can_always_eat);
1144 let c = YogItemDef {
1145 id: YogStr::from_str(&def.id),
1146 max_stack: def.max_stack as u32,
1147 name: def.name.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1148 tooltip: def.tooltip.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1149 max_damage: def.max_damage,
1150 fire_resistant: def.fire_resistant,
1151 fuel_ticks: def.fuel_ticks,
1152 food_nutrition,
1153 food_saturation,
1154 food_always_eat,
1155 };
1156 unsafe { ((*self.api).register_item)(self.ctx(), &c) }
1157 }
1158
1159 pub fn register_block(&mut self, def: BlockDef) {
1160 let shape = def.shape.unwrap_or([0.0; 6]);
1161 let groups_joined = def.connect_groups.join(",");
1162 let c = YogBlockDef {
1163 id: YogStr::from_str(&def.id),
1164 hardness: def.hardness,
1165 resistance: def.resistance,
1166 name: def.name.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1167 light_level: def.light_level,
1168 sound: def.sound.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1169 requires_tool: def.requires_tool,
1170 no_collision: def.no_collision,
1171 slipperiness: def.slipperiness,
1172 shape,
1173 connects: def.connects,
1174 connect_groups: YogStr::from_str(&groups_joined),
1175 };
1176 unsafe { ((*self.api).register_block)(self.ctx(), &c) }
1177 }
1178
1179 pub fn register_startup_grant(&mut self, grant: StartupGrant) {
1183 let items_str = grant.items.join("|");
1184 let c = YogStartupGrantDef {
1185 id: YogStr::from_str(&grant.id),
1186 items: YogStr::from_str(&items_str),
1187 book: grant.book.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1188 command: grant.command.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1189 };
1190 unsafe { ((*self.api).register_startup_grant)(self.ctx(), &c) }
1191 }
1192
1193 pub fn register_book(&mut self, book: &Book) {
1195 let json = book.to_json();
1196 let id = YogStr::from_str(&book.id);
1197 let j = YogStr::from_str(&json);
1198 unsafe { ((*self.api).register_book)(self.ctx(), id, j) }
1199 }
1200
1201
1202 pub fn installed_mods(&self) -> Vec<ModInfo> {
1209 installed_mods()
1210 }
1211
1212 pub fn register_menu_entry(&mut self, label: &str, ui_id: &str) {
1213 let l = YogStr::from_str(label);
1214 let u = YogStr::from_str(ui_id);
1215 unsafe { ((*self.api).register_menu_entry)(self.ctx(), l, u) }
1216 }
1217
1218 pub fn register_ui<F>(&mut self, ui_id: &str, handler: F)
1222 where F: Fn(&str, &str) + Send + Sync + 'static {
1223 let ud = Self::leak(handler);
1224 let id = YogStr::from_str(ui_id);
1225 let empty = YogStr::from_str("{}");
1226 unsafe {
1227 ((*self.api).register_ui)(self.ctx(), id, empty, ud, trampoline_ui_event::<F>)
1228 }
1229 }
1230
1231 pub fn schedule_once<F>(&self, delay_ticks: u64, handler: F)
1234 where F: Fn(&dyn Server) + Send + Sync + 'static {
1235 let ud = Self::leak(handler);
1236 unsafe { ((*self.api).schedule_once)(self.ctx(), delay_ticks, ud, trampoline_scheduled::<F>) }
1237 }
1238
1239 pub fn schedule_repeating<F>(&self, period_ticks: u64, handler: F)
1240 where F: Fn(&dyn Server) + Send + Sync + 'static {
1241 let ud = Self::leak(handler);
1242 unsafe { ((*self.api).schedule_repeating)(self.ctx(), period_ticks, ud, trampoline_scheduled::<F>) }
1243 }
1244
1245 pub fn on_client_tick<F>(&mut self, handler: F)
1249 where F: Fn(&ClientTickEvent) + Send + Sync + 'static {
1250 let ud = Self::leak(handler);
1251 unsafe { ((*self.api).on_client_tick)(self.ctx(), ud, trampoline_client_tick::<F>) }
1252 }
1253
1254 pub fn on_ui_render<F>(&mut self, ui_id: &str, handler: F)
1263 where F: Fn(&GfxContext) + Send + Sync + 'static {
1264 let ud = Self::leak(handler);
1265 let id = YogStr::from_str(ui_id);
1266 unsafe { ((*self.api).on_ui_render)(self.ctx(), id, ud, trampoline_hud_render::<F>) }
1267 }
1268
1269 pub fn on_hud_render<F>(&mut self, handler: F)
1274 where F: Fn(&GfxContext) + Send + Sync + 'static {
1275 let ud = Self::leak(handler);
1276 unsafe { ((*self.api).on_hud_render)(self.ctx(), ud, trampoline_hud_render::<F>) }
1277 }
1278
1279 pub fn on_world_render<F>(&mut self, handler: F)
1285 where F: Fn(&GfxContext) + Send + Sync + 'static {
1286 let ud = Self::leak(handler);
1287 unsafe { ((*self.api).on_world_render)(self.ctx(), ud, trampoline_world_render::<F>) }
1288 }
1289
1290 pub fn on_key_press<F>(&mut self, handler: F)
1293 where F: Fn(&KeyPressEvent) -> bool + Send + Sync + 'static {
1294 let ud = Self::leak(handler);
1295 unsafe { ((*self.api).on_key_press)(self.ctx(), ud, trampoline_key_press::<F>) }
1296 }
1297
1298 pub fn on_screen_open<F>(&mut self, handler: F)
1300 where F: Fn(&ScreenEvent) + Send + Sync + 'static {
1301 let ud = Self::leak(handler);
1302 unsafe { ((*self.api).on_screen_open)(self.ctx(), ud, trampoline_screen::<F>) }
1303 }
1304
1305 pub fn on_screen_close<F>(&mut self, handler: F)
1307 where F: Fn(&ScreenEvent) + Send + Sync + 'static {
1308 let ud = Self::leak(handler);
1309 unsafe { ((*self.api).on_screen_close)(self.ctx(), ud, trampoline_screen::<F>) }
1310 }
1311}
1312
1313unsafe extern "C" fn trampoline_ui_event<F>(ud: *mut c_void, ui_id: yog_abi::YogStr, event_id: yog_abi::YogStr)
1314where F: Fn(&str, &str) + Send + Sync + 'static
1315{
1316 let f = &*(ud as *const F);
1317 let ui = unsafe { ui_id.as_str() };
1318 let ev = unsafe { event_id.as_str() };
1319 f(ui, ev);
1320}
1321
1322pub trait Mod {
1326 fn register(registry: &mut Registry);
1327}