Tell native mods when the server's difficulty changes

MinecraftServer.setDifficulty is the one door /difficulty, a dedicated
server's management and a test environment's difficulty all go through, and
nothing told a mod about it. native_difficulty_changed(from, to) now runs
there, after the change, with the two difficulty names, and only when the
difficulty is another one.
This commit is contained in:
MSedgeMC committed 2026-11-01 23:09:54 +00:00
1 parent fe12948459
commit eb94a3af37
3 files changed
+52

No files matched your search

@@ -2958,6 +2958,7 @@ impl Game<'_> {
}
/// `MinecraftServer.setDifficulty(difficulty, true)`.
pub(super) fn set_difficulty_forced(&mut self, i: u8) {
let from = self.ui.difficulty;
self.ui.difficulty = i;
// The level data holds the world's difficulty: it survives the
// reopen, so it follows the command.
@@ -2976,6 +2977,10 @@ impl Game<'_> {
locked: self.level.difficulty_locked,
}));
}
if from != i {
let (from, to) = difficulty_names(from, i);
self.native_difficulty_changed(from, to);
}
}
fn cmd_spawnpoint(&mut self, ctx: &Context) -> R<i32> {
let targets = if ctx.get("targets").is_some() {
@@ -3702,6 +3707,30 @@ pub(super) fn block_input_matches(
.all(|(k, v)| s.properties.get(k) == Some(v))
}
/// The names `native_difficulty_changed` hears for a change from `from` to
/// `to`: the four difficulties of `options.difficulty.*`, the index kept in
/// range as the command and the options keep it.
fn difficulty_names(from: u8, to: u8) -> (&'static str, &'static str) {
(
DIFFICULTIES[usize::from(from) & 3],
DIFFICULTIES[usize::from(to) & 3],
)
}
#[cfg(test)]
mod difficulty_tests {
use super::difficulty_names;
#[test]
fn a_difficulty_change_names_both_ends() {
assert_eq!(difficulty_names(0, 3), ("peaceful", "hard"));
assert_eq!(difficulty_names(2, 1), ("normal", "easy"));
// The four difficulties are the only indexes the command and the
// options keep; an index outside them still names one.
assert_eq!(difficulty_names(7, 4), ("hard", "peaceful"));
}
}
#[cfg(test)]
mod summon_tests {
#[test]
@@ -3115,6 +3115,16 @@ impl Game<'_> {
pub(super) fn native_level_unload(&mut self, dimension: &str) {
let _ = dimension;
}
/// The server's difficulty changed, from `from` to `to` (`peaceful`,
/// `easy`, `normal`, `hard`; NeoForge's `DifficultyChangeEvent`). It is
/// vanilla's `MinecraftServer.setDifficulty`, which `/difficulty`, a
/// dedicated server's management and a test environment's difficulty all
/// go through, and it is told only when the difficulty is another one. It
/// only hears: the change has already happened. Server-side. API
/// @API:difficulty_changed@.
pub(super) fn native_difficulty_changed(&mut self, from: &str, to: &str) {
let _ = (from, to);
}
/// Chunk `chunk` (`[x, z]`, in chunks) of `dimension` came into the world
/// (NeoForge's `ChunkEvent.Load`): `new` when it was just generated, false
/// when read from the save. A flat world's chunk that leaves before it's
@@ -0,0 +1,13 @@
{
"hooks": [
{
"name": "difficulty_changed",
"target": "horizon_client::game::native_hooks::Game<'_>::native_difficulty_changed",
"neoforge": "DifficultyChangeEvent",
"side": "server"
}
],
"rust_summary": "the server's difficulty changing (`native_difficulty_changed`).",
"doc_summary": "the server's difficulty changed, from one of `peaceful`, `easy`, `normal`, `hard` to another, through `native_difficulty_changed` (NeoForge's `DifficultyChangeEvent`). It is vanilla's `MinecraftServer.setDifficulty`, which `/difficulty`, a dedicated server's management and a test environment's difficulty all go through, and it is told only when the difficulty is another one. It only hears: the change has already happened. Bundles that use it need \"hooks\": @API:difficulty_changed@.",
"comments": []
}