Skip to main content

yog_core/
server.rs

1//! The handle Rust mods use to act on the running server — the Rust → Minecraft
2//! path.
3
4use crate::{BlockHit, BlockInfo, BlockPos, EntityInfo, Face, PlayerInfo};
5
6/// Low-level capabilities the Yog runtime exposes to mods (the engine contract).
7///
8/// The runtime provides the concrete implementation, backed by JNI calls into
9/// the Java host; this crate stays JVM-free. Higher-level, ergonomic wrappers
10/// live in the domain crates (e.g. `yog-world`'s `World`).
11///
12/// Dimensions are identified by their registry id string, e.g.
13/// `"minecraft:overworld"`.
14pub trait Server {
15    /// Broadcast a chat message to all players on the server.
16    fn broadcast(&self, message: &str);
17
18    /// Registry id of the block at `pos` in `dimension`
19    /// (e.g. `"minecraft:stone"`), or `None` if the dimension/position is
20    /// unavailable. Call from the server thread (e.g. an event handler).
21    fn get_block(&self, dimension: &str, pos: BlockPos) -> Option<String>;
22
23    /// Set the block at `pos` in `dimension` to `block_id` — a registry id
24    /// or, like `/setblock`, a state (`"minecraft:water_cauldron[level=3]"`).
25    /// Returns whether the change was applied. Call from the server thread.
26    fn set_block(&self, dimension: &str, pos: BlockPos, block_id: &str) -> bool;
27
28    /// Give `count` of `item_id` to the named player. Returns whether it worked
29    /// (player online, item valid). Call from the server thread.
30    fn give_item(&self, player: &str, item_id: &str, count: u32) -> bool;
31
32    /// Teleport the named player to `(x, y, z)` in their current world. Returns
33    /// whether it worked. Call from the server thread.
34    fn teleport(&self, player: &str, x: f64, y: f64, z: f64) -> bool;
35
36    /// Send a raw-byte packet to the named player on `channel` (server → client).
37    /// Returns whether the player was online. Payload is opaque bytes — no NBT.
38    fn send_to_player(&self, player: &str, channel: &str, payload: &[u8]) -> bool;
39
40    /// Send a raw-byte packet to the server on `channel` (client → server).
41    /// Only works in a client context; returns whether it was sent.
42    fn send_to_server(&self, channel: &str, payload: &[u8]) -> bool;
43
44    // ── entity (universal, by UUID) ─────────────────────────────────────────
45
46    /// Teleport any entity (by UUID) within its current world.
47    fn entity_teleport(&self, uuid: &str, x: f64, y: f64, z: f64) -> bool;
48
49    /// Position of an entity, or `None` if not loaded.
50    fn entity_position(&self, uuid: &str) -> Option<(f64, f64, f64)>;
51
52    /// Health of a living entity, or `None`.
53    fn entity_health(&self, uuid: &str) -> Option<f32>;
54
55    /// Set a living entity's health; returns whether it applied.
56    fn entity_set_health(&self, uuid: &str, health: f32) -> bool;
57
58    /// Remove/kill an entity.
59    fn entity_kill(&self, uuid: &str) -> bool;
60
61    /// Spawn an entity of `entity_type` (e.g. `minecraft:pig`) at a position;
62    /// returns its UUID, or `None` on failure.
63    fn spawn_entity(
64        &self,
65        entity_type: &str,
66        dimension: &str,
67        x: f64,
68        y: f64,
69        z: f64,
70    ) -> Option<String>;
71
72    // ── status effects ──────────────────────────────────────────────────────
73
74    /// Apply a status effect to a living entity. `effect_id` is a registry id
75    /// such as `"minecraft:speed"` or `"minecraft:regeneration"`. `amplifier` is
76    /// 0-based (0 = level I). Returns `false` if the entity or effect is unknown.
77    fn entity_add_effect(
78        &self,
79        uuid: &str,
80        effect_id: &str,
81        duration_ticks: i32,
82        amplifier: u8,
83        show_particles: bool,
84    ) -> bool;
85
86    /// Remove a single status effect from a living entity.
87    fn entity_remove_effect(&self, uuid: &str, effect_id: &str) -> bool;
88
89    /// Clear all active status effects from a living entity.
90    fn entity_clear_effects(&self, uuid: &str) -> bool;
91
92    // ── loot tables ─────────────────────────────────────────────────────────
93
94    /// Roll a loot table and spawn the resulting item entities in the world.
95    /// `table_id` is the namespaced id, e.g. `"minecraft:entities/zombie"`.
96    fn drop_loot(&self, table_id: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool;
97
98    // ── tag queries ─────────────────────────────────────────────────────────
99
100    /// Returns whether `item_id` (e.g. `"minecraft:stone"`) belongs to `tag_id`
101    /// (e.g. `"minecraft:planks"`).
102    fn has_item_tag(&self, item_id: &str, tag_id: &str) -> bool;
103
104    /// Returns whether `block_id` belongs to `tag_id`.
105    fn has_block_tag(&self, block_id: &str, tag_id: &str) -> bool;
106
107    // ── world state ─────────────────────────────────────────────────────────
108
109    /// Game time in ticks since world creation (never wraps, keeps counting).
110    fn world_time(&self, dimension: &str) -> Option<i64>;
111
112    /// Set the time-of-day (0 = dawn, 6000 = noon, 12000 = dusk, 18000 = midnight).
113    /// Only changes the visual time, not the absolute world age.
114    fn world_set_time(&self, dimension: &str, time: i64) -> bool;
115
116    /// Whether it is currently raining in the given dimension.
117    fn world_is_raining(&self, dimension: &str) -> bool;
118
119    /// Start or stop rain. `duration_ticks` controls how long the weather lasts
120    /// (use 0 for a server-chosen default duration).
121    fn world_set_weather(&self, dimension: &str, raining: bool, duration_ticks: i32) -> bool;
122
123    // ── entity velocity ─────────────────────────────────────────────────────
124
125    /// Current velocity `(vx, vy, vz)` of any entity, or `None` if not loaded.
126    fn entity_velocity(&self, uuid: &str) -> Option<(f64, f64, f64)>;
127
128    /// Set the velocity of any entity. Returns `false` if not loaded.
129    fn entity_set_velocity(&self, uuid: &str, vx: f64, vy: f64, vz: f64) -> bool;
130
131    /// Add a velocity impulse (cumulative with existing velocity).
132    fn entity_add_velocity(&self, uuid: &str, vx: f64, vy: f64, vz: f64) -> bool;
133
134    // ── scoreboard ──────────────────────────────────────────────────────────
135
136    /// Score of `player` on `objective`, or `None` if the objective doesn't exist.
137    fn scoreboard_get(&self, objective: &str, player: &str) -> Option<i32>;
138
139    /// Set the score; returns `false` if the objective doesn't exist.
140    fn scoreboard_set(&self, objective: &str, player: &str, score: i32) -> bool;
141
142    /// Add `delta` to the score (negative = subtract). Returns the new score,
143    /// or `None` if the objective doesn't exist.
144    fn scoreboard_add(&self, objective: &str, player: &str, delta: i32) -> Option<i32>;
145
146    // ── sound ───────────────────────────────────────────────────────────────
147
148    /// Play a sound at `(x, y, z)` in `dimension`. `sound_id` is a registry id
149    /// (e.g. `"minecraft:entity.player.levelup"`). All players within range hear
150    /// it. Returns `false` if the dimension is unknown.
151    fn play_sound(
152        &self,
153        dimension: &str,
154        x: f64,
155        y: f64,
156        z: f64,
157        sound_id: &str,
158        volume: f32,
159        pitch: f32,
160    ) -> bool;
161
162    /// Play a sound at the named player's current position. All players nearby
163    /// (including the target) hear it. Returns `false` if the player is offline.
164    fn play_sound_to_player(&self, player: &str, sound_id: &str, volume: f32, pitch: f32) -> bool;
165
166    // ── title / actionbar ───────────────────────────────────────────────────
167
168    /// Send a title+subtitle screen to a player. Pass empty strings to omit
169    /// either line. Timings are in ticks (20 ticks = 1 second).
170    fn send_title(
171        &self,
172        player: &str,
173        title: &str,
174        subtitle: &str,
175        fadein: i32,
176        stay: i32,
177        fadeout: i32,
178    ) -> bool;
179
180    /// Send a short message to the action-bar (the line just above the hotbar).
181    fn send_actionbar(&self, player: &str, message: &str) -> bool;
182
183    /// Yaw and pitch (degrees) of an entity by UUID, or `None` if it does not
184    /// exist. Minecraft convention: yaw 0 = south, positive pitch looks down.
185    fn entity_rotation(&self, uuid: &str) -> Option<(f32, f32)>;
186
187    // ── player management ───────────────────────────────────────────────────
188
189    /// Disconnect `player` with the given `reason` message.
190    fn kick_player(&self, player: &str, reason: &str) -> bool;
191
192    /// Change a player's game mode. `gamemode` is one of `"survival"`,
193    /// `"creative"`, `"adventure"`, `"spectator"` (or the abbreviations
194    /// `"s"`, `"c"`, `"a"`, `"sp"`). Returns `false` if the player is offline
195    /// or `gamemode` is unrecognised.
196    fn set_gamemode(&self, player: &str, gamemode: &str) -> bool;
197
198    // ── boss bar ────────────────────────────────────────────────────────────
199
200    /// Create a new boss bar identified by `id` (a namespaced id such as
201    /// `"mymod:progress"`). `color`: `"pink"` / `"blue"` / `"red"` / `"green"` /
202    /// `"yellow"` / `"purple"` / `"white"`. `style`: `"progress"` /
203    /// `"notched_6"` / `"notched_10"` / `"notched_12"` / `"notched_20"`.
204    /// Returns `false` if a bar with that id already exists.
205    fn bossbar_create(&self, id: &str, title: &str, color: &str, style: &str) -> bool;
206
207    /// Remove a boss bar (also removes it from all players). Returns `false` if
208    /// the bar doesn't exist.
209    fn bossbar_remove(&self, id: &str) -> bool;
210
211    /// Update the displayed title of a boss bar.
212    fn bossbar_set_title(&self, id: &str, title: &str) -> bool;
213
214    /// Set the fill level of a boss bar (0.0 = empty, 1.0 = full).
215    fn bossbar_set_progress(&self, id: &str, progress: f32) -> bool;
216
217    /// Change the color of a boss bar (same color names as [`bossbar_create`]).
218    fn bossbar_set_color(&self, id: &str, color: &str) -> bool;
219
220    /// Add an online player to the boss bar's audience.
221    fn bossbar_add_player(&self, id: &str, player: &str) -> bool;
222
223    /// Remove a player from the boss bar's audience.
224    fn bossbar_remove_player(&self, id: &str, player: &str) -> bool;
225
226    /// Show or hide a boss bar for all its current audience members.
227    fn bossbar_set_visible(&self, id: &str, visible: bool) -> bool;
228
229    // ── misc ────────────────────────────────────────────────────────────────
230
231    /// Absolute path of the game / server root directory.
232    fn game_dir(&self) -> String;
233
234    /// Names of all currently connected players.
235    fn online_players(&self) -> Vec<String>;
236
237    // ── block entity ─────────────────────────────────────────────────────────
238
239    /// SNBT string of the block entity at `pos` (e.g. chest contents, furnace
240    /// state, sign text). Returns `None` if there is no block entity there.
241    fn get_block_nbt(&self, dimension: &str, pos: BlockPos) -> Option<String>;
242
243    /// Write `snbt` data into the block entity at `pos` and mark it dirty.
244    /// Returns `false` if there is no block entity at that position.
245    fn set_block_nbt(&self, dimension: &str, pos: BlockPos, snbt: &str) -> bool;
246
247    // ── inventory-backed block slots (yog-inventory) ─────────────────────────
248
249    /// `(item_id, count)` of one slot of the inventory-backed block at `pos`
250    /// (see `yog_inventory::InventoryDef`). Returns `None` if the slot is
251    /// empty, or there is no such inventory at that position.
252    fn get_inventory_slot(
253        &self,
254        dimension: &str,
255        pos: BlockPos,
256        slot: u32,
257    ) -> Option<(String, u32)>;
258
259    /// Set (or clear when `count == 0`) one slot of the inventory-backed
260    /// block at `pos`. Returns `false` if there is no such inventory there.
261    fn set_inventory_slot(
262        &self,
263        dimension: &str,
264        pos: BlockPos,
265        slot: u32,
266        item_id: &str,
267        count: u32,
268    ) -> bool;
269
270    // ── inventory ────────────────────────────────────────────────────────────
271
272    /// All occupied inventory slots of an online player.
273    /// Returns one entry per occupied slot: `(slot_index, item_id, count)`.
274    fn player_inventory(&self, player: &str) -> Vec<(u32, String, u32)>;
275
276    /// Set (or clear when `count == 0`) one inventory slot of an online player.
277    fn player_set_slot(&self, player: &str, slot: u32, item_id: &str, count: u32) -> bool;
278
279    // ── cross-dimension teleport ─────────────────────────────────────────────
280
281    /// Teleport a player to `(x, y, z)` in a different (or same) dimension.
282    fn teleport_to_dim(&self, player: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool;
283
284    /// Teleport any entity (by UUID) to `(x, y, z)` in `dimension`.
285    fn entity_teleport_to_dim(&self, uuid: &str, dimension: &str, x: f64, y: f64, z: f64) -> bool;
286
287    // ── entity query ─────────────────────────────────────────────────────────
288
289    /// Number of loaded entities of `entity_type` (e.g. `"minecraft:zombie"`)
290    /// in `dimension`. Returns `-1` if the dimension or entity type is unknown.
291    fn world_entity_count(&self, dimension: &str, entity_type: &str) -> i32;
292
293    // ── entity NBT ───────────────────────────────────────────────────────────
294
295    /// SNBT string of the entity's persistent NBT, or `None` if not found.
296    fn entity_get_nbt(&self, uuid: &str) -> Option<String>;
297
298    /// Merge SNBT data into the entity's persistent NBT. Returns `false` if not found.
299    fn entity_set_nbt(&self, uuid: &str, snbt: &str) -> bool;
300
301    // ── particles ────────────────────────────────────────────────────────────
302
303    /// Spawn `count` particles at `(x, y, z)` in `dimension`.
304    /// `particle_type` is a particle id or, like `/particle`, an id with its
305    /// options (`"minecraft:dust 1 0.5 0 1"`).
306    /// `dx/dy/dz` control the spatial spread; `speed` controls particle velocity.
307    fn spawn_particles(
308        &self,
309        dimension: &str,
310        x: f64,
311        y: f64,
312        z: f64,
313        particle_type: &str,
314        count: i32,
315        dx: f64,
316        dy: f64,
317        dz: f64,
318        speed: f64,
319    ) -> bool;
320
321    // ── attributes ───────────────────────────────────────────────────────────
322
323    /// Get the base value of an attribute on a living entity.
324    /// `attribute_id` e.g. `"minecraft:generic.max_health"`.
325    /// Returns `None` if the entity or attribute is not found.
326    fn entity_attribute_get(&self, uuid: &str, attribute_id: &str) -> Option<f64>;
327
328    /// Set the base value of an attribute. Returns false if not found.
329    fn entity_attribute_set(&self, uuid: &str, attribute_id: &str, value: f64) -> bool;
330
331    // ── held item NBT (ABI minor 11) ─────────────────────────────────────────
332
333    /// SNBT string of the item currently held in the player's main hand.
334    /// Returns `None` if the player is offline or holding air.
335    fn get_held_item_nbt(&self, player: &str) -> Option<String>;
336
337    /// Merge `snbt` data into the NBT of the item in the player's main hand.
338    /// Returns `false` if the player is offline or holding air.
339    fn set_held_item_nbt(&self, player: &str, snbt: &str) -> bool;
340
341    // ── item stack query (ABI minor 12) ──────────────────────────────────────
342
343    /// SNBT of the item in the player's off hand.
344    /// Returns `None` if offline or holding air.
345    fn get_offhand_item_nbt(&self, player: &str) -> Option<String>;
346
347    /// Merge `snbt` into the NBT of the player's off-hand item.
348    /// Returns `false` if offline or holding air.
349    fn set_offhand_item_nbt(&self, player: &str, snbt: &str) -> bool;
350
351    /// Full item stack at inventory `slot`: `(item_id, count, nbt_snbt)`.
352    /// `nbt_snbt` is `"{}"` when the item has no NBT.
353    /// Returns `None` if the player is offline or the slot is empty.
354    fn get_slot_item(&self, player: &str, slot: u32) -> Option<(String, u32, String)>;
355
356    /// Replace inventory `slot`. Pass `count == 0` to clear the slot.
357    /// `snbt` is merged into the new item's NBT (pass `""` for no NBT).
358    fn set_slot_item(&self, player: &str, slot: u32, item_id: &str, count: u32, snbt: &str)
359        -> bool;
360
361    // ── world queries & effects (ABI minor 1) ────────────────────────────────
362
363    /// Type, position, size and kind of a loaded entity, or `None` if no
364    /// entity has that uuid.
365    fn entity_info(&self, uuid: &str) -> Option<EntityInfo>;
366
367    /// Uuids of the entities whose bounding boxes touch the box `min`–`max`
368    /// in `dimension`.
369    fn entities_in_box(
370        &self,
371        dimension: &str,
372        min: (f64, f64, f64),
373        max: (f64, f64, f64),
374    ) -> Vec<String>;
375
376    /// The first block with a collision shape on the segment `from`–`to`
377    /// (fluids are ignored).
378    fn raycast_block(
379        &self,
380        dimension: &str,
381        from: (f64, f64, f64),
382        to: (f64, f64, f64),
383    ) -> Option<BlockHit>;
384
385    /// The nearest pickable entity whose (slightly inflated) bounding box the
386    /// segment `from`–`to` crosses, other than `exclude` (a uuid, or `""`)
387    /// and whatever it rides.
388    fn raycast_entity(
389        &self,
390        dimension: &str,
391        from: (f64, f64, f64),
392        to: (f64, f64, f64),
393        exclude: &str,
394    ) -> Option<String>;
395
396    /// State, hardness, fluid and redstone power of the block at `pos`.
397    fn block_info(&self, dimension: &str, pos: BlockPos) -> Option<BlockInfo>;
398
399    /// Break the block at `pos` as `breaker` (a player name, or `""`):
400    /// plays the break effects and, if `drop`, drops its loot as if mined
401    /// with an empty hand. Returns `false` for air and unbreakable blocks.
402    fn break_block(&self, dimension: &str, pos: BlockPos, drop: bool, breaker: &str) -> bool;
403
404    /// Place the block item in the player's inventory `slot` at `pos`, as if
405    /// the player clicked the block below it: the item's own placement
406    /// rules apply and one item is used up (unless creative).
407    fn place_block_from_slot(
408        &self,
409        player: &str,
410        slot: u32,
411        dimension: &str,
412        pos: BlockPos,
413    ) -> bool;
414
415    /// Apply bone meal to the block at `pos`. Returns whether it grew.
416    fn bonemeal(&self, dimension: &str, pos: BlockPos) -> bool;
417
418    /// An explosion of `power` (TNT is 4) at `pos`, caused by entity
419    /// `source` (a uuid, or `""`); `fire` sets fires like a ghast fireball.
420    #[allow(clippy::too_many_arguments)]
421    fn explode(
422        &self,
423        dimension: &str,
424        x: f64,
425        y: f64,
426        z: f64,
427        power: f32,
428        fire: bool,
429        source: &str,
430    ) -> bool;
431
432    /// A system chat message to one player, like `/tellraw`: `json` is a
433    /// JSON text component, so it can hold translation keys
434    /// (`{"translate":"mymod.msg","with":["x"]}`) that each client shows in
435    /// its own language.
436    fn tellraw(&self, player: &str, json: &str) -> bool;
437
438    /// Hurt an entity. `damage_type` is a damage type id
439    /// (`"minecraft:magic"`, `"minecraft:drown"`, …; `""` picks one from
440    /// the attacker: player attack, mob attack, or magic without one), and
441    /// `attacker` the uuid of the entity responsible (or `""`). An unknown
442    /// damage type falls back to magic. Returns whether it took the damage.
443    fn entity_damage(&self, uuid: &str, amount: f32, damage_type: &str, attacker: &str) -> bool;
444
445    /// Set an entity on fire for `ticks` (`0` puts it out).
446    fn entity_set_fire_ticks(&self, uuid: &str, ticks: i32) -> bool;
447
448    /// Give (or, negative, take) experience points.
449    fn player_add_xp(&self, player: &str, amount: i32) -> bool;
450
451    /// Let a player fly (creative-style) or take it away (also stops them
452    /// flying). Game mode changes reset it.
453    fn player_set_may_fly(&self, player: &str, may_fly: bool) -> bool;
454
455    /// Game mode, selected slot, experience, air and flight of a player.
456    fn player_info(&self, player: &str) -> Option<PlayerInfo>;
457
458    /// Drop an item stack into the world with velocity `vel`; `snbt` is the
459    /// stack's NBT (`""` for none). Returns the item entity's uuid.
460    #[allow(clippy::too_many_arguments)]
461    fn spawn_item(
462        &self,
463        dimension: &str,
464        pos: (f64, f64, f64),
465        vel: (f64, f64, f64),
466        item_id: &str,
467        count: u32,
468        snbt: &str,
469    ) -> Option<String>;
470
471    /// The stack inside a dropped item entity: `(item_id, count, snbt)`.
472    fn item_entity_stack(&self, uuid: &str) -> Option<(String, u32, String)>;
473
474    /// Replace the stack inside a dropped item entity (`count == 0` removes
475    /// the entity).
476    fn item_entity_set_stack(&self, uuid: &str, item_id: &str, count: u32, snbt: &str) -> bool;
477
478    /// An action-bar message (the line above the hotbar) from a JSON text
479    /// component, like [`tellraw`](Self::tellraw): translation keys show
480    /// in each client's own language.
481    fn actionbar_json(&self, player: &str, json: &str) -> bool;
482
483    /// Use one `item_id` (a fresh single item, nothing is taken from anyone)
484    /// on the `face` of the block at `pos`, as `player` (a name, or `""` for
485    /// nobody): flint and steel lights it, a shovel puts out a campfire, a
486    /// hoe tills it… Returns whether the item did something.
487    fn use_item_on_block(
488        &self,
489        dimension: &str,
490        pos: BlockPos,
491        face: Face,
492        item_id: &str,
493        player: &str,
494    ) -> bool;
495
496    /// Empty the fluid of a bucket item (`"minecraft:water_bucket"`) at `pos`
497    /// the way a player would: it waterlogs a waterloggable block, replaces
498    /// a replaceable one, and evaporates where water can't exist. Returns
499    /// whether any fluid was placed.
500    fn pour_fluid(&self, dimension: &str, pos: BlockPos, bucket_item_id: &str) -> bool;
501
502    /// Whether an entity type (`"minecraft:zombie"`) is in `tag_id`
503    /// (`"minecraft:skeletons"`).
504    fn has_entity_tag(&self, entity_type: &str, tag_id: &str) -> bool;
505
506    /// The block an item places (`"minecraft:torch"` for the torch item), or
507    /// `None` if it isn't a block item.
508    fn item_block(&self, item_id: &str) -> Option<String>;
509
510    /// Place a configured feature (`"minecraft:oak"`, or a datapack's own
511    /// `data/<ns>/worldgen/configured_feature/*.json`) at `pos`, the way
512    /// a growing sapling places its tree. Returns whether it was placed.
513    fn place_feature(&self, dimension: &str, pos: BlockPos, feature_id: &str) -> bool;
514}