Native mods: the client's level made and dropped (LevelEvent on the client)

native_client_level_load when the client makes a level (joining a server, a
dimension change), native_client_level_unload when it drops one (replaced,
told after the new one's load as Minecraft.setLevel does, or leaving the
server). The client half of #6154.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
levzzzandClaude Opus 5.5 committed 2026-11-01 23:06:24 +05:00
1 parent 9f683428a6
commit ba04f50325
3 files changed
+55

No files matched your search

@@ -1146,6 +1146,24 @@ impl Game<'_> {
/// Atlas, models, renderer and client caches already refer to the new resources.
/// Selection/F3+T and server-pack reloads share this point; initial startup does not.
pub(super) fn native_client_resources_reloaded(&mut self) {}
/// The client made a new level for `dimension` (NeoForge's
/// `LevelEvent.Load` from the `ClientLevel` constructor): on joining a
/// server, single player's own included, and on changing dimension.
/// Its chunks come after. When the dimension changes, the old level's
/// `native_client_level_unload` follows this, as `Minecraft.setLevel`
/// tells it after the new level is made. Client-side, on the window; the
/// server's levels have `native_level_load`. API @API:client_level_events@.
pub(super) fn native_client_level_load(&mut self, dimension: &str) {
let _ = dimension;
}
/// The client dropped its level for `dimension` (`LevelEvent.Unload`
/// from `Minecraft.setLevel` and `disconnect`): replaced by another
/// dimension's, or on leaving the server. Once for each
/// `native_client_level_load`. Not told when the game itself quits.
/// Client-side. API @API:client_level_events@.
pub(super) fn native_client_level_unload(&mut self, dimension: &str) {
let _ = dimension;
}
/// Once a tick, in every `Game`: the window's (in single player, on LAN
/// and on servers), and the server's own (`native_window` is false
/// there: the single player server thread, a dedicated server).
+17
View File
@@ -471,6 +471,9 @@ pub(super) struct Remote {
/// the first teleport, which takes them then.
abilities: Option<play::PlayerAbilities>,
loaded_sent: bool,
/// The dimension of the client level the mods heard made
/// (`native_client_level_load`), to be told dropped once.
heard_level: Option<String>,
/// `ClientPacketListener.levelLoadTracker`: the loading screen after a login
/// or respawn, until the player's section is shown.
pub(super) level_load: horizon_client::level_loading::LevelLoadTracker,
@@ -967,6 +970,7 @@ impl Game<'_> {
carried: None,
abilities: None,
loaded_sent: false,
heard_level: None,
level_load: horizon_client::level_loading::LevelLoadTracker::new(0),
sent_info: info,
predictions: HashMap::new(),
@@ -1073,6 +1077,10 @@ impl Game<'_> {
self.clear_narrator();
// A world is leaving either way: its icon attempt goes with it.
self.world_icon = None;
// Minecraft.disconnect: the client level goes.
if let Some(old) = self.remote.as_mut().and_then(|r| r.heard_level.take()) {
self.native_client_level_unload(&old);
}
if let Some(mut r) = self.remote.take() {
r.session.disconnect();
}
@@ -2069,6 +2077,15 @@ impl Game<'_> {
if let Some(renderer) = self.renderer.as_mut() {
renderer.clear_sections(self.world.layout());
}
// The new ClientLevel is told before setLevel drops the old one.
let old = self
.remote
.as_mut()
.and_then(|r| r.heard_level.replace(spawn.dimension.clone()));
self.native_client_level_load(&spawn.dimension);
if let Some(old) = old {
self.native_client_level_unload(&old);
}
}
let has_sky = self
.remote
@@ -0,0 +1,20 @@
{
"hooks": [
{
"name": "client_level_load",
"target": "horizon_client::game::native_hooks::Game<'_>::native_client_level_load",
"neoforge": "LevelEvent.Load",
"side": "client",
"cancellable": false
},
{
"name": "client_level_unload",
"target": "horizon_client::game::native_hooks::Game<'_>::native_client_level_unload",
"neoforge": "LevelEvent.Unload",
"side": "client",
"cancellable": false
}
],
"rust_summary": "the client's level made and dropped (`native_client_level_load`, `native_client_level_unload`).",
"doc_summary": "the client's level made and dropped, on the window: `native_client_level_load(dimension)` when the client makes a level, on joining a server (single player's own included) and on changing dimension (NeoForge's `LevelEvent.Load` from the `ClientLevel` constructor), and `native_client_level_unload(dimension)` when it drops one, replaced by another dimension's (told after the new one's load, as `Minecraft.setLevel` does) or on leaving the server (`LevelEvent.Unload`). Each load has one unload, except when the game itself quits. Bundles that use them need \"hooks\": @API:client_level_events@."
}