mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Stamp native hook API fragments (through API 409); warn when Actions can't open the PR
The native hook stamp workflow has failed since 14:35Z: the repository doesn't let GitHub Actions open pull requests, so ten merged fragments stayed unnumbered. This stamps them on current main with tools/stamp_native_hooks.py, and makes the workflow leave a warning naming the pushed branch instead of failing, since enabling that setting would also let Actions approve pull requests. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
6ddd14e727
commit
a22f5b6e36
16 files changed
+165
-170
No files matched your search
@@ -52,4 +52,8 @@ jobs:
|
||||
git fetch origin "+refs/heads/$branch:refs/remotes/origin/$branch"
|
||||
fi
|
||||
git push --force-with-lease origin "$branch"
|
||||
gh pr create --base main --head "$branch" --title 'Stamp native hook API fragments' --body 'Assign API numbers to the pending native hook fragments. Close and reopen this PR to run CI.'
|
||||
# The repo doesn't let GitHub Actions open pull requests (that setting would also let it approve them):
|
||||
# the branch is pushed, and a maintainer opens the PR from it.
|
||||
if ! gh pr create --base main --head "$branch" --title 'Stamp native hook API fragments' --body 'Assign API numbers to the pending native hook fragments. Close and reopen this PR to run CI.'; then
|
||||
echo "::warning::Stamped fragments are on $branch; open a pull request from it (GitHub Actions may not open one here)."
|
||||
fi
|
||||
@@ -6,6 +6,28 @@
|
||||
//! Horizon's own HUD extras do, and keep a mod's settings where the
|
||||
//! WebAssembly mod of the same id kept them.
|
||||
//!
|
||||
//! API 409 adds a client mod's play packet to the server, as it is (`native_send_packet`).
|
||||
//!
|
||||
//! API 408 adds reading the server's play packets on the client (`native_client_packet`).
|
||||
//!
|
||||
//! API 407 adds the player's IP address on `NativeServerPlayer` (`address`).
|
||||
//!
|
||||
//! API 406 adds a trade's live offer, for the mods to change (`native_merchant_offer_traded`).
|
||||
//!
|
||||
//! API 405 adds a dying player's inventory to `native_loot_drops` (`entity` the player, `minecraft:player`).
|
||||
//!
|
||||
//! API 404 adds a client mod's chat line or command to the server (`native_send_chat`).
|
||||
//!
|
||||
//! API 403 adds a chat line from the server about to show, replaceable or cancellable (`native_client_chat_received`).
|
||||
//!
|
||||
//! API 402 adds a camera a mod draws the world from (`native_camera_pose`).
|
||||
//!
|
||||
//! API 401 adds a mod menu type's extra data (`native_menu_extra_data`), and the client helpers `native_screen_pos`,
|
||||
//! `native_screen_extra_data`.
|
||||
//!
|
||||
//! API 400 adds a mod's own data folders, read on each data load of a server (`native_add_server_reload_listeners`,
|
||||
//! `native_server_reload_listener_apply`; `native_reload_listeners.rs`).
|
||||
//!
|
||||
//! API 399 adds a player's chat message before it is sent (`native_player_chat`).
|
||||
//!
|
||||
//! API 398 adds the player's network entity id on `NativeServerPlayer` (`entity_id`).
|
||||
@@ -1134,7 +1156,7 @@ pub(super) use horizon_world::level::flags;
|
||||
/// The hook points' API version. The launcher reads this line from the
|
||||
/// source it builds; keep its form.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) const NATIVE_HOOKS_API: u32 = 399;
|
||||
pub(crate) const NATIVE_HOOKS_API: u32 = 409;
|
||||
|
||||
impl GameLevel<'_> {
|
||||
/// A hopper at `pos` is about to pick up `count` of `item`. Set `cancel` to leave the dropped stack in the world. Server-side. 232.
|
||||
@@ -2316,7 +2338,7 @@ impl Game<'_> {
|
||||
/// (`AddServerReloadListenersEvent`): push yours, each a listener id and a
|
||||
/// folder under `data/<namespace>/`. Asked at the start of every data load
|
||||
/// of a server: a world opening, `/reload`. A folder that leaves
|
||||
/// `data/<namespace>/` is skipped. API @API:server_reload_listeners@.
|
||||
/// `data/<namespace>/` is skipped. API 400.
|
||||
pub(super) fn native_add_server_reload_listeners(
|
||||
&mut self,
|
||||
listeners: &mut Vec<NativeReloadListener>,
|
||||
@@ -2330,7 +2352,7 @@ impl Game<'_> {
|
||||
/// data packs; for each id the top pack's file, and a file that isn't JSON
|
||||
/// is logged and left out. Every mod hears every listener, so check
|
||||
/// `listener.id`. Fired on each data load before `native_server_data_loaded`.
|
||||
/// Server-side. API @API:server_reload_listeners@.
|
||||
/// Server-side. API 400.
|
||||
pub(super) fn native_server_reload_listener_apply(
|
||||
&mut self,
|
||||
listener: &NativeReloadListener,
|
||||
@@ -2809,7 +2831,7 @@ impl Game<'_> {
|
||||
/// draw the world from anywhere: a cinematic or replay camera. Only the picture, the sound's
|
||||
/// listener and the billboards facing the camera follow it; the player, where they aim, the
|
||||
/// first-person hand and which chunks load stay the player's. Values that aren't finite keep
|
||||
/// vanilla's. Not called on the title screen's panorama. API @API:camera_pose@.
|
||||
/// vanilla's. Not called on the title screen's panorama. API 402.
|
||||
pub(super) fn native_camera_pose(
|
||||
&self,
|
||||
partial: f32,
|
||||
@@ -4803,7 +4825,7 @@ impl Game<'_> {
|
||||
/// client reads with `native_screen_extra_data` while the screen is open
|
||||
/// (NeoForge's `openMenu` with an extra-data writer). The first mod to
|
||||
/// set it wins, so answer only for your blocks. The player's state is not
|
||||
/// swapped in. @API:menu_extra_data@.
|
||||
/// swapped in. 401.
|
||||
pub(super) fn native_menu_extra_data(
|
||||
&mut self,
|
||||
player: u128,
|
||||
@@ -5139,7 +5161,7 @@ impl Game<'_> {
|
||||
/// `trade_with_villager`, which hear the offer as the trade left it.
|
||||
/// `merchant` is the trader's entity id, `kind` its type. Not asked for a
|
||||
/// trade window without a trader. Server-side. API
|
||||
/// @API:merchant_offer_traded@.
|
||||
/// 406.
|
||||
pub(super) fn native_merchant_offer_traded(
|
||||
&mut self,
|
||||
merchant: u32,
|
||||
@@ -5923,7 +5945,7 @@ impl Game<'_> {
|
||||
/// one, while the narrator still says the original. Set `cancel` and it
|
||||
/// doesn't show: a delayed message lets the next one through. Lines the
|
||||
/// client adds itself and validation errors are not told. Client-side.
|
||||
/// API @API:client_chat_received@.
|
||||
/// API 403.
|
||||
pub(super) fn native_client_chat_received(
|
||||
&mut self,
|
||||
system: bool,
|
||||
@@ -6830,7 +6852,7 @@ impl Game<'_> {
|
||||
/// and far terrain tiles; neither is the configuration phase.
|
||||
/// Read-only: the game handles the packet as it would without the mod.
|
||||
/// Client-side, on any server, single player's own included.
|
||||
/// API @API:client_packet@.
|
||||
/// API 408.
|
||||
pub(super) fn native_client_packet(&mut self, packet: &ClientboundPlayPacket) {
|
||||
mod_api::dispatch_client_packet(self, mod_api::mods(), packet);
|
||||
}
|
||||
@@ -8965,13 +8987,13 @@ impl Game<'_> {
|
||||
}
|
||||
/// The block of the mod screen that is open (`native_screen`), as the
|
||||
/// server named it when the block opened its menu type; None when no mod
|
||||
/// screen is open. @API:menu_extra_data@.
|
||||
/// screen is open. 401.
|
||||
pub(super) fn native_screen_pos(&self) -> Option<[i32; 3]> {
|
||||
self.shown_native_screen()?.pos()
|
||||
}
|
||||
/// What the block's mod wrote for the mod screen that is open
|
||||
/// (`native_menu_extra_data` on the server), empty when it wrote nothing;
|
||||
/// None when no mod screen is open. @API:menu_extra_data@.
|
||||
/// None when no mod screen is open. 401.
|
||||
pub(super) fn native_screen_extra_data(&self) -> Option<&[u8]> {
|
||||
let screen = self.shown_native_screen()?;
|
||||
Some(screen.extra.as_ref().map_or(&[], |e| e.data.as_slice()))
|
||||
|
||||
@@ -170,7 +170,7 @@ impl Game<'_> {
|
||||
/// chat history, and no client chat event (vanilla's `ClientChatEvent`
|
||||
/// comes only from ChatScreen). An error when the player isn't in a
|
||||
/// server's play state or the Chat option blocks the message. API
|
||||
/// @API:send_chat@.
|
||||
/// 404.
|
||||
pub(super) fn native_send_chat(&mut self, message: &str) -> Result<(), String> {
|
||||
let Some(remote) = self.remote.as_ref() else {
|
||||
return Err("not connected to a server".into());
|
||||
@@ -197,7 +197,7 @@ impl Game<'_> {
|
||||
/// the client's own state is the mod's to get right. An error when the
|
||||
/// player isn't in a server's play state, and for a custom payload past
|
||||
/// `ServerboundCustomPayloadPacket.MAX_PAYLOAD_SIZE`, which a server
|
||||
/// disconnects for. API @API:send_packet@.
|
||||
/// disconnects for. API 409.
|
||||
pub(super) fn native_send_packet(
|
||||
&mut self,
|
||||
packet: ServerboundPlayPacket,
|
||||
|
||||
@@ -134,7 +134,7 @@ pub struct NativeLootDrops<'a> {
|
||||
/// the player's id and `minecraft:player`, `player` them, `table` empty,
|
||||
/// `origin` where the items leave, `used` false); `drops` empty means
|
||||
/// the mod took the whole inventory. Not heard with keepInventory. API
|
||||
/// @API:player_death_drops@.
|
||||
/// 405.
|
||||
pub used: bool,
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ pub struct NativeServerPlayer {
|
||||
/// API 398.
|
||||
pub entity_id: i32,
|
||||
/// The IP address the player connects from (behind a Velocity proxy: the address the proxy forwards);
|
||||
/// empty when not known. API @API:server_player_address@.
|
||||
/// empty when not known. API 407.
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
|
||||
+27
-7
@@ -2,7 +2,7 @@
|
||||
|
||||
API 362 adds `native_compute_fov_modifier(player, base, modifier)` on the client each tick for the local player's FOV scale, after vanilla effects and before zoom and camera easing. `player` contains the calculation inputs and `base` is the original scale. Non-finite modifiers or values outside 0.01..=10 fall back to `base`. It does not affect a spectator camera on a mob. Bundles need "hooks": 362.
|
||||
|
||||
The client hook `native_client_packet(packet)` hears each play packet the server sends, decoded (`ClientboundPlayPacket`, `horizon_protocol`'s `play::Clientbound`), just before the game handles it, custom payloads included and in the order they came. It only reads: the game handles the packet as it would without the mod. Packets the network thread handles itself (keep-alives, bundle delimiters, resource packs, cookies, server links, transfers, disconnects, the configuration switch, `minecraft:brand`, far terrain tiles) and the configuration phase are not heard. Bundles need "hooks": @API:client_packet@.
|
||||
The client hook `native_client_packet(packet)` hears each play packet the server sends, decoded (`ClientboundPlayPacket`, `horizon_protocol`'s `play::Clientbound`), just before the game handles it, custom payloads included and in the order they came. It only reads: the game handles the packet as it would without the mod. Packets the network thread handles itself (keep-alives, bundle delimiters, resource packs, cookies, server links, transfers, disconnects, the configuration switch, `minecraft:brand`, far terrain tiles) and the configuration phase are not heard. Bundles need "hooks": 408.
|
||||
|
||||
The client hook `native_render_name_tag(entity_id, kind, vanilla_visible, visible, text)` runs at player and mob, armor stand, and item frame name decisions before shared geometry. Set `visible` to override vanilla and `text` to `Some` literal replacement text (NeoForge `RenderNameTagEvent`). Distance and entity availability still apply; the local player's tag is considered only when its own camera and settings gates allow it. Bundles need "hooks": 372.
|
||||
|
||||
@@ -1497,7 +1497,7 @@ API 309 adds a shift-click in a mod container's menu routed by the mod, `Abstrac
|
||||
|
||||
API 310 adds a server player's trade with a villager or a wandering trader, as NeoForge's `TradeWithVillagerEvent`: `native_trade_with_villager(merchant, kind, offer)` is heard once per trade made, after its statistic and `villager_trade` trigger, with the trader's entity id and type and the `MerchantOffer` as it is after the trade. Listen only; the player's state is swapped in. Bundles need "hooks": 310.
|
||||
|
||||
API @API:merchant_offer_traded@ adds `native_merchant_offer_traded(merchant, kind, offer)`, asked once per trade made with the live `MerchantOffer` in the state the trade left it in. A mod may change `uses`, `max_uses`, `demand`, `special_price_diff`, `price_multiplier` and `xp` (Bukkit's `PlayerTradeEvent#getTrade`, `Merchant` recipes): the next click and the offers sent to the player see the change, so a mod can keep a trade from running out or from getting dearer. The unchanged `trade_with_villager` still hears the offer as the trade left it. A shift-click's trades are asked for after the click. Bundles need "hooks": @API:merchant_offer_traded@.
|
||||
API 406 adds `native_merchant_offer_traded(merchant, kind, offer)`, asked once per trade made with the live `MerchantOffer` in the state the trade left it in. A mod may change `uses`, `max_uses`, `demand`, `special_price_diff`, `price_multiplier` and `xp` (Bukkit's `PlayerTradeEvent#getTrade`, `Merchant` recipes): the next click and the offers sent to the player see the change, so a mod can keep a trade from running out or from getting dearer. The unchanged `trade_with_villager` still hears the offer as the trade left it. A shift-click's trades are asked for after the click. Bundles need "hooks": 406.
|
||||
|
||||
API 311 adds a server player's `teleport_randomly` consume effect (chorus fruit) is about to try a spot: `native_chorus_fruit_teleport(player, name, from, target, cancel)`, once per attempt (up to 16). A mod may move `target`; the game still looks down from it for ground to land on. `cancel` ends the effect with no teleport and no more attempts. Foxes are not heard. Bundles need "hooks": 311.
|
||||
|
||||
@@ -1681,6 +1681,26 @@ API 398 adds `NativeServerPlayer.entity_id` is the network entity id the player
|
||||
|
||||
API 399 adds A player's chat message is about to be sent to everyone: `native_player_chat(player, name, message, replies, cancel)` is heard once for each message a player sends, after the secure-chat chain and the chat filter took it and before anyone sees it. Set `cancel` to drop it for everybody; push lines to `replies` and they go to the sender as system chat (the sender is not told otherwise). The text cannot be changed, a signed message would no longer verify. Bundles need "hooks": 399.
|
||||
|
||||
API 400 adds a mod's own data folders (`AddServerReloadListenersEvent`). `native_add_server_reload_listeners` lists a mod's listeners: `NativeReloadListener::json(id, folder)`, the `.json` files of `data/<namespace>/<folder>/` in every namespace, as vanilla's `SimpleJsonResourceReloadListener` reads its folder. On every data load of a server (a world opening, `/reload`), before `native_server_data_loaded`, `native_server_reload_listener_apply` hands over each listener's files: `<namespace>:<path>` (without `.json`) and the parsed JSON, sorted by id, from the resource root (vanilla's and content mods' data) and the world's enabled data packs, the top pack's file for each id. A file that isn't JSON is logged and left out; a folder that leaves `data/<namespace>/` is skipped. Every mod hears every listener, so check `listener.id`. Bundles need "hooks": 400.
|
||||
|
||||
API 401 adds a mod menu type opened with extra data (NeoForge's `openMenu` with an extra-data writer). When a mod block opens its content mod's menu type for a player, `native_menu_extra_data(player, menu, block, pos, data)` asks on the server for bytes of the mod's own (up to 32 KiB; the first mod to set `data` wins). A Horizon client gets them with the block's position just before the menu opens; while the mod's screen is open, `native_screen_pos()` gives the block the server named (not the last clicked one) and `native_screen_extra_data()` the bytes, empty when the mod wrote none. Bundles need "hooks": 401.
|
||||
|
||||
API 402 adds `native_camera_pose(partial, position, yaw, pitch)` (client) runs every world frame after vanilla placed the camera (first or third person, a spectated mob, a minecart), with its position and its yaw and pitch in degrees. Set them to draw the world from anywhere: a cinematic, replay or film camera. The picture, culling, the sound's listener and what faces the camera (particles, item sprites, block entity text) follow it; the player, where they aim, the first-person hand (cancel it with `native_render_hand`) and which chunks load stay the player's. Values that aren't finite keep vanilla's. The field of view is `native_compute_fov`'s. Not called on the title screen's panorama. Bundles need "hooks": 402.
|
||||
|
||||
API 403 adds A chat line from the server is about to show, once Chat Delay lets it through: `native_client_chat_received(system, overlay, sender, chat_type, message, cancel)`, NeoForge's `ClientChatReceivedEvent`, for system messages (`overlay` for the action bar), player chat and disguised chat. `sender` is 0 for system and disguised messages; `chat_type` is the chat type's registry name. Replace `message` to show another line, or set `cancel` to hide it. Bundles need "hooks": 403.
|
||||
|
||||
API 404 adds `native_send_chat(message)` sends chat, or a command with a leading `/`, as the chat screen would, to any server; an error when not in a server's play state, for an empty message, or when the Chat option blocks it. Bundles need "hooks": 404.
|
||||
|
||||
API 405 adds a dying player's inventory to `native_loot_drops`: after vanishing-curse items are gone and before the rest is thrown, naming the player (`entity` the player's id and `minecraft:player`, no table). A mod that takes every stack out of `drops` keeps the inventory. Not heard with `keep_inventory`. Bundles that rely on it need `"hooks": 405`.
|
||||
|
||||
API 406 adds a trade's live offer, for the mods to change: `native_merchant_offer_traded(merchant, kind, offer)` is asked once per trade made with the live `MerchantOffer` as the trade left it (`uses` counted). A mod may change `uses`, `max_uses`, `demand`, `special_price_diff`, `price_multiplier` and `xp`; the next click and the offers sent to the player see it. Bundles need "hooks": 406.
|
||||
|
||||
API 407 adds `NativeServerPlayer.address` is the IP address the player connects from, without the port (behind a Velocity proxy, the address the proxy forwards; empty when not known), for per-IP limits and sessions. Bundles need "hooks": 407.
|
||||
|
||||
API 408 adds reading the server's play packets on the client (`native_client_packet`). Bundles need "hooks": 408.
|
||||
|
||||
API 409 adds `native_send_packet(packet)` sends any serverbound play packet (`ServerboundPlayPacket`), a plugin channel's custom payload included, to any server, unchecked; an error when not in a server's play state. Bundles need "hooks": 409.
|
||||
|
||||
## What the launcher does
|
||||
|
||||
**Developing a mod?** Run `horizon-launcher settings native-profile dev` once, or pick "Dev build" in the Mods page's
|
||||
@@ -2843,18 +2863,18 @@ one custom payload channel `horizon:mod_net`. A vanilla client never gets them,
|
||||
|
||||
### Chat and commands a client mod sends
|
||||
|
||||
API @API:send_chat@, `crates/horizon-client/src/game/native_net.rs`: `native_send_chat(message)` sends what the player
|
||||
API 404, `crates/horizon-client/src/game/native_net.rs`: `native_send_chat(message)` sends what the player
|
||||
could type in chat, to any server, a vanilla one included: `ClientPacketListener.sendChat` and `sendCommand`. A leading
|
||||
`/` sends the rest as a command, signed where its arguments are messages; anything else goes as signed chat. The message
|
||||
is trimmed first, as the chat screen trims it. It isn't added to the chat history, and no client chat event fires
|
||||
(vanilla's `ClientChatEvent` comes only from the chat screen). It is an error when the player isn't in a server's play
|
||||
state (not connected, not joined yet or being reconfigured), when the trimmed message is empty, and when the Chat option
|
||||
blocks it: Commands Only blocks chat, Hidden blocks chat and commands. The server's own spam limits apply as they do to
|
||||
typed chat. Bundles need `"hooks": @API:send_chat@`.
|
||||
typed chat. Bundles need `"hooks": 404`.
|
||||
|
||||
### Packets a client mod sends
|
||||
|
||||
API @API:send_packet@, `crates/horizon-client/src/game/native_net.rs`: `native_send_packet(packet)` sends one
|
||||
API 409, `crates/horizon-client/src/game/native_net.rs`: `native_send_packet(packet)` sends one
|
||||
serverbound play packet (`mod_api::ServerboundPlayPacket`, Horizon's `play::Serverbound`) to any server, a vanilla one
|
||||
included. The usual one is a plugin channel's `ServerboundPlayPacket::CustomPayload`, for a server plugin or a Java mod
|
||||
that listens on that channel; its data is at most 32767 bytes (`ServerboundCustomPayloadPacket.MAX_PAYLOAD_SIZE`), past
|
||||
@@ -2862,7 +2882,7 @@ which a server disconnects. The packet goes out as it is: nothing counts it, and
|
||||
so a packet that needs a sequence number, a signature or the client's own state (a block placed, a slot clicked, signed
|
||||
chat) is the mod's to get right. It is an error when the player isn't in a server's play state (not connected, not
|
||||
joined yet or being reconfigured), and for a custom payload over the limit. Mod messages between the halves of one
|
||||
Horizon mod stay with `native_net_send_to_server`. Bundles need `"hooks": @API:send_packet@`.
|
||||
Horizon mod stay with `native_net_send_to_server`. Bundles need `"hooks": 409`.
|
||||
|
||||
### Server menus
|
||||
|
||||
@@ -2958,7 +2978,7 @@ block and `native_screen_extra_data()` the bytes (empty when the mod wrote none)
|
||||
open, and inside `native_screen` itself, whose slot layout the server asks for too and so can't depend on them. The
|
||||
data slots still carry what changes while the menu is open; the extra data is sent once, when it opens. Works the same
|
||||
on single player's server thread, for LAN guests and on a dedicated server. Bundles need "hooks":
|
||||
@API:menu_extra_data@.
|
||||
401.
|
||||
|
||||
### Menu slot rules
|
||||
|
||||
|
||||
@@ -655,6 +655,24 @@
|
||||
"name": "recipe_book_category",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_recipe_book_category",
|
||||
"mod_api": {}
|
||||
},
|
||||
{
|
||||
"name": "screen_pos",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_screen_pos",
|
||||
"mod_api": {}
|
||||
},
|
||||
{
|
||||
"name": "screen_extra_data",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_screen_extra_data",
|
||||
"mod_api": {}
|
||||
},
|
||||
{
|
||||
"name": "send_chat",
|
||||
"target": "horizon_client::game::native_net::Game<'_>::native_send_chat"
|
||||
},
|
||||
{
|
||||
"name": "send_packet",
|
||||
"target": "horizon_client::game::native_net::Game<'_>::native_send_packet"
|
||||
}
|
||||
],
|
||||
"hooks": [
|
||||
@@ -4877,6 +4895,85 @@
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "camera_pose",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_camera_pose",
|
||||
"neoforge": "ViewportEvent.ComputeCameraAngles",
|
||||
"side": "client",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "client_chat_received",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_client_chat_received",
|
||||
"neoforge": "ClientChatReceivedEvent",
|
||||
"side": "client",
|
||||
"cancellable": true,
|
||||
"mod_api": {
|
||||
"contract": "cancel",
|
||||
"out": "cancel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "client_packet",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_client_packet",
|
||||
"side": "client",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "menu_extra_data",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_menu_extra_data",
|
||||
"neoforge": "IPlayerExtension.openMenu(MenuProvider, Consumer<RegistryFriendlyByteBuf>)",
|
||||
"side": "server",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "replace",
|
||||
"out": "data"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "merchant_offer_traded",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_merchant_offer_traded",
|
||||
"neoforge": "none (NeoForge has no such event; Bukkit's PlayerTradeEvent#getTrade is mutable)",
|
||||
"side": "server",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "collect",
|
||||
"out": "offer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "add_server_reload_listeners",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_add_server_reload_listeners",
|
||||
"neoforge": "AddServerReloadListenersEvent",
|
||||
"side": "server",
|
||||
"mod_api": {
|
||||
"contract": "collect",
|
||||
"out": "listeners"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server_reload_listener_apply",
|
||||
"version": 1,
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_server_reload_listener_apply",
|
||||
"neoforge": "SimpleJsonResourceReloadListener.apply",
|
||||
"side": "server",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "camera_pose",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_camera_pose",
|
||||
"neoforge": "ViewportEvent.ComputeCameraAngles",
|
||||
"side": "client",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "a camera a mod draws the world from (`native_camera_pose`).",
|
||||
"doc_summary": "`native_camera_pose(partial, position, yaw, pitch)` (client) runs every world frame after vanilla placed the camera (first or third person, a spectated mob, a minecart), with its position and its yaw and pitch in degrees. Set them to draw the world from anywhere: a cinematic, replay or film camera. The picture, culling, the sound's listener and what faces the camera (particles, item sprites, block entity text) follow it; the player, where they aim, the first-person hand (cancel it with `native_render_hand`) and which chunks load stay the player's. Values that aren't finite keep vanilla's. The field of view is `native_compute_fov`'s. Not called on the title screen's panorama. Bundles need \"hooks\": @API:camera_pose@."
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "client_chat_received",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_client_chat_received",
|
||||
"neoforge": "ClientChatReceivedEvent",
|
||||
"side": "client",
|
||||
"cancellable": true,
|
||||
"mod_api": {
|
||||
"contract": "cancel",
|
||||
"out": "cancel"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "a chat line from the server about to show, replaceable or cancellable (`native_client_chat_received`).",
|
||||
"doc_summary": "A chat line from the server is about to show, once Chat Delay lets it through: `native_client_chat_received(system, overlay, sender, chat_type, message, cancel)`, NeoForge's `ClientChatReceivedEvent`, for system messages (`overlay` for the action bar), player chat and disguised chat. `sender` is 0 for system and disguised messages; `chat_type` is the chat type's registry name. Replace `message` to show another line, or set `cancel` to hide it. Bundles need \"hooks\": @API:client_chat_received@."
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "client_packet",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_client_packet",
|
||||
"side": "client",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "reading the server's play packets on the client (`native_client_packet`).",
|
||||
"doc_summary": "reading the server's play packets on the client (`native_client_packet`). Bundles need \"hooks\": @API:client_packet@."
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "menu_extra_data",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_menu_extra_data",
|
||||
"neoforge": "IPlayerExtension.openMenu(MenuProvider, Consumer<RegistryFriendlyByteBuf>)",
|
||||
"side": "server",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "replace",
|
||||
"out": "data"
|
||||
}
|
||||
}
|
||||
],
|
||||
"helpers": [
|
||||
{
|
||||
"name": "screen_pos",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_screen_pos",
|
||||
"mod_api": {}
|
||||
},
|
||||
{
|
||||
"name": "screen_extra_data",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_screen_extra_data",
|
||||
"mod_api": {}
|
||||
}
|
||||
],
|
||||
"rust_summary": "a mod menu type's extra data (`native_menu_extra_data`), and the client helpers `native_screen_pos`,\n`native_screen_extra_data`.",
|
||||
"doc_summary": "a mod menu type opened with extra data (NeoForge's `openMenu` with an extra-data writer). When a mod block opens its content mod's menu type for a player, `native_menu_extra_data(player, menu, block, pos, data)` asks on the server for bytes of the mod's own (up to 32 KiB; the first mod to set `data` wins). A Horizon client gets them with the block's position just before the menu opens; while the mod's screen is open, `native_screen_pos()` gives the block the server named (not the last clicked one) and `native_screen_extra_data()` the bytes, empty when the mod wrote none. Bundles need \"hooks\": @API:menu_extra_data@."
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "merchant_offer_traded",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_merchant_offer_traded",
|
||||
"neoforge": "none (NeoForge has no such event; Bukkit's PlayerTradeEvent#getTrade is mutable)",
|
||||
"side": "server",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "collect",
|
||||
"out": "offer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "a trade's live offer, for the mods to change (`native_merchant_offer_traded`).",
|
||||
"doc_summary": "a trade's live offer, for the mods to change: `native_merchant_offer_traded(merchant, kind, offer)` is asked once per trade made with the live `MerchantOffer` as the trade left it (`uses` counted). A mod may change `uses`, `max_uses`, `demand`, `special_price_diff`, `price_multiplier` and `xp`; the next click and the offers sent to the player see it. Bundles need \"hooks\": @API:merchant_offer_traded@."
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"hooks": [],
|
||||
"rust_summary": "a dying player's inventory to `native_loot_drops` (`entity` the player, `minecraft:player`).",
|
||||
"doc_summary": "a dying player's inventory to `native_loot_drops`: after vanishing-curse items are gone and before the rest is thrown, naming the player (`entity` the player's id and `minecraft:player`, no table). A mod that takes every stack out of `drops` keeps the inventory. Not heard with `keep_inventory`. Bundles that rely on it need `\"hooks\": @API:player_death_drops@`."
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"hooks": [],
|
||||
"helpers": [
|
||||
{"name": "send_chat", "target": "horizon_client::game::native_net::Game<'_>::native_send_chat"}
|
||||
],
|
||||
"rust_summary": "a client mod's chat line or command to the server (`native_send_chat`).",
|
||||
"doc_summary": "`native_send_chat(message)` sends chat, or a command with a leading `/`, as the chat screen would, to any server; an error when not in a server's play state, for an empty message, or when the Chat option blocks it. Bundles need \"hooks\": @API:send_chat@.",
|
||||
"comments": ["crates/horizon-client/src/game/native_net.rs"]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"hooks": [],
|
||||
"helpers": [
|
||||
{"name": "send_packet", "target": "horizon_client::game::native_net::Game<'_>::native_send_packet"}
|
||||
],
|
||||
"rust_summary": "a client mod's play packet to the server, as it is (`native_send_packet`).",
|
||||
"doc_summary": "`native_send_packet(packet)` sends any serverbound play packet (`ServerboundPlayPacket`), a plugin channel's custom payload included, to any server, unchecked; an error when not in a server's play state. Bundles need \"hooks\": @API:send_packet@.",
|
||||
"comments": ["crates/horizon-client/src/game/native_net.rs"]
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"hooks": [],
|
||||
"rust_summary": "the player's IP address on `NativeServerPlayer` (`address`).",
|
||||
"doc_summary": "`NativeServerPlayer.address` is the IP address the player connects from, without the port (behind a Velocity proxy, the address the proxy forwards; empty when not known), for per-IP limits and sessions. Bundles need \"hooks\": @API:server_player_address@."
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "add_server_reload_listeners",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_add_server_reload_listeners",
|
||||
"neoforge": "AddServerReloadListenersEvent",
|
||||
"side": "server",
|
||||
"mod_api": {
|
||||
"contract": "collect",
|
||||
"out": "listeners"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server_reload_listener_apply",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_server_reload_listener_apply",
|
||||
"neoforge": "SimpleJsonResourceReloadListener.apply",
|
||||
"side": "server",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "a mod's own data folders, read on each data load of a server (`native_add_server_reload_listeners`,\n`native_server_reload_listener_apply`; `native_reload_listeners.rs`).",
|
||||
"doc_summary": "a mod's own data folders (`AddServerReloadListenersEvent`). `native_add_server_reload_listeners` lists a mod's listeners: `NativeReloadListener::json(id, folder)`, the `.json` files of `data/<namespace>/<folder>/` in every namespace, as vanilla's `SimpleJsonResourceReloadListener` reads its folder. On every data load of a server (a world opening, `/reload`), before `native_server_data_loaded`, `native_server_reload_listener_apply` hands over each listener's files: `<namespace>:<path>` (without `.json`) and the parsed JSON, sorted by id, from the resource root (vanilla's and content mods' data) and the world's enabled data packs, the top pack's file for each id. A file that isn't JSON is logged and left out; a folder that leaves `data/<namespace>/` is skipped. Every mod hears every listener, so check `listener.id`. Bundles need \"hooks\": @API:server_reload_listeners@."
|
||||
}
|
||||
Reference in new issue
Block a user