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