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 send_actionbar(&self, player: &str, message: &str) -> bool {
270 let s = srv!(self);
271 unsafe { (s.send_actionbar)(s.ctx, YogStr::from_str(player), YogStr::from_str(message)) }
272 }
273
274 fn kick_player(&self, player: &str, reason: &str) -> bool {
275 let s = srv!(self);
276 unsafe { (s.kick_player)(s.ctx, YogStr::from_str(player), YogStr::from_str(reason)) }
277 }
278
279 fn set_gamemode(&self, player: &str, gamemode: &str) -> bool {
280 let s = srv!(self);
281 unsafe { (s.set_gamemode)(s.ctx, YogStr::from_str(player), YogStr::from_str(gamemode)) }
282 }
283
284 fn bossbar_create(&self, id: &str, title: &str, color: &str, style: &str) -> bool {
285 let s = srv!(self);
286 unsafe { (s.bossbar_create)(s.ctx, YogStr::from_str(id), YogStr::from_str(title), YogStr::from_str(color), YogStr::from_str(style)) }
287 }
288
289 fn bossbar_remove(&self, id: &str) -> bool {
290 let s = srv!(self);
291 unsafe { (s.bossbar_remove)(s.ctx, YogStr::from_str(id)) }
292 }
293
294 fn bossbar_set_title(&self, id: &str, title: &str) -> bool {
295 let s = srv!(self);
296 unsafe { (s.bossbar_set_title)(s.ctx, YogStr::from_str(id), YogStr::from_str(title)) }
297 }
298
299 fn bossbar_set_progress(&self, id: &str, progress: f32) -> bool {
300 let s = srv!(self);
301 unsafe { (s.bossbar_set_progress)(s.ctx, YogStr::from_str(id), progress) }
302 }
303
304 fn bossbar_set_color(&self, id: &str, color: &str) -> bool {
305 let s = srv!(self);
306 unsafe { (s.bossbar_set_color)(s.ctx, YogStr::from_str(id), YogStr::from_str(color)) }
307 }
308
309 fn bossbar_add_player(&self, id: &str, player: &str) -> bool {
310 let s = srv!(self);
311 unsafe { (s.bossbar_add_player)(s.ctx, YogStr::from_str(id), YogStr::from_str(player)) }
312 }
313
314 fn bossbar_remove_player(&self, id: &str, player: &str) -> bool {
315 let s = srv!(self);
316 unsafe { (s.bossbar_remove_player)(s.ctx, YogStr::from_str(id), YogStr::from_str(player)) }
317 }
318
319 fn bossbar_set_visible(&self, id: &str, visible: bool) -> bool {
320 let s = srv!(self);
321 unsafe { (s.bossbar_set_visible)(s.ctx, YogStr::from_str(id), visible) }
322 }
323
324 fn online_players(&self) -> Vec<String> {
325 let s = srv!(self);
326 let owned = unsafe { (s.online_players)(s.ctx) };
327 if owned.is_none() { return Vec::new(); }
328 let text = unsafe {
329 String::from_utf8(
330 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
331 ).unwrap_or_default()
332 };
333 unsafe { (s.free_str)(owned.ptr, owned.len) };
334 if text.is_empty() { Vec::new() } else { text.lines().map(str::to_owned).collect() }
335 }
336
337 fn get_block_nbt(&self, dimension: &str, pos: yog_core::BlockPos) -> Option<String> {
338 let s = srv!(self);
339 let owned = unsafe {
340 (s.get_block_nbt)(s.ctx, YogStr::from_str(dimension),
341 yog_abi::YogBlockPos { x: pos.x, y: pos.y, z: pos.z })
342 };
343 if owned.is_none() { return None; }
344 let result = unsafe {
345 String::from_utf8(
346 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
347 ).ok()
348 };
349 unsafe { (s.free_str)(owned.ptr, owned.len) };
350 result
351 }
352
353 fn set_block_nbt(&self, dimension: &str, pos: yog_core::BlockPos, snbt: &str) -> bool {
354 let s = srv!(self);
355 unsafe {
356 (s.set_block_nbt)(s.ctx, YogStr::from_str(dimension),
357 yog_abi::YogBlockPos { x: pos.x, y: pos.y, z: pos.z },
358 YogStr::from_str(snbt))
359 }
360 }
361
362 fn player_inventory(&self, player: &str) -> Vec<(u32, String, u32)> {
363 let s = srv!(self);
364 let owned = unsafe { (s.player_inventory)(s.ctx, YogStr::from_str(player)) };
365 if owned.is_none() { return Vec::new(); }
366 let text = unsafe {
367 String::from_utf8(
368 std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()
369 ).unwrap_or_default()
370 };
371 unsafe { (s.free_str)(owned.ptr, owned.len) };
372 text.lines().filter_map(|line| {
373 let mut it = line.split('\t');
374 let slot: u32 = it.next()?.parse().ok()?;
375 let item_id = it.next()?.to_owned();
376 let count: u32 = it.next()?.parse().ok()?;
377 Some((slot, item_id, count))
378 }).collect()
379 }
380
381 fn player_set_slot(&self, player: &str, slot: u32, item_id: &str, count: u32) -> bool {
382 let s = srv!(self);
383 unsafe {
384 (s.player_set_slot)(s.ctx, YogStr::from_str(player), slot, YogStr::from_str(item_id), count)
385 }
386 }
387
388 fn teleport_to_dim(&self, player: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool {
389 let s = srv!(self);
390 unsafe {
391 (s.player_teleport_dim)(s.ctx, YogStr::from_str(player),
392 YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z })
393 }
394 }
395
396 fn entity_teleport_to_dim(&self, uuid: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool {
397 let s = srv!(self);
398 unsafe {
399 (s.entity_teleport_dim)(s.ctx, YogStr::from_str(uuid),
400 YogStr::from_str(dimension), yog_abi::YogVec3 { x, y, z })
401 }
402 }
403
404 fn world_entity_count(&self, dimension: &str, entity_type: &str) -> i32 {
405 let s = srv!(self);
406 unsafe { (s.world_entity_count)(s.ctx, YogStr::from_str(dimension), YogStr::from_str(entity_type)) }
407 }
408
409 fn entity_get_nbt(&self, uuid: &str) -> Option<String> {
410 let s = srv!(self);
411 let owned = unsafe { (s.entity_get_nbt)(s.ctx, YogStr::from_str(uuid)) };
412 if owned.is_none() { return None; }
413 let result = unsafe {
414 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()).ok()
415 };
416 unsafe { (s.free_str)(owned.ptr, owned.len) };
417 result
418 }
419
420 fn entity_set_nbt(&self, uuid: &str, snbt: &str) -> bool {
421 let s = srv!(self);
422 unsafe { (s.entity_set_nbt)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(snbt)) }
423 }
424
425 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 {
426 let s = srv!(self);
427 unsafe {
428 (s.spawn_particles)(s.ctx, YogStr::from_str(dimension),
429 yog_abi::YogVec3 { x, y, z }, YogStr::from_str(particle_type),
430 count, dx, dy, dz, speed)
431 }
432 }
433
434 fn entity_attribute_get(&self, uuid: &str, attribute_id: &str) -> Option<f64> {
435 let s = srv!(self);
436 let v = unsafe { (s.entity_attribute_get)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(attribute_id)) };
437 if v.is_nan() { None } else { Some(v) }
438 }
439
440 fn entity_attribute_set(&self, uuid: &str, attribute_id: &str, value: f64) -> bool {
441 let s = srv!(self);
442 unsafe { (s.entity_attribute_set)(s.ctx, YogStr::from_str(uuid), YogStr::from_str(attribute_id), value) }
443 }
444
445 fn get_held_item_nbt(&self, player: &str) -> Option<String> {
446 let s = srv!(self);
447 let owned = unsafe { (s.get_held_item_nbt)(s.ctx, YogStr::from_str(player)) };
448 if owned.is_none() { return None; }
449 let result = unsafe {
450 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()).ok()
451 };
452 unsafe { (s.free_str)(owned.ptr, owned.len) };
453 result
454 }
455
456 fn set_held_item_nbt(&self, player: &str, snbt: &str) -> bool {
457 let s = srv!(self);
458 unsafe { (s.set_held_item_nbt)(s.ctx, YogStr::from_str(player), YogStr::from_str(snbt)) }
459 }
460
461 fn get_offhand_item_nbt(&self, player: &str) -> Option<String> {
462 let s = srv!(self);
463 let owned = unsafe { (s.get_offhand_item_nbt)(s.ctx, YogStr::from_str(player)) };
464 if owned.is_none() { return None; }
465 let result = unsafe {
466 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec()).ok()
467 };
468 unsafe { (s.free_str)(owned.ptr, owned.len) };
469 result
470 }
471
472 fn set_offhand_item_nbt(&self, player: &str, snbt: &str) -> bool {
473 let s = srv!(self);
474 unsafe { (s.set_offhand_item_nbt)(s.ctx, YogStr::from_str(player), YogStr::from_str(snbt)) }
475 }
476
477 fn get_slot_item(&self, player: &str, slot: u32) -> Option<(String, u32, String)> {
478 let s = srv!(self);
479 let owned = unsafe { (s.get_slot_item)(s.ctx, YogStr::from_str(player), slot) };
480 if owned.is_none() { return None; }
481 let text = unsafe {
482 String::from_utf8(std::slice::from_raw_parts(owned.ptr, owned.len as usize).to_vec())
483 .unwrap_or_default()
484 };
485 unsafe { (s.free_str)(owned.ptr, owned.len) };
486 let mut it = text.splitn(3, '\t');
487 let item_id = it.next()?.to_owned();
488 let count: u32 = it.next()?.parse().ok()?;
489 let nbt = it.next().unwrap_or("{}").to_owned();
490 Some((item_id, count, nbt))
491 }
492
493 fn set_slot_item(&self, player: &str, slot: u32, item_id: &str, count: u32, snbt: &str) -> bool {
494 let s = srv!(self);
495 unsafe {
496 (s.set_slot_item)(s.ctx, YogStr::from_str(player), slot,
497 YogStr::from_str(item_id), count, YogStr::from_str(snbt))
498 }
499 }
500}
501
502macro_rules! trampoline_phased {
520 ($name:ident, $abi_ev:ty, $rust_ev:ty, |$ev:ident| $build:expr) => {
521 unsafe extern "C" fn $name<F>(
522 ud: *mut c_void, srv: *const YogServer, ev: *const $abi_ev, phase: u8,
523 ) -> bool
524 where F: Fn(&$rust_ev, EventPhase, &dyn Server) -> bool + Send + Sync,
525 {
526 let f = &*(ud as *const F);
527 let $ev = &*ev;
528 let rust_ev = $build;
529 let p = if phase == 0 { EventPhase::Pre } else { EventPhase::Post };
530 f(&rust_ev, p, &CServer(srv))
531 }
532 };
533}
534
535trampoline_phased!(trampoline_block_break, YogBlockBreakEvent, BlockBreakEvent, |ev| BlockBreakEvent {
536 player_name: ev.player.as_str().to_owned(),
537 block_id: ev.block.as_str().to_owned(),
538 pos: yog_core::BlockPos { x: ev.pos.x, y: ev.pos.y, z: ev.pos.z },
539});
540
541trampoline_phased!(trampoline_chat, YogChatEvent, ChatEvent, |ev| ChatEvent {
542 player_name: ev.player.as_str().to_owned(),
543 message: ev.message.as_str().to_owned(),
544});
545
546trampoline_phased!(trampoline_player_join, YogPlayerEvent, PlayerJoinEvent, |ev| PlayerJoinEvent {
547 player_name: ev.player.as_str().to_owned(),
548 uuid: ev.uuid.as_str().to_owned(),
549});
550
551trampoline_phased!(trampoline_player_leave, YogPlayerEvent, PlayerLeaveEvent, |ev| PlayerLeaveEvent {
552 player_name: ev.player.as_str().to_owned(),
553 uuid: ev.uuid.as_str().to_owned(),
554});
555
556trampoline_phased!(trampoline_use_item, YogUseItemEvent, UseItemEvent, |ev| UseItemEvent {
557 player_name: ev.player.as_str().to_owned(),
558 item_id: ev.item.as_str().to_owned(),
559});
560
561trampoline_phased!(trampoline_use_block, YogUseBlockEvent, UseBlockEvent, |ev| UseBlockEvent {
562 player_name: ev.player.as_str().to_owned(),
563 block_id: ev.block.as_str().to_owned(),
564 pos: yog_core::BlockPos { x: ev.pos.x, y: ev.pos.y, z: ev.pos.z },
565});
566
567trampoline_phased!(trampoline_attack_entity, YogAttackEntityEvent, AttackEntityEvent, |ev| AttackEntityEvent {
568 player_name: ev.player.as_str().to_owned(),
569 target_type: ev.target_type.as_str().to_owned(),
570 target_uuid: ev.target_uuid.as_str().to_owned(),
571});
572
573trampoline_phased!(trampoline_entity_damage, YogEntityDamageEvent, EntityDamageEvent, |ev| EntityDamageEvent {
574 entity_type: ev.entity_type.as_str().to_owned(),
575 uuid: ev.uuid.as_str().to_owned(),
576 amount: ev.amount,
577 source: ev.source.as_str().to_owned(),
578});
579
580trampoline_phased!(trampoline_entity_death, YogEntityDeathEvent, EntityDeathEvent, |ev| EntityDeathEvent {
581 entity_type: ev.entity_type.as_str().to_owned(),
582 uuid: ev.uuid.as_str().to_owned(),
583 source: ev.source.as_str().to_owned(),
584});
585
586trampoline_phased!(trampoline_entity_spawn, YogEntitySpawnEvent, EntitySpawnEvent, |ev| EntitySpawnEvent {
587 entity_type: ev.entity_type.as_str().to_owned(),
588 uuid: ev.uuid.as_str().to_owned(),
589 dimension: ev.dimension.as_str().to_owned(),
590});
591
592trampoline_phased!(trampoline_place_block, YogPlaceBlockEvent, PlaceBlockEvent, |ev| PlaceBlockEvent {
593 player_name: ev.player.as_str().to_owned(),
594 block_id: ev.block.as_str().to_owned(),
595 pos: yog_core::BlockPos { x: ev.pos.x, y: ev.pos.y, z: ev.pos.z },
596});
597
598trampoline_phased!(trampoline_player_death, YogPlayerDeathEvent, PlayerDeathEvent, |ev| PlayerDeathEvent {
599 player_name: ev.player.as_str().to_owned(),
600 uuid: ev.uuid.as_str().to_owned(),
601 source: ev.source.as_str().to_owned(),
602});
603
604trampoline_phased!(trampoline_player_respawn, YogPlayerRespawnEvent, PlayerRespawnEvent, |ev| PlayerRespawnEvent {
605 player_name: ev.player.as_str().to_owned(),
606 uuid: ev.uuid.as_str().to_owned(),
607 at_anchor: ev.at_anchor,
608});
609
610trampoline_phased!(trampoline_advancement, YogAdvancementEvent, AdvancementEvent, |ev| AdvancementEvent {
611 player_name: ev.player.as_str().to_owned(),
612 uuid: ev.uuid.as_str().to_owned(),
613 advancement_id: ev.advancement.as_str().to_owned(),
614});
615
616trampoline_phased!(trampoline_entity_interact, YogEntityInteractEvent, EntityInteractEvent, |ev| EntityInteractEvent {
617 player_name: ev.player.as_str().to_owned(),
618 player_uuid: ev.player_uuid.as_str().to_owned(),
619 entity_type: ev.entity_type.as_str().to_owned(),
620 entity_uuid: ev.entity_uuid.as_str().to_owned(),
621 hand: ev.hand.as_str().to_owned(),
622});
623
624trampoline_phased!(trampoline_craft, YogCraftEvent, CraftEvent, |ev| CraftEvent {
625 player_name: ev.player.as_str().to_owned(),
626 player_uuid: ev.player_uuid.as_str().to_owned(),
627 result_item: ev.result_item.as_str().to_owned(),
628 result_count: ev.result_count,
629});
630
631trampoline_phased!(trampoline_explosion, YogExplosionEvent, ExplosionEvent, |ev| ExplosionEvent {
632 dimension: ev.dimension.as_str().to_owned(),
633 x: ev.x,
634 y: ev.y,
635 z: ev.z,
636 power: ev.power,
637 cause_uuid: ev.cause_uuid.as_str().to_owned(),
638});
639
640trampoline_phased!(trampoline_item_pickup, YogItemPickupEvent, ItemPickupEvent, |ev| ItemPickupEvent {
641 player_name: ev.player.as_str().to_owned(),
642 player_uuid: ev.player_uuid.as_str().to_owned(),
643 item_id: ev.item_id.as_str().to_owned(),
644 item_count: ev.item_count,
645 entity_uuid: ev.entity_uuid.as_str().to_owned(),
646});
647
648trampoline_phased!(trampoline_player_move, YogPlayerMoveEvent, PlayerMoveEvent, |ev| PlayerMoveEvent {
649 player_name: ev.player.as_str().to_owned(),
650 player_uuid: ev.player_uuid.as_str().to_owned(),
651 x: ev.x,
652 y: ev.y,
653 z: ev.z,
654 yaw: ev.yaw,
655 pitch: ev.pitch,
656});
657
658trampoline_phased!(trampoline_container_open, YogContainerOpenEvent, ContainerOpenEvent, |ev| ContainerOpenEvent {
659 player_name: ev.player.as_str().to_owned(),
660 player_uuid: ev.player_uuid.as_str().to_owned(),
661 container_type: ev.container_type.as_str().to_owned(),
662});
663
664trampoline_phased!(trampoline_container_close, YogContainerCloseEvent, ContainerCloseEvent, |ev| ContainerCloseEvent {
665 player_name: ev.player.as_str().to_owned(),
666 player_uuid: ev.player_uuid.as_str().to_owned(),
667});
668
669trampoline_phased!(trampoline_projectile_hit, YogProjectileHitEvent, ProjectileHitEvent, |ev| ProjectileHitEvent {
670 projectile_type: ev.projectile_type.as_str().to_owned(),
671 projectile_uuid: ev.projectile_uuid.as_str().to_owned(),
672 shooter_uuid: ev.shooter_uuid.as_str().to_owned(),
673 hit_type: ev.hit_type.as_str().to_owned(),
674 hit_entity_uuid: ev.hit_entity_uuid.as_str().to_owned(),
675 x: ev.x,
676 y: ev.y,
677 z: ev.z,
678 dimension: ev.dimension.as_str().to_owned(),
679});
680
681unsafe extern "C" fn trampoline_server_fn<F>(ud: *mut c_void, srv: *const YogServer)
682where F: Fn(&dyn Server) + Send + Sync,
683{
684 let f = &*(ud as *const F);
685 f(&CServer(srv));
686}
687
688unsafe extern "C" fn trampoline_packet<F>(ud: *mut c_void, srv: *const YogServer, ev: *const YogPacketEvent)
689where F: Fn(&PacketEvent, &dyn Server) + Send + Sync,
690{
691 let f = &*(ud as *const F);
692 let ev = &*ev;
693 let rust_ev = PacketEvent {
694 channel: ev.channel.as_str().to_owned(),
695 player: ev.player.as_str().to_owned(),
696 payload: std::slice::from_raw_parts(ev.payload, ev.payload_len as usize).to_vec(),
697 };
698 f(&rust_ev, &CServer(srv));
699}
700
701unsafe extern "C" fn trampoline_command<F>(
702 ud: *mut c_void,
703 srv: *const YogServer,
704 ev: *const YogCommandEvent,
705 reply_buf: *mut u8,
706 reply_cap: u32,
707 reply_len: *mut u32,
708) where F: Fn(&CommandContext, &dyn Server) -> Option<String> + Send + Sync,
709{
710 let f = &*(ud as *const F);
711 let ev = &*ev;
712 let ctx = CommandContext {
713 name: ev.name.as_str().to_owned(),
714 args: ev.args.as_str().to_owned(),
715 source: ev.source.as_str().to_owned(),
716 uuid: ev.uuid.as_str().to_owned(),
717 };
718 *reply_len = 0;
719 if let Some(reply) = f(&ctx, &CServer(srv)) {
720 let bytes = reply.as_bytes();
721 let n = bytes.len().min(reply_cap as usize);
722 std::ptr::copy_nonoverlapping(bytes.as_ptr(), reply_buf, n);
723 *reply_len = n as u32;
724 }
725}
726
727unsafe extern "C" fn trampoline_scheduled<F>(ud: *mut c_void, srv: *const YogServer)
728where F: Fn(&dyn Server) + Send + Sync,
729{
730 let f = &*(ud as *const F);
731 f(&CServer(srv));
732}
733
734unsafe extern "C" fn trampoline_client_tick<F>(ud: *mut c_void)
737where F: Fn(&ClientTickEvent) + Send + Sync,
738{
739 let f = &*(ud as *const F);
740 f(&ClientTickEvent {});
741}
742
743unsafe extern "C" fn trampoline_hud_render<F>(ud: *mut c_void, gfx: *const YogGfxApi)
744where F: Fn(&GfxContext) + Send + Sync,
745{
746 let f = &*(ud as *const F);
747 f(&GfxContext::from_raw(gfx));
748}
749
750unsafe extern "C" fn trampoline_world_render<F>(ud: *mut c_void, gfx: *const YogGfxApi)
751where F: Fn(&GfxContext) + Send + Sync,
752{
753 let f = &*(ud as *const F);
754 f(&GfxContext::from_raw(gfx));
755}
756
757unsafe extern "C" fn trampoline_key_press<F>(
758 ud: *mut c_void,
759 ev: *const YogKeyPressEvent,
760) -> bool
761where F: Fn(&KeyPressEvent) -> bool + Send + Sync,
762{
763 let f = &*(ud as *const F);
764 let e = &*ev;
765 f(&KeyPressEvent {
766 key_code: e.key_code,
767 scan_code: e.scan_code,
768 action: e.action,
769 modifiers: e.modifiers,
770 })
771}
772
773unsafe extern "C" fn trampoline_screen<F>(ud: *mut c_void, screen_class: YogStr) -> bool
774where F: Fn(&ScreenEvent) + Send + Sync,
775{
776 let f = &*(ud as *const F);
777 f(&ScreenEvent { screen_class: screen_class.as_str().to_owned() });
778 true
779}
780
781pub struct Registry {
789 api: *const YogApi,
790}
791
792unsafe impl Send for Registry {}
794unsafe impl Sync for Registry {}
795
796impl Registry {
797 pub unsafe fn from_raw(api: *const YogApi) -> Self {
799 Self { api }
800 }
801
802 #[inline]
803 fn ctx(&self) -> *mut c_void { unsafe { (*self.api).ctx } }
804
805 fn leak<F: 'static>(f: F) -> *mut c_void {
808 Box::into_raw(Box::new(f)) as *mut c_void
809 }
810
811 pub fn on_block_break<F>(&mut self, handler: F)
819 where F: Fn(&BlockBreakEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
820 let ud = Self::leak(handler);
821 unsafe { ((*self.api).on_block_break)(self.ctx(), ud, trampoline_block_break::<F>) }
822 }
823
824 pub fn on_chat<F>(&mut self, handler: F)
825 where F: Fn(&ChatEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
826 let ud = Self::leak(handler);
827 unsafe { ((*self.api).on_chat)(self.ctx(), ud, trampoline_chat::<F>) }
828 }
829
830 pub fn on_player_join<F>(&mut self, handler: F)
831 where F: Fn(&PlayerJoinEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
832 let ud = Self::leak(handler);
833 unsafe { ((*self.api).on_player_join)(self.ctx(), ud, trampoline_player_join::<F>) }
834 }
835
836 pub fn on_player_leave<F>(&mut self, handler: F)
837 where F: Fn(&PlayerLeaveEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
838 let ud = Self::leak(handler);
839 unsafe { ((*self.api).on_player_leave)(self.ctx(), ud, trampoline_player_leave::<F>) }
840 }
841
842 pub fn on_use_item<F>(&mut self, handler: F)
843 where F: Fn(&UseItemEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
844 let ud = Self::leak(handler);
845 unsafe { ((*self.api).on_use_item)(self.ctx(), ud, trampoline_use_item::<F>) }
846 }
847
848 pub fn on_use_block<F>(&mut self, handler: F)
849 where F: Fn(&UseBlockEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
850 let ud = Self::leak(handler);
851 unsafe { ((*self.api).on_use_block)(self.ctx(), ud, trampoline_use_block::<F>) }
852 }
853
854 pub fn on_attack_entity<F>(&mut self, handler: F)
855 where F: Fn(&AttackEntityEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
856 let ud = Self::leak(handler);
857 unsafe { ((*self.api).on_attack_entity)(self.ctx(), ud, trampoline_attack_entity::<F>) }
858 }
859
860 pub fn on_entity_damage<F>(&mut self, handler: F)
861 where F: Fn(&EntityDamageEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
862 let ud = Self::leak(handler);
863 unsafe { ((*self.api).on_entity_damage)(self.ctx(), ud, trampoline_entity_damage::<F>) }
864 }
865
866 pub fn on_entity_death<F>(&mut self, handler: F)
867 where F: Fn(&EntityDeathEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
868 let ud = Self::leak(handler);
869 unsafe { ((*self.api).on_entity_death)(self.ctx(), ud, trampoline_entity_death::<F>) }
870 }
871
872 pub fn on_entity_spawn<F>(&mut self, handler: F)
873 where F: Fn(&EntitySpawnEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
874 let ud = Self::leak(handler);
875 unsafe { ((*self.api).on_entity_spawn)(self.ctx(), ud, trampoline_entity_spawn::<F>) }
876 }
877
878 pub fn on_player_place_block<F>(&mut self, handler: F)
879 where F: Fn(&PlaceBlockEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
880 let ud = Self::leak(handler);
881 unsafe { ((*self.api).on_player_place_block)(self.ctx(), ud, trampoline_place_block::<F>) }
882 }
883
884 pub fn on_player_death<F>(&mut self, handler: F)
885 where F: Fn(&PlayerDeathEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
886 let ud = Self::leak(handler);
887 unsafe { ((*self.api).on_player_death)(self.ctx(), ud, trampoline_player_death::<F>) }
888 }
889
890 pub fn on_player_respawn<F>(&mut self, handler: F)
891 where F: Fn(&PlayerRespawnEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
892 let ud = Self::leak(handler);
893 unsafe { ((*self.api).on_player_respawn)(self.ctx(), ud, trampoline_player_respawn::<F>) }
894 }
895
896 pub fn on_advancement<F>(&mut self, handler: F)
897 where F: Fn(&AdvancementEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
898 let ud = Self::leak(handler);
899 unsafe { ((*self.api).on_advancement)(self.ctx(), ud, trampoline_advancement::<F>) }
900 }
901
902 pub fn on_entity_interact<F>(&mut self, handler: F)
903 where F: Fn(&EntityInteractEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
904 let ud = Self::leak(handler);
905 unsafe { ((*self.api).on_entity_interact)(self.ctx(), ud, trampoline_entity_interact::<F>) }
906 }
907
908 pub fn on_item_craft<F>(&mut self, handler: F)
909 where F: Fn(&CraftEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
910 let ud = Self::leak(handler);
911 unsafe { ((*self.api).on_item_craft)(self.ctx(), ud, trampoline_craft::<F>) }
912 }
913
914 pub fn on_explosion<F>(&mut self, handler: F)
915 where F: Fn(&ExplosionEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
916 let ud = Self::leak(handler);
917 unsafe { ((*self.api).on_explosion)(self.ctx(), ud, trampoline_explosion::<F>) }
918 }
919
920 pub fn on_item_pickup<F>(&mut self, handler: F)
921 where F: Fn(&ItemPickupEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
922 let ud = Self::leak(handler);
923 unsafe { ((*self.api).on_item_pickup)(self.ctx(), ud, trampoline_item_pickup::<F>) }
924 }
925
926 pub fn on_player_move<F>(&mut self, handler: F)
927 where F: Fn(&PlayerMoveEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
928 let ud = Self::leak(handler);
929 unsafe { ((*self.api).on_player_move)(self.ctx(), ud, trampoline_player_move::<F>) }
930 }
931
932 pub fn on_container_open<F>(&mut self, handler: F)
933 where F: Fn(&ContainerOpenEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
934 let ud = Self::leak(handler);
935 unsafe { ((*self.api).on_container_open)(self.ctx(), ud, trampoline_container_open::<F>) }
936 }
937
938 pub fn on_container_close<F>(&mut self, handler: F)
939 where F: Fn(&ContainerCloseEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
940 let ud = Self::leak(handler);
941 unsafe { ((*self.api).on_container_close)(self.ctx(), ud, trampoline_container_close::<F>) }
942 }
943
944 pub fn on_projectile_hit<F>(&mut self, handler: F)
945 where F: Fn(&ProjectileHitEvent, EventPhase, &dyn Server) -> bool + Send + Sync + 'static {
946 let ud = Self::leak(handler);
947 unsafe { ((*self.api).on_projectile_hit)(self.ctx(), ud, trampoline_projectile_hit::<F>) }
948 }
949
950 pub fn on_tick<F>(&mut self, listener: F)
951 where F: Fn(&dyn Server) + Send + Sync + 'static {
952 let ud = Self::leak(listener);
953 unsafe { ((*self.api).on_server_tick)(self.ctx(), ud, trampoline_server_fn::<F>) }
954 }
955
956 pub fn on_server_started<F>(&mut self, listener: F)
957 where F: Fn(&dyn Server) + Send + Sync + 'static {
958 let ud = Self::leak(listener);
959 unsafe { ((*self.api).on_server_started)(self.ctx(), ud, trampoline_server_fn::<F>) }
960 }
961
962 pub fn on_server_stopping<F>(&mut self, listener: F)
963 where F: Fn(&dyn Server) + Send + Sync + 'static {
964 let ud = Self::leak(listener);
965 unsafe { ((*self.api).on_server_stopping)(self.ctx(), ud, trampoline_server_fn::<F>) }
966 }
967
968 pub fn on_command<F>(&mut self, name: impl AsRef<str>, handler: F)
971 where F: Fn(&CommandContext, &dyn Server) -> Option<String> + Send + Sync + 'static {
972 let name_ys = YogStr::from_str(name.as_ref());
973 let ud = Self::leak(handler);
974 unsafe { ((*self.api).register_command)(self.ctx(), name_ys, ud, trampoline_command::<F>) }
975 }
976
977 pub fn on_typed_command<F>(&mut self, name: impl AsRef<str>, schema: impl AsRef<str>, handler: F)
984 where F: Fn(&CommandContext, &dyn Server) -> Option<String> + Send + Sync + 'static {
985 let name_ys = YogStr::from_str(name.as_ref());
986 let schema_ys = YogStr::from_str(schema.as_ref());
987 let ud = Self::leak(handler);
988 unsafe { ((*self.api).register_typed_command)(self.ctx(), name_ys, schema_ys, ud, trampoline_command::<F>) }
989 }
990
991 pub fn on_packet<F>(&mut self, channel: impl AsRef<str>, handler: F)
994 where F: Fn(&PacketEvent, &dyn Server) + Send + Sync + 'static {
995 let ch = YogStr::from_str(channel.as_ref());
996 let ud = Self::leak(handler);
997 unsafe { ((*self.api).on_packet)(self.ctx(), ch, ud, trampoline_packet::<F>) }
998 }
999
1000 pub fn on_client_packet<F>(&mut self, channel: impl AsRef<str>, handler: F)
1001 where F: Fn(&PacketEvent, &dyn Server) + Send + Sync + 'static {
1002 let ch = YogStr::from_str(channel.as_ref());
1003 let ud = Self::leak(handler);
1004 unsafe { ((*self.api).on_client_packet)(self.ctx(), ch, ud, trampoline_packet::<F>) }
1005 }
1006
1007 pub fn on_typed_packet<P, F>(&mut self, channel: impl AsRef<str>, handler: F)
1012 where
1013 P: Packet + Send + Sync + 'static,
1014 F: Fn(&P, &dyn Server) + Send + Sync + 'static,
1015 {
1016 self.on_packet(channel, move |ev, srv| {
1017 if let Some(pkt) = P::decode(&ev.payload) {
1018 handler(&pkt, srv);
1019 }
1020 });
1021 }
1022
1023 fn recipe(&mut self, ns: &str, name: &str, json: &str) {
1026 unsafe {
1027 ((*self.api).register_recipe_json)(
1028 self.ctx(),
1029 YogStr::from_str(ns), YogStr::from_str(name), YogStr::from_str(json),
1030 )
1031 }
1032 }
1033
1034 pub fn add_shaped_recipe(&mut self, recipe: ShapedRecipe) {
1036 let json = recipe.to_json();
1037 let (ns, name) = recipe.ns_name();
1038 self.recipe(ns, name, &json);
1039 }
1040
1041 pub fn add_shapeless_recipe(&mut self, recipe: ShapelessRecipe) {
1043 let json = recipe.to_json();
1044 let (ns, name) = recipe.ns_name();
1045 self.recipe(ns, name, &json);
1046 }
1047
1048 pub fn add_furnace_recipe(&mut self, recipe: FurnaceRecipe) {
1050 let json = recipe.to_json();
1051 let (ns, name) = recipe.ns_name();
1052 self.recipe(ns, name, &json);
1053 }
1054
1055 pub fn register_item(&mut self, def: ItemDef) {
1058 let food_nutrition = def.food.as_ref().map_or(0, |f| f.nutrition);
1062 let food_saturation = def.food.as_ref().map_or(0.0, |f| f.saturation);
1063 let food_always_eat = def.food.as_ref().map_or(false, |f| f.can_always_eat);
1064 let c = YogItemDef {
1065 id: YogStr::from_str(&def.id),
1066 max_stack: def.max_stack as u32,
1067 name: def.name.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1068 tooltip: def.tooltip.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1069 max_damage: def.max_damage,
1070 fire_resistant: def.fire_resistant,
1071 fuel_ticks: def.fuel_ticks,
1072 food_nutrition,
1073 food_saturation,
1074 food_always_eat,
1075 };
1076 unsafe { ((*self.api).register_item)(self.ctx(), &c) }
1077 }
1078
1079 pub fn register_block(&mut self, def: BlockDef) {
1080 let shape = def.shape.unwrap_or([0.0; 6]);
1081 let c = YogBlockDef {
1082 id: YogStr::from_str(&def.id),
1083 hardness: def.hardness,
1084 resistance: def.resistance,
1085 name: def.name.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1086 light_level: def.light_level,
1087 sound: def.sound.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1088 requires_tool: def.requires_tool,
1089 no_collision: def.no_collision,
1090 slipperiness: def.slipperiness,
1091 shape,
1092 };
1093 unsafe { ((*self.api).register_block)(self.ctx(), &c) }
1094 }
1095
1096 pub fn register_startup_grant(&mut self, grant: StartupGrant) {
1100 let items_str = grant.items.join("|");
1101 let c = YogStartupGrantDef {
1102 id: YogStr::from_str(&grant.id),
1103 items: YogStr::from_str(&items_str),
1104 book: grant.book.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1105 command: grant.command.as_deref().map(YogStr::from_str).unwrap_or(YogStr::EMPTY),
1106 };
1107 unsafe { ((*self.api).register_startup_grant)(self.ctx(), &c) }
1108 }
1109
1110 pub fn register_book(&mut self, book: &Book) {
1112 let json = book.to_json();
1113 let id = YogStr::from_str(&book.id);
1114 let j = YogStr::from_str(&json);
1115 unsafe { ((*self.api).register_book)(self.ctx(), id, j) }
1116 }
1117
1118
1119 pub fn register_ui<F>(&mut self, ui_id: &str, handler: F)
1123 where F: Fn(&str, &str) + Send + Sync + 'static {
1124 let ud = Self::leak(handler);
1125 let id = YogStr::from_str(ui_id);
1126 let empty = YogStr::from_str("{}");
1127 unsafe {
1128 ((*self.api).register_ui)(self.ctx(), id, empty, ud, trampoline_ui_event::<F>)
1129 }
1130 }
1131
1132 pub fn schedule_once<F>(&self, delay_ticks: u64, handler: F)
1135 where F: Fn(&dyn Server) + Send + Sync + 'static {
1136 let ud = Self::leak(handler);
1137 unsafe { ((*self.api).schedule_once)(self.ctx(), delay_ticks, ud, trampoline_scheduled::<F>) }
1138 }
1139
1140 pub fn schedule_repeating<F>(&self, period_ticks: u64, handler: F)
1141 where F: Fn(&dyn Server) + Send + Sync + 'static {
1142 let ud = Self::leak(handler);
1143 unsafe { ((*self.api).schedule_repeating)(self.ctx(), period_ticks, ud, trampoline_scheduled::<F>) }
1144 }
1145
1146 pub fn on_client_tick<F>(&mut self, handler: F)
1150 where F: Fn(&ClientTickEvent) + Send + Sync + 'static {
1151 let ud = Self::leak(handler);
1152 unsafe { ((*self.api).on_client_tick)(self.ctx(), ud, trampoline_client_tick::<F>) }
1153 }
1154
1155 pub fn on_hud_render<F>(&mut self, handler: F)
1160 where F: Fn(&GfxContext) + Send + Sync + 'static {
1161 let ud = Self::leak(handler);
1162 unsafe { ((*self.api).on_hud_render)(self.ctx(), ud, trampoline_hud_render::<F>) }
1163 }
1164
1165 pub fn on_world_render<F>(&mut self, handler: F)
1171 where F: Fn(&GfxContext) + Send + Sync + 'static {
1172 let ud = Self::leak(handler);
1173 unsafe { ((*self.api).on_world_render)(self.ctx(), ud, trampoline_world_render::<F>) }
1174 }
1175
1176 pub fn on_key_press<F>(&mut self, handler: F)
1179 where F: Fn(&KeyPressEvent) -> bool + Send + Sync + 'static {
1180 let ud = Self::leak(handler);
1181 unsafe { ((*self.api).on_key_press)(self.ctx(), ud, trampoline_key_press::<F>) }
1182 }
1183
1184 pub fn on_screen_open<F>(&mut self, handler: F)
1186 where F: Fn(&ScreenEvent) + Send + Sync + 'static {
1187 let ud = Self::leak(handler);
1188 unsafe { ((*self.api).on_screen_open)(self.ctx(), ud, trampoline_screen::<F>) }
1189 }
1190
1191 pub fn on_screen_close<F>(&mut self, handler: F)
1193 where F: Fn(&ScreenEvent) + Send + Sync + 'static {
1194 let ud = Self::leak(handler);
1195 unsafe { ((*self.api).on_screen_close)(self.ctx(), ud, trampoline_screen::<F>) }
1196 }
1197}
1198
1199unsafe extern "C" fn trampoline_ui_event<F>(ud: *mut c_void, ui_id: yog_abi::YogStr, event_id: yog_abi::YogStr)
1200where F: Fn(&str, &str) + Send + Sync + 'static
1201{
1202 let f = &*(ud as *const F);
1203 let ui = unsafe { ui_id.as_str() };
1204 let ev = unsafe { event_id.as_str() };
1205 f(ui, ev);
1206}
1207
1208pub trait Mod {
1212 fn register(registry: &mut Registry);
1213}