diff --git a/.github/workflows/native-hook-stamp.yml b/.github/workflows/native-hook-stamp.yml index 3ca07a4732..2f06bf3d5f 100644 --- a/.github/workflows/native-hook-stamp.yml +++ b/.github/workflows/native-hook-stamp.yml @@ -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 diff --git a/crates/horizon-client/src/game/native_hooks.rs b/crates/horizon-client/src/game/native_hooks.rs index c30031e769..62b29ff579 100644 --- a/crates/horizon-client/src/game/native_hooks.rs +++ b/crates/horizon-client/src/game/native_hooks.rs @@ -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//`. Asked at the start of every data load /// of a server: a world opening, `/reload`. A folder that leaves - /// `data//` is skipped. API @API:server_reload_listeners@. + /// `data//` is skipped. API 400. pub(super) fn native_add_server_reload_listeners( &mut self, listeners: &mut Vec, @@ -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())) diff --git a/crates/horizon-client/src/game/native_net.rs b/crates/horizon-client/src/game/native_net.rs index 109e204d6b..fdf6da107e 100644 --- a/crates/horizon-client/src/game/native_net.rs +++ b/crates/horizon-client/src/game/native_net.rs @@ -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, diff --git a/crates/horizon-client/src/mod_api.rs b/crates/horizon-client/src/mod_api.rs index 8cb38e3647..d7cca4ec43 100644 --- a/crates/horizon-client/src/mod_api.rs +++ b/crates/horizon-client/src/mod_api.rs @@ -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, } diff --git a/docs/native-mods.md b/docs/native-mods.md index 7828d5f085..510da8a17c 100644 --- a/docs/native-mods.md +++ b/docs/native-mods.md @@ -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///` 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: `:` (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//` 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 diff --git a/native-hooks.json b/native-hooks.json index 35866bc00f..2c1a3b75d3 100644 --- a/native-hooks.json +++ b/native-hooks.json @@ -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)", + "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" + } } ] } diff --git a/tools/native-hook-fragments/camera_pose.json b/tools/native-hook-fragments/camera_pose.json deleted file mode 100644 index 62f090292e..0000000000 --- a/tools/native-hook-fragments/camera_pose.json +++ /dev/null @@ -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@." -} diff --git a/tools/native-hook-fragments/client_chat_received.json b/tools/native-hook-fragments/client_chat_received.json deleted file mode 100644 index e7bd0562da..0000000000 --- a/tools/native-hook-fragments/client_chat_received.json +++ /dev/null @@ -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@." -} diff --git a/tools/native-hook-fragments/client_packet.json b/tools/native-hook-fragments/client_packet.json deleted file mode 100644 index 5d12afb853..0000000000 --- a/tools/native-hook-fragments/client_packet.json +++ /dev/null @@ -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@." -} diff --git a/tools/native-hook-fragments/menu_extra_data.json b/tools/native-hook-fragments/menu_extra_data.json deleted file mode 100644 index 1a857022a0..0000000000 --- a/tools/native-hook-fragments/menu_extra_data.json +++ /dev/null @@ -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)", - "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@." -} diff --git a/tools/native-hook-fragments/merchant_offer_traded.json b/tools/native-hook-fragments/merchant_offer_traded.json deleted file mode 100644 index 74875d913b..0000000000 --- a/tools/native-hook-fragments/merchant_offer_traded.json +++ /dev/null @@ -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@." -} diff --git a/tools/native-hook-fragments/player_death_drops.json b/tools/native-hook-fragments/player_death_drops.json deleted file mode 100644 index 701d9610b0..0000000000 --- a/tools/native-hook-fragments/player_death_drops.json +++ /dev/null @@ -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@`." -} diff --git a/tools/native-hook-fragments/send_chat.json b/tools/native-hook-fragments/send_chat.json deleted file mode 100644 index 4a838cd6ab..0000000000 --- a/tools/native-hook-fragments/send_chat.json +++ /dev/null @@ -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"] -} diff --git a/tools/native-hook-fragments/send_packet.json b/tools/native-hook-fragments/send_packet.json deleted file mode 100644 index 4e7ce749c7..0000000000 --- a/tools/native-hook-fragments/send_packet.json +++ /dev/null @@ -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"] -} diff --git a/tools/native-hook-fragments/server_player_address.json b/tools/native-hook-fragments/server_player_address.json deleted file mode 100644 index dae992679e..0000000000 --- a/tools/native-hook-fragments/server_player_address.json +++ /dev/null @@ -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@." -} diff --git a/tools/native-hook-fragments/server_reload_listeners.json b/tools/native-hook-fragments/server_reload_listeners.json deleted file mode 100644 index 4d5c271c87..0000000000 --- a/tools/native-hook-fragments/server_reload_listeners.json +++ /dev/null @@ -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///` 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: `:` (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//` is skipped. Every mod hears every listener, so check `listener.id`. Bundles need \"hooks\": @API:server_reload_listeners@." -}