mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-09 02:29:50 -10:00
Native hooks: a player's plugin channel message (custom_payload_from_client, #10461)
native_custom_payload_from_client(player, channel, data) hears a guest's ServerboundCustomPayloadPacket in play on any channel that isn't Horizon's own (horizon:mod_net, horizon:quiet_commands, horizon:lod), which the server drops today. Like mod messages it waits for the tick's end, with the hub back, so every helper works; it is heard from a dead player too, as vanilla's handleCustomPayload doesn't look at health. Horizon's own channels are handled as before. The client side is #6774.
This commit is contained in:
1 parent
01fec61d2d
commit
27200f64cd
5 files changed
+76
-1
No files matched your search
@@ -1943,6 +1943,20 @@ impl Game<'_> {
|
||||
let Some(gi) = host.hub.guests.iter().position(|g| g.conn == conn) else {
|
||||
return;
|
||||
};
|
||||
// A plugin channel's message on a channel that isn't one of Horizon's own (the match below
|
||||
// takes those) is for the mods, from a dead player too: vanilla's handleCustomPayload doesn't
|
||||
// look at health.
|
||||
let packet = match packet {
|
||||
S::CustomPayload(p)
|
||||
if p.channel != horizon_protocol::quiet::CHANNEL
|
||||
&& p.channel != horizon_protocol::mod_net::CHANNEL
|
||||
&& p.channel != horizon_client::lod_net::CHANNEL =>
|
||||
{
|
||||
self.guest_custom_payload(host, conn, p.channel, p.data);
|
||||
return;
|
||||
}
|
||||
packet => packet,
|
||||
};
|
||||
// A dead player acts no more, but the death screen still respawns and chats: its
|
||||
// commands run as anyone's (ServerGamePacketListenerImpl.handleChatCommand doesn't
|
||||
// look at the player's health).
|
||||
|
||||
@@ -6512,6 +6512,25 @@ impl Game<'_> {
|
||||
) {
|
||||
mod_api::dispatch_player_level_change(self, mod_api::mods(), player, name, from, to);
|
||||
}
|
||||
/// A plugin channel message from a player's client
|
||||
/// (`ServerboundCustomPayloadPacket` in play) on any channel that isn't
|
||||
/// Horizon's own (`horizon:mod_net`, `horizon:quiet_commands`,
|
||||
/// `horizon:lod`), which vanilla drops: `channel` as the client sent it
|
||||
/// (`voicechat:request_secret`), `data` its bytes, checked by nothing.
|
||||
/// Runs in the tick after it arrives, in the order the messages came,
|
||||
/// with the hub back and no player's state swapped in, so every helper
|
||||
/// works; `native_send_custom_payload_to_player` answers on a channel of
|
||||
/// any name. Heard from a dead player too. Server-side, for every guest
|
||||
/// (a single player world's own player sends none). The client side is
|
||||
/// #6774. API @API:custom_payload_from_client@.
|
||||
pub(super) fn native_custom_payload_from_client(
|
||||
&mut self,
|
||||
player: u128,
|
||||
channel: &str,
|
||||
data: &[u8],
|
||||
) {
|
||||
mod_api::dispatch_custom_payload_from_client(self, mod_api::mods(), player, channel, data);
|
||||
}
|
||||
/// A click in a menu a mod opened (`native_open_menu`), which moved
|
||||
/// nothing: the menu's `slot` (its own first, then the player's
|
||||
/// inventory, `native_menu_inventory_slot`; -999 outside), the `button`
|
||||
|
||||
@@ -28,6 +28,9 @@ pub(super) struct NativeNet {
|
||||
to_players: Vec<(u128, Vec<u8>)>,
|
||||
to_counts: HashMap<u128, u32>,
|
||||
pub(super) to_server: u32,
|
||||
/// Plugin channel messages from players on channels that aren't Horizon's own, for
|
||||
/// `native_custom_payload_from_client`: player, channel, data.
|
||||
payloads_from: Vec<(u128, String, Vec<u8>)>,
|
||||
}
|
||||
|
||||
/// A message's payload as `native_net_send_*` check it.
|
||||
@@ -59,9 +62,23 @@ impl Game<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A plugin channel message from `conn` on a channel that isn't Horizon's own: queued for
|
||||
/// `run_native_net`, which hands it to `native_custom_payload_from_client`.
|
||||
pub(super) fn guest_custom_payload(
|
||||
&mut self,
|
||||
host: &LanHost,
|
||||
conn: u32,
|
||||
channel: String,
|
||||
data: Vec<u8>,
|
||||
) {
|
||||
if let Some(player) = host.hub.guest(conn).map(|g| g.uuid) {
|
||||
self.native_net.payloads_from.push((player, channel, data));
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether messages from players wait for `run_native_net`.
|
||||
pub(super) fn native_net_waiting(&self) -> bool {
|
||||
!self.native_net.from_players.is_empty()
|
||||
!self.native_net.from_players.is_empty() || !self.native_net.payloads_from.is_empty()
|
||||
}
|
||||
|
||||
/// The waiting messages reach the mods, with the hub back in the game.
|
||||
@@ -69,6 +86,9 @@ impl Game<'_> {
|
||||
for (player, m) in std::mem::take(&mut self.native_net.from_players) {
|
||||
self.native_net_from_client(player, &m.channel, &m.data);
|
||||
}
|
||||
for (player, channel, data) in std::mem::take(&mut self.native_net.payloads_from) {
|
||||
self.native_custom_payload_from_client(player, &channel, &data);
|
||||
}
|
||||
}
|
||||
|
||||
/// What the mods sent this tick leaves; the tick's allowances start over.
|
||||
|
||||
@@ -2501,6 +2501,13 @@ before (#10461).
|
||||
With proxy forwarding on (`forwarding.secret`, offline mode) the server reads the handshake's host up to 32767
|
||||
characters, as Paper does behind a proxy, so a Floodgate player's long data reaches the hook; without forwarding the
|
||||
limit stays vanilla's 255.
|
||||
- **`native_custom_payload_from_client(player, channel, data)`**: a player's plugin channel message
|
||||
(`ServerboundCustomPayloadPacket` in play) on any channel that isn't Horizon's own (`horizon:mod_net`,
|
||||
`horizon:quiet_commands`, `horizon:lod`), which vanilla drops: a Simple Voice Chat client's `voicechat:*` requests,
|
||||
a proxy's or a client mod's channels. `data` is the client's bytes, checked by nothing. It runs in the tick after the
|
||||
message arrived, in arrival order, with the hub back and no player's state swapped in, so every helper works; it is
|
||||
heard from a dead player too. Every guest is heard (a single player world's own player sends none). The client side,
|
||||
a window's own plugin channels, is #6774. Bundles need `"hooks": @API:custom_payload_from_client@`.
|
||||
|
||||
- **`native_perform_command(player, command, ran)`**: a player typed a registered command (without its slash) and
|
||||
their level allows it, whether the world allows commands or not. The mod parses the line and sets `ran`. The
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "custom_payload_from_client",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_custom_payload_from_client",
|
||||
"neoforge": "none (NeoForge registers payload handlers per type; Bukkit's PluginMessageListener)",
|
||||
"side": "server",
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "a player's plugin channel message on a channel that isn't Horizon's own (`native_custom_payload_from_client`).",
|
||||
"doc_summary": "`native_custom_payload_from_client(player, channel, data)` hears a player's `ServerboundCustomPayloadPacket` in play on any channel that isn't Horizon's own, which vanilla drops: in the tick after it arrives, with no player's state swapped in, from a dead player too. Bundles need \"hooks\": @API:custom_payload_from_client@."
|
||||
}
|
||||
Reference in new issue
Block a user