mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
chore: impl many ClientPacket traits
This commit is contained in:
@@ -15,3 +15,13 @@ impl<'a> ServerPacket<'a> for SAcceptCodeOfConduct {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SAcceptCodeOfConduct {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
_write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,3 +65,28 @@ impl<'a> ServerPacket<'a> for SClientInformationConfig<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SClientInformationConfig<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.locale)?;
|
||||
write.write_i8(self.view_distance)?;
|
||||
write.write_var_int(&self.chat_mode)?;
|
||||
write.write_bool(self.chat_colors)?;
|
||||
write.write_u8(self.skin_parts)?;
|
||||
if version >= &JavaMinecraftVersion::V_1_9 {
|
||||
write.write_var_int(&self.main_hand)?;
|
||||
}
|
||||
if version >= &JavaMinecraftVersion::V_1_17 {
|
||||
write.write_bool(self.text_filtering)?;
|
||||
}
|
||||
if version >= &JavaMinecraftVersion::V_1_18 {
|
||||
write.write_bool(self.server_listing)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,3 +50,22 @@ impl<'a> ServerPacket<'a> for SConfigCookieResponse<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SConfigCookieResponse<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
write.write_string(self.key)?;
|
||||
if let Some(payload) = self.payload {
|
||||
write.write_bool(true)?;
|
||||
write.write_var_int(&VarInt(payload.len() as i32))?;
|
||||
write.write_slice(payload)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,21 @@ impl<'a> ServerPacket<'a> for SCustomClickAction<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SCustomClickAction<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.action_id)?;
|
||||
if let Some(payload) = self.payload {
|
||||
write.write_bool(true)?;
|
||||
write.write_slice(payload)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SKeepAlive {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SKeepAlive {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i64_be(self.keep_alive_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +31,18 @@ impl<'a> ServerPacket<'a> for SKnownPacks<'a> {
|
||||
Ok(Self { known_packs })
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SKnownPacks<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
write.write_var_int(&VarInt(self.known_packs.len() as i32))?;
|
||||
for pack in &self.known_packs {
|
||||
pack.write(&mut write)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,3 +28,16 @@ impl<'a> ServerPacket<'a> for SPluginMessage<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPluginMessage<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.channel)?;
|
||||
write.write_slice(self.data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,3 +16,15 @@ impl<'a> ServerPacket<'a> for SConfigPong {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SConfigPong {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i32_be(self.id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,19 @@ impl<'a> ServerPacket<'a> for SConfigResourcePack {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SConfigResourcePack {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_uuid(&self.uuid)?;
|
||||
write.write_var_int(&self.result)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SConfigResourcePack {
|
||||
#[must_use]
|
||||
pub const fn response_result(&self) -> ResourcePackResponseResult {
|
||||
|
||||
@@ -40,3 +40,22 @@ impl<'a> ServerPacket<'a> for SLoginCookieResponse<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SLoginCookieResponse<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
write.write_string(self.key)?;
|
||||
if let Some(payload) = self.payload {
|
||||
write.write_bool(true)?;
|
||||
write.write_var_int(&VarInt(payload.len() as i32))?;
|
||||
write.write_slice(payload)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,3 +16,13 @@ impl<'a> ServerPacket<'a> for SLoginAcknowledged {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SLoginAcknowledged {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
_write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,21 @@ impl<'a> ServerPacket<'a> for SLoginPluginResponse {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SLoginPluginResponse {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.message_id)?;
|
||||
if let Some(data) = &self.data {
|
||||
write.write_bool(true)?;
|
||||
write.write_slice(data)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,15 @@ impl<'a> ServerPacket<'a> for SAttack {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SAttack {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,16 @@ impl<'a> ServerPacket<'a> for SBlockEntityTagQuery {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SBlockEntityTagQuery {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.transaction_id)?;
|
||||
write.write_block_pos(&self.location)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,16 @@ impl<'a> ServerPacket<'a> for SBundleItemSelected {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SBundleItemSelected {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.slot_id)?;
|
||||
write.write_var_int(&self.selected_item_index)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,15 @@ impl<'a> ServerPacket<'a> for SChangeGameMode {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SChangeGameMode {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_u8(self.game_mode as u8)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SChatCommand<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SChatCommand<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.command)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,15 @@ impl<'a> ServerPacket<'a> for SChunkBatch {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SChunkBatch {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_f32_be(self.chunks_per_tick)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,32 @@ impl<'a> ServerPacket<'a> for SClickSlot {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SClickSlot {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.sync_id)?;
|
||||
if version >= &JavaMinecraftVersion::V_1_17_1 {
|
||||
write.write_var_int(&self.revision)?;
|
||||
} else {
|
||||
write.write_i16_be(self.revision.0 as i16)?;
|
||||
}
|
||||
write.write_i16_be(self.slot)?;
|
||||
write.write_i8(self.button)?;
|
||||
self.mode.write(&mut write)?;
|
||||
write.write_var_int(&VarInt(self.array_of_changed_slots.len() as i32))?;
|
||||
for (slot, item) in &self.array_of_changed_slots {
|
||||
write.write_i16_be(*slot)?;
|
||||
item.write(&mut write)?;
|
||||
}
|
||||
self.carried_item.write(&mut write)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum SlotActionType {
|
||||
/// Performs a normal slot click. This can pick up or place items in the slot, possibly merging the cursor stack into the slot, or swapping the slot stack with the cursor stack if they can't be merged.
|
||||
@@ -93,6 +119,22 @@ impl SlotActionType {
|
||||
Self::try_from(mode.0)
|
||||
.map_err(|_| ReadingError::Message("Invalid slot action type".to_string()))
|
||||
}
|
||||
|
||||
pub fn write(
|
||||
&self,
|
||||
write: &mut impl crate::ser::NetworkWriteExt,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
let mode = match self {
|
||||
Self::Pickup => 0,
|
||||
Self::QuickMove => 1,
|
||||
Self::Swap => 2,
|
||||
Self::Clone => 3,
|
||||
Self::Throw => 4,
|
||||
Self::QuickCraft => 5,
|
||||
Self::PickupAll => 6,
|
||||
};
|
||||
write.write_var_int(&VarInt(mode))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -20,3 +20,15 @@ impl<'a> ServerPacket<'a> for SClientCommand {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SClientCommand {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.action_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,3 +55,28 @@ impl<'a> ServerPacket<'a> for SClientInformationPlay<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SClientInformationPlay<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.locale)?;
|
||||
write.write_i8(self.view_distance)?;
|
||||
write.write_var_int(&self.chat_mode)?;
|
||||
write.write_bool(self.chat_colors)?;
|
||||
write.write_u8(self.skin_parts)?;
|
||||
if version >= &JavaMinecraftVersion::V_1_9 {
|
||||
write.write_var_int(&self.main_hand)?;
|
||||
}
|
||||
if version >= &JavaMinecraftVersion::V_1_17 {
|
||||
write.write_bool(self.text_filtering)?;
|
||||
}
|
||||
if version >= &JavaMinecraftVersion::V_1_18 {
|
||||
write.write_bool(self.server_listing)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,3 +14,13 @@ impl<'a> ServerPacket<'a> for SClientTickEnd {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SClientTickEnd {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
_write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,15 @@ impl<'a> ServerPacket<'a> for SCloseContainer {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SCloseContainer {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.window_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,16 @@ impl<'a> ServerPacket<'a> for SCommandSuggestion<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SCommandSuggestion<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.id)?;
|
||||
write.write_string(self.command)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,3 +15,13 @@ impl<'a> ServerPacket<'a> for SConfigurationAcknowledged {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SConfigurationAcknowledged {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
_write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,15 @@ impl<'a> ServerPacket<'a> for SConfirmTeleport {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SConfirmTeleport {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.teleport_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,16 @@ impl<'a> ServerPacket<'a> for SContainerButtonClick {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SContainerButtonClick {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.window_id)?;
|
||||
write.write_var_int(&self.button_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,17 @@ impl<'a> ServerPacket<'a> for SContainerSlotStateChanged {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SContainerSlotStateChanged {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.slot_id)?;
|
||||
write.write_var_int(&self.container_id)?;
|
||||
write.write_bool(self.new_state)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,3 +39,22 @@ impl<'a> ServerPacket<'a> for SCookieResponse<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SCookieResponse<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
write.write_string(self.key)?;
|
||||
if let Some(payload) = self.payload {
|
||||
write.write_bool(true)?;
|
||||
write.write_var_int(&VarInt(payload.len() as i32))?;
|
||||
write.write_slice(payload)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,21 @@ impl<'a> ServerPacket<'a> for SCustomClickAction<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SCustomClickAction<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.action_id)?;
|
||||
if let Some(payload) = self.payload {
|
||||
write.write_bool(true)?;
|
||||
write.write_slice(payload)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,3 +28,16 @@ impl<'a> ServerPacket<'a> for SCustomPayload<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SCustomPayload<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.channel)?;
|
||||
write.write_slice(self.data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,15 @@ impl<'a> ServerPacket<'a> for SDebugSampleSubscription {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SDebugSampleSubscription {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.sample_type)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,15 @@ impl<'a> ServerPacket<'a> for SDebugSubscriptionRequest {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SDebugSubscriptionRequest {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.sample_type)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,25 @@ impl<'a> ServerPacket<'a> for SEditBook<'a> {
|
||||
Ok(Self { slot, pages, title })
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SEditBook<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.slot)?;
|
||||
write.write_var_int(&VarInt(self.pages.len() as i32))?;
|
||||
for page in &self.pages {
|
||||
write.write_string_bounded(page, 1024)?;
|
||||
}
|
||||
if let Some(title) = self.title {
|
||||
write.write_bool(true)?;
|
||||
write.write_string_bounded(title, 128)?;
|
||||
} else {
|
||||
write.write_bool(false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,16 @@ impl<'a> ServerPacket<'a> for SEntityTagQuery {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SEntityTagQuery {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.transaction_id)?;
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,40 @@ impl<'a> ServerPacket<'a> for SInteract {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SInteract {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
if version >= &JavaMinecraftVersion::V_26_1 {
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
write.write_var_int(&self.hand.unwrap_or(VarInt(0)))?;
|
||||
if let Some(pos) = self.target_position {
|
||||
LpVector3d(pos).write(&mut write)?;
|
||||
} else {
|
||||
LpVector3d(Vector3::new(0.0, 0.0, 0.0)).write(&mut write)?;
|
||||
}
|
||||
write.write_bool(self.sneaking)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
write.write_var_int(&self.r#type)?;
|
||||
if let Some(target) = self.target_position {
|
||||
write.write_f32_be(target.x as f32)?;
|
||||
write.write_f32_be(target.y as f32)?;
|
||||
write.write_f32_be(target.z as f32)?;
|
||||
}
|
||||
if let Some(hand) = self.hand {
|
||||
write.write_var_int(&hand)?;
|
||||
}
|
||||
write.write_bool(self.sneaking)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum ActionType {
|
||||
Interact,
|
||||
|
||||
@@ -28,3 +28,17 @@ impl<'a> ServerPacket<'a> for SJigsawGenerate {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SJigsawGenerate {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.pos)?;
|
||||
write.write_var_int(&self.levels)?;
|
||||
write.write_bool(self.keep_jigsaws)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SKeepAlive {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SKeepAlive {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i64_be(self.keep_alive_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SLockDifficulty {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SLockDifficulty {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_bool(self.locked)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,3 +29,19 @@ impl<'a> ServerPacket<'a> for SMoveVehicle {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SMoveVehicle {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_f64_be(self.x)?;
|
||||
write.write_f64_be(self.y)?;
|
||||
write.write_f64_be(self.z)?;
|
||||
write.write_f32_be(self.yaw)?;
|
||||
write.write_f32_be(self.pitch)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,16 @@ impl<'a> ServerPacket<'a> for SPaddleBoat {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPaddleBoat {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_bool(self.left_paddle)?;
|
||||
write.write_bool(self.right_paddle)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,19 @@ impl<'a> ServerPacket<'a> for SPickItemFromBlock {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPickItemFromBlock {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.pos)?;
|
||||
write.write_bool(self.include_data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[java_packet(PLAY_PICK_ITEM_FROM_ENTITY)]
|
||||
pub struct SPickItemFromEntity {
|
||||
pub id: VarInt,
|
||||
@@ -38,3 +51,16 @@ impl<'a> ServerPacket<'a> for SPickItemFromEntity {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPickItemFromEntity {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.id)?;
|
||||
write.write_bool(self.include_data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SPlayPingRequest {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayPingRequest {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i64_be(self.payload)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,17 @@ impl<'a> ServerPacket<'a> for SPlaceRecipe {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlaceRecipe {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i8(self.container_id)?;
|
||||
write.write_var_int(&self.recipe_display_id)?;
|
||||
write.write_bool(self.use_max_items)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,15 @@ impl<'a> ServerPacket<'a> for SPlayerAbilities {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerAbilities {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i8(self.flags)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,21 @@ impl<'a> ServerPacket<'a> for SPlayerAction {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerAction {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.status)?;
|
||||
write.write_block_pos(&self.position)?;
|
||||
write.write_u8(self.face)?;
|
||||
write.write_var_int(&self.sequence)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::doc_markdown)]
|
||||
pub enum Status {
|
||||
/// Sent when the player starts digging a block. If the block was insta-mined or the player is in creative mode, the client will not send `Status` = `FinishedDigging``, and will assume the server completed the destruction. To detect this, it is necessary to calculate the block destruction speed server-side.
|
||||
|
||||
@@ -70,3 +70,45 @@ impl<'a> ServerPacket<'a> for SPlayerCommand {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerCommand {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
let action_id = if version < &JavaMinecraftVersion::V_1_21_6 {
|
||||
match self.action {
|
||||
Action::StartSneaking => 0,
|
||||
Action::StopSneaking => 1,
|
||||
Action::LeaveBed => 2,
|
||||
Action::StartSprinting => 3,
|
||||
Action::StopSprinting => 4,
|
||||
Action::StartHorseJump => 5,
|
||||
Action::StopHorseJump => 6,
|
||||
Action::OpenVehicleInventory => 7,
|
||||
Action::StartFlyingElytra => 8,
|
||||
}
|
||||
} else {
|
||||
match self.action {
|
||||
Action::StartSneaking | Action::StopSneaking => {
|
||||
return Err(crate::ser::WritingError::Message(
|
||||
"Sneaking action removed in 1.21.6+".into(),
|
||||
));
|
||||
}
|
||||
Action::LeaveBed => 0,
|
||||
Action::StartSprinting => 1,
|
||||
Action::StopSprinting => 2,
|
||||
Action::StartHorseJump => 3,
|
||||
Action::StopHorseJump => 4,
|
||||
Action::OpenVehicleInventory => 5,
|
||||
Action::StartFlyingElytra => 6,
|
||||
}
|
||||
};
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
write.write_var_int(&VarInt(action_id))?;
|
||||
write.write_var_int(&self.jump_boost)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,15 @@ impl<'a> ServerPacket<'a> for SSetPlayerGround {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetPlayerGround {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_bool(self.on_ground)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,3 +56,38 @@ impl<'a> ServerPacket<'a> for SPlayerInput {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerInput {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
if version >= &JavaMinecraftVersion::V_1_21_2 {
|
||||
write.write_i8(self.input)?;
|
||||
} else {
|
||||
let mut sideways: f32 = 0.0;
|
||||
let mut forward: f32 = 0.0;
|
||||
if (self.input & Self::FORWARD) != 0 {
|
||||
forward += 1.0;
|
||||
}
|
||||
if (self.input & Self::BACKWARD) != 0 {
|
||||
forward -= 1.0;
|
||||
}
|
||||
if (self.input & Self::LEFT) != 0 {
|
||||
sideways += 1.0;
|
||||
}
|
||||
if (self.input & Self::RIGHT) != 0 {
|
||||
sideways -= 1.0;
|
||||
}
|
||||
let jumping = (self.input & Self::JUMP) != 0;
|
||||
let sneaking = (self.input & Self::SNEAK) != 0;
|
||||
write.write_f32_be(sideways)?;
|
||||
write.write_f32_be(forward)?;
|
||||
write.write_bool(jumping)?;
|
||||
write.write_bool(sneaking)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,3 +14,13 @@ impl<'a> ServerPacket<'a> for SPlayerLoaded {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerLoaded {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
_write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,3 +27,18 @@ impl<'a> ServerPacket<'a> for SPlayerPosition {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerPosition {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_f64_be(self.position.x)?;
|
||||
write.write_f64_be(self.position.y)?;
|
||||
write.write_f64_be(self.position.z)?;
|
||||
write.write_u8(self.collision)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,3 +34,20 @@ impl<'a> ServerPacket<'a> for SPlayerPositionRotation {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerPositionRotation {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_f64_be(self.position.x)?;
|
||||
write.write_f64_be(self.position.y)?;
|
||||
write.write_f64_be(self.position.z)?;
|
||||
write.write_f32_be(self.yaw)?;
|
||||
write.write_f32_be(self.pitch)?;
|
||||
write.write_u8(self.collision)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,17 @@ impl<'a> ServerPacket<'a> for SPlayerRotation {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerRotation {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_f32_be(self.yaw)?;
|
||||
write.write_f32_be(self.pitch)?;
|
||||
write.write_bool(self.ground)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,3 +45,20 @@ impl<'a> ServerPacket<'a> for SPlayerSession {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayerSession {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
write.write_uuid(&self.session_id)?;
|
||||
write.write_i64_be(self.expires_at)?;
|
||||
write.write_var_int(&VarInt(self.public_key.len() as i32))?;
|
||||
write.write_slice(&self.public_key)?;
|
||||
write.write_var_int(&VarInt(self.key_signature.len() as i32))?;
|
||||
write.write_slice(&self.key_signature)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SPlayPong {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayPong {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i32_be(self.id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,17 @@ impl<'a> ServerPacket<'a> for SRecipeBookChangeSettings {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SRecipeBookChangeSettings {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.book_type)?;
|
||||
write.write_bool(self.is_open)?;
|
||||
write.write_bool(self.is_filtering)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,15 @@ impl<'a> ServerPacket<'a> for SRecipeBookSeenRecipe {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SRecipeBookSeenRecipe {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.recipe_display_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SRenameItem<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SRenameItem<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string_bounded(self.item_name, 32767)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,3 +52,16 @@ impl<'a> ServerPacket<'a> for SPlayResourcePack {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SPlayResourcePack {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_uuid(&self.uuid)?;
|
||||
write.write_var_int(&self.result)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,3 +32,23 @@ impl<'a> ServerPacket<'a> for SSeenAdvancement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSeenAdvancement {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
match self {
|
||||
Self::OpenTab(id) => {
|
||||
write.write_var_int(&VarInt(0))?;
|
||||
write.write_string(&id.to_string())?;
|
||||
}
|
||||
Self::CloseTab => {
|
||||
write.write_var_int(&VarInt(1))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,15 @@ impl<'a> ServerPacket<'a> for SSelectTrade {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSelectTrade {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.selected_slot)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,22 @@ impl<'a> ServerPacket<'a> for SSetBeacon {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetBeacon {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_option(
|
||||
&self.primary_effect,
|
||||
crate::ser::NetworkWriteExt::write_var_int,
|
||||
)?;
|
||||
write.write_option(
|
||||
&self.secondary_effect,
|
||||
crate::ser::NetworkWriteExt::write_var_int,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,21 @@ impl<'a> ServerPacket<'a> for SSetCommandBlock<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetCommandBlock<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.pos)?;
|
||||
write.write_string_bounded(self.command, 32767)?;
|
||||
write.write_var_int(&self.mode)?;
|
||||
write.write_i8(self.flags)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CommandBlockMode {
|
||||
Chain,
|
||||
Repeating,
|
||||
|
||||
@@ -24,3 +24,17 @@ impl<'a> ServerPacket<'a> for SSetCommandMinecart<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetCommandMinecart<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
write.write_string(self.command)?;
|
||||
write.write_bool(self.track_output)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,16 @@ impl<'a> ServerPacket<'a> for SSetCreativeSlot {
|
||||
Ok(Self { slot, clicked_item })
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetCreativeSlot {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i16_be(self.slot)?;
|
||||
self.clicked_item.write_with_version(&mut write, version)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,16 @@ impl<'a> ServerPacket<'a> for SSetGameRule<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetGameRule<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_string(self.rule)?;
|
||||
write.write_string(self.value)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,15 @@ impl<'a> ServerPacket<'a> for SSetHeldItem {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetHeldItem {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_i16_be(self.slot)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,3 +35,22 @@ impl<'a> ServerPacket<'a> for SSetJigsawBlock<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetJigsawBlock<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.pos)?;
|
||||
write.write_string_bounded(self.name, 32767)?;
|
||||
write.write_string_bounded(self.target, 32767)?;
|
||||
write.write_string_bounded(self.pool, 32767)?;
|
||||
write.write_string_bounded(self.final_state, 32767)?;
|
||||
write.write_string_bounded(self.joint, 32767)?;
|
||||
write.write_var_int(&self.selection_priority)?;
|
||||
write.write_var_int(&self.placement_priority)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,3 +50,30 @@ impl<'a> ServerPacket<'a> for SSetStructureBlock<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetStructureBlock<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.location)?;
|
||||
write.write_var_int(&self.action)?;
|
||||
write.write_var_int(&self.mode)?;
|
||||
write.write_string(self.name)?;
|
||||
write.write_i8(self.offset_x)?;
|
||||
write.write_i8(self.offset_y)?;
|
||||
write.write_i8(self.offset_z)?;
|
||||
write.write_u8(self.size_x)?;
|
||||
write.write_u8(self.size_y)?;
|
||||
write.write_u8(self.size_z)?;
|
||||
write.write_var_int(&self.mirror)?;
|
||||
write.write_var_int(&self.rotation)?;
|
||||
write.write_string(self.metadata)?;
|
||||
write.write_f32_be(self.integrity)?;
|
||||
write.write_var_long(&self.seed)?;
|
||||
write.write_u8(self.flags)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,20 @@ impl<'a> ServerPacket<'a> for SSetTestBlock<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSetTestBlock<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.position)?;
|
||||
self.mode.write(&mut write)?;
|
||||
write.write_string(self.message)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TestBlockMode {
|
||||
Start,
|
||||
@@ -47,4 +61,17 @@ impl TestBlockMode {
|
||||
_ => Err(ReadingError::Message("Invalid TestBlockMode".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(
|
||||
self,
|
||||
write: &mut impl crate::ser::NetworkWriteExt,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
let val = match self {
|
||||
Self::Start => 0,
|
||||
Self::Log => 1,
|
||||
Self::Fail => 2,
|
||||
Self::Accept => 3,
|
||||
};
|
||||
write.write_var_int(&crate::VarInt(val))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,3 +19,15 @@ impl<'a> ServerPacket<'a> for SSpectateEntity {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSpectateEntity {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_uuid(&self.target)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,15 @@ impl<'a> ServerPacket<'a> for SSwingArm {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SSwingArm {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.hand)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,15 @@ impl<'a> ServerPacket<'a> for STeleportToEntity {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for STeleportToEntity {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_uuid(&self.target)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,20 @@ impl<'a> ServerPacket<'a> for STestInstanceBlockAction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for STestInstanceBlockAction<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.pos)?;
|
||||
self.action.write(&mut write)?;
|
||||
self.data.write(&mut write)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TestInstanceBlockAction {
|
||||
Init,
|
||||
@@ -54,6 +68,22 @@ impl TestInstanceBlockAction {
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(
|
||||
self,
|
||||
write: &mut impl crate::ser::NetworkWriteExt,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
let val = match self {
|
||||
Self::Init => 0,
|
||||
Self::Query => 1,
|
||||
Self::Set => 2,
|
||||
Self::Reset => 3,
|
||||
Self::Save => 4,
|
||||
Self::Export => 5,
|
||||
Self::Run => 6,
|
||||
};
|
||||
write.write_var_int(&VarInt(val))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VarIntVector3 {
|
||||
@@ -70,6 +100,16 @@ impl VarIntVector3 {
|
||||
z: bytebuf.get_var_int()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
write: &mut impl crate::ser::NetworkWriteExt,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
write.write_var_int(&self.x)?;
|
||||
write.write_var_int(&self.y)?;
|
||||
write.write_var_int(&self.z)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestInstanceBlockData<'a> {
|
||||
@@ -116,6 +156,31 @@ impl<'a> TestInstanceBlockData<'a> {
|
||||
error_message,
|
||||
})
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
write: &mut impl crate::ser::NetworkWriteExt,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
write.write_option(&self.test, |w, t| w.write_string(t))?;
|
||||
self.size.write(write)?;
|
||||
let rot_val = match self.rotation {
|
||||
pumpkin_data::block_rotation::Rotation::None => 0,
|
||||
pumpkin_data::block_rotation::Rotation::Clockwise90 => 1,
|
||||
pumpkin_data::block_rotation::Rotation::Rotate180 => 2,
|
||||
pumpkin_data::block_rotation::Rotation::CounterClockwise90 => 3,
|
||||
};
|
||||
write.write_var_int(&VarInt(rot_val))?;
|
||||
write.write_bool(self.ignore_entities)?;
|
||||
let status_val = match self.status {
|
||||
TestInstanceBlockStatus::Cleared => 0,
|
||||
TestInstanceBlockStatus::Running => 1,
|
||||
TestInstanceBlockStatus::Success => 2,
|
||||
TestInstanceBlockStatus::Failed => 3,
|
||||
};
|
||||
write.write_var_int(&VarInt(status_val))?;
|
||||
write.write_option(&self.error_message, |w, msg| w.write_string(msg))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
||||
@@ -31,3 +31,20 @@ impl<'a> ServerPacket<'a> for SUpdateSign<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SUpdateSign<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_block_pos(&self.location)?;
|
||||
write.write_bool(self.is_front_text)?;
|
||||
write.write_string_bounded(self.line_1, MAX_LINE_LENGTH)?;
|
||||
write.write_string_bounded(self.line_2, MAX_LINE_LENGTH)?;
|
||||
write.write_string_bounded(self.line_3, MAX_LINE_LENGTH)?;
|
||||
write.write_string_bounded(self.line_4, MAX_LINE_LENGTH)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,3 +35,20 @@ impl<'a> ServerPacket<'a> for SUseItem {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SUseItem {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.hand)?;
|
||||
write.write_var_int(&self.sequence)?;
|
||||
if version >= &JavaMinecraftVersion::V_1_21_2 {
|
||||
write.write_f32_be(self.yaw)?;
|
||||
write.write_f32_be(self.pitch)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,3 +49,25 @@ impl<'a> ServerPacket<'a> for SUseItemOn {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ClientPacket for SUseItemOn {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
use crate::ser::NetworkWriteExt;
|
||||
write.write_var_int(&self.hand)?;
|
||||
write.write_block_pos(&self.position)?;
|
||||
write.write_var_int(&self.face)?;
|
||||
write.write_f32_be(self.cursor_pos.x)?;
|
||||
write.write_f32_be(self.cursor_pos.y)?;
|
||||
write.write_f32_be(self.cursor_pos.z)?;
|
||||
write.write_bool(self.inside_block)?;
|
||||
if version >= &JavaMinecraftVersion::V_1_21_5 {
|
||||
write.write_bool(self.is_against_world_border)?;
|
||||
}
|
||||
write.write_var_int(&self.sequence)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@ pub async fn send_c_commands_packet(
|
||||
continue;
|
||||
}
|
||||
|
||||
// For double-slash commands, if the single-slash alias (/set) exists, only
|
||||
// register the single-slash literal for the Java client.
|
||||
if key.starts_with("//") && fallback_dispatcher.commands.contains_key(&key[1..]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Ok(tree) = fallback_dispatcher.get_tree(key) else {
|
||||
continue;
|
||||
};
|
||||
@@ -51,10 +57,16 @@ pub async fn send_c_commands_packet(
|
||||
let (is_executable, child_nodes) =
|
||||
nodes_to_proto_node_builders(&cmd_src, &tree.nodes, &tree.children);
|
||||
|
||||
let name = if key.starts_with("//") {
|
||||
&key[1..]
|
||||
} else {
|
||||
key.as_str()
|
||||
};
|
||||
|
||||
let proto_node = ProtoNodeBuilder {
|
||||
child_nodes,
|
||||
node_type: ProtoNodeType::Literal {
|
||||
name: key,
|
||||
name,
|
||||
is_executable,
|
||||
redirect_target: None,
|
||||
restricted: false,
|
||||
@@ -104,26 +116,39 @@ pub async fn send_c_commands_packet(
|
||||
.values()
|
||||
.copied()
|
||||
.filter(|id| {
|
||||
let disabled = match &dispatcher.tree[*id] {
|
||||
AttachedNode::Literal(child) => {
|
||||
dispatcher.is_disabled(&child.meta.literal_lowercase)
|
||||
}
|
||||
AttachedNode::Command(child) => {
|
||||
dispatcher.is_disabled(&child.meta.literal_lowercase)
|
||||
}
|
||||
_ => false,
|
||||
let (disabled, name) = match &dispatcher.tree[*id] {
|
||||
AttachedNode::Literal(child) => (
|
||||
dispatcher.is_disabled(&child.meta.literal_lowercase),
|
||||
child.meta.literal.as_ref(),
|
||||
),
|
||||
AttachedNode::Command(child) => (
|
||||
dispatcher.is_disabled(&child.meta.literal_lowercase),
|
||||
child.meta.literal.as_ref(),
|
||||
),
|
||||
_ => (false, ""),
|
||||
};
|
||||
!disabled
|
||||
if disabled {
|
||||
return false;
|
||||
}
|
||||
if name.starts_with("//") && dispatcher.tree.get(&name[1..]).is_some() {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
})
|
||||
.map(|id| resolve_node_id(id, node_id_offset, root_node_index))
|
||||
.map(|i| VarInt(i as i32))
|
||||
.collect();
|
||||
}
|
||||
AttachedNode::Literal(literal_attached_node) => {
|
||||
let name = if literal_attached_node.meta.literal.starts_with("//") {
|
||||
&literal_attached_node.meta.literal[1..]
|
||||
} else {
|
||||
&literal_attached_node.meta.literal
|
||||
};
|
||||
let node = ProtoNode {
|
||||
children,
|
||||
node_type: ProtoNodeType::Literal {
|
||||
name: &literal_attached_node.meta.literal,
|
||||
name,
|
||||
is_executable: literal_attached_node.owned.command.is_some(),
|
||||
redirect_target,
|
||||
restricted: !satisfies_requirements,
|
||||
@@ -132,10 +157,15 @@ pub async fn send_c_commands_packet(
|
||||
proto_nodes.push(node);
|
||||
}
|
||||
AttachedNode::Command(command_attached_node) => {
|
||||
let name = if command_attached_node.meta.literal.starts_with("//") {
|
||||
&command_attached_node.meta.literal[1..]
|
||||
} else {
|
||||
&command_attached_node.meta.literal
|
||||
};
|
||||
let node = ProtoNode {
|
||||
children,
|
||||
node_type: ProtoNodeType::Literal {
|
||||
name: &command_attached_node.meta.literal,
|
||||
name,
|
||||
is_executable: command_attached_node.owned.command.is_some(),
|
||||
redirect_target,
|
||||
restricted: !satisfies_requirements,
|
||||
@@ -281,6 +311,7 @@ struct BuilderContext<'a> {
|
||||
enums: &'a mut Vec<CommandEnum>,
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_lines)]
|
||||
pub async fn send_bedrock_commands_packet(
|
||||
player: &Arc<Player>,
|
||||
server: &Server,
|
||||
@@ -298,6 +329,10 @@ pub async fn send_bedrock_commands_packet(
|
||||
continue;
|
||||
}
|
||||
|
||||
if key.starts_with("//") && fallback_dispatcher.commands.contains_key(&key[1..]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Ok(tree) = fallback_dispatcher.get_tree(key) else {
|
||||
continue;
|
||||
};
|
||||
@@ -365,6 +400,10 @@ pub async fn send_bedrock_commands_packet(
|
||||
continue;
|
||||
}
|
||||
|
||||
if name.starts_with("//") && dispatcher.tree.get(&name[1..]).is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut ctx = BuilderContext {
|
||||
enum_values: &mut enum_values,
|
||||
enums: &mut enums,
|
||||
|
||||
@@ -663,23 +663,61 @@ impl CommandDispatcher {
|
||||
|
||||
/// Register a command with the dispatcher.
|
||||
pub fn register<P: Into<String>>(&mut self, tree: CommandTree, permission: P) {
|
||||
let mut names = tree.names.iter();
|
||||
let names = tree.names.clone();
|
||||
let mut names_iter = names.iter();
|
||||
let permission = permission.into();
|
||||
|
||||
let Some(primary_name) = names.next() else {
|
||||
let Some(primary_name) = names_iter.next() else {
|
||||
tracing::warn!("Command registration skipped: command tree has no names");
|
||||
return;
|
||||
};
|
||||
|
||||
for name in names {
|
||||
for name in names_iter {
|
||||
self.commands
|
||||
.insert(name.clone(), Command::Alias(primary_name.clone()));
|
||||
self.permissions.insert(name.clone(), permission.clone());
|
||||
|
||||
// For double-slash or slash-prefixed commands (like WorldEdit's //set or /set),
|
||||
// automatically register the alternate slash variant as an alias.
|
||||
if let Some(stripped) = name.strip_prefix("//") {
|
||||
let single_slash = format!("/{stripped}");
|
||||
if !self.commands.contains_key(&single_slash) && &single_slash != primary_name {
|
||||
self.commands
|
||||
.insert(single_slash.clone(), Command::Alias(primary_name.clone()));
|
||||
self.permissions.insert(single_slash, permission.clone());
|
||||
}
|
||||
} else if let Some(stripped) = name.strip_prefix('/') {
|
||||
let double_slash = format!("//{stripped}");
|
||||
if !self.commands.contains_key(&double_slash) && &double_slash != primary_name {
|
||||
self.commands
|
||||
.insert(double_slash.clone(), Command::Alias(primary_name.clone()));
|
||||
self.permissions.insert(double_slash, permission.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.permissions.insert(primary_name.clone(), permission);
|
||||
self.permissions
|
||||
.insert(primary_name.clone(), permission.clone());
|
||||
self.commands
|
||||
.insert(primary_name.clone(), Command::Tree(tree));
|
||||
|
||||
// For double-slash or slash-prefixed primary commands (like //set or /set),
|
||||
// automatically register the alternate slash variant as an alias.
|
||||
if let Some(stripped) = primary_name.strip_prefix("//") {
|
||||
let single_slash = format!("/{stripped}");
|
||||
if !self.commands.contains_key(&single_slash) {
|
||||
self.commands
|
||||
.insert(single_slash.clone(), Command::Alias(primary_name.clone()));
|
||||
self.permissions.insert(single_slash, permission);
|
||||
}
|
||||
} else if let Some(stripped) = primary_name.strip_prefix('/') {
|
||||
let double_slash = format!("//{stripped}");
|
||||
if !self.commands.contains_key(&double_slash) {
|
||||
self.commands
|
||||
.insert(double_slash.clone(), Command::Alias(primary_name.clone()));
|
||||
self.permissions.insert(double_slash, permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a command from the dispatcher by its primary name.
|
||||
@@ -695,6 +733,30 @@ impl CommandDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(stripped) = name.strip_prefix("//") {
|
||||
let single_slash = format!("/{stripped}");
|
||||
for (key, value) in &self.commands {
|
||||
if key == &single_slash {
|
||||
to_remove.push(key.clone());
|
||||
} else if let Command::Alias(target) = value
|
||||
&& target == &single_slash
|
||||
{
|
||||
to_remove.push(key.clone());
|
||||
}
|
||||
}
|
||||
} else if let Some(stripped) = name.strip_prefix('/') {
|
||||
let double_slash = format!("//{stripped}");
|
||||
for (key, value) in &self.commands {
|
||||
if key == &double_slash {
|
||||
to_remove.push(key.clone());
|
||||
} else if let Command::Alias(target) = value
|
||||
&& target == &double_slash
|
||||
{
|
||||
to_remove.push(key.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key in to_remove {
|
||||
self.commands.remove(&key);
|
||||
self.permissions.remove(&key);
|
||||
@@ -868,4 +930,20 @@ mod test {
|
||||
|
||||
assert!(selected.is(&error_types::DISPATCHER_UNKNOWN_COMMAND));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_slash_command_registration_and_lookup() {
|
||||
let mut dispatcher = super::CommandDispatcher::default();
|
||||
let tree = CommandTree::new(["//set", "/set"], "WorldEdit set block");
|
||||
dispatcher.register(tree, "worldedit.set");
|
||||
|
||||
assert!(dispatcher.commands.contains_key("//set"));
|
||||
assert!(dispatcher.commands.contains_key("/set"));
|
||||
assert!(dispatcher.get_tree("//set").is_ok());
|
||||
assert!(dispatcher.get_tree("/set").is_ok());
|
||||
|
||||
dispatcher.unregister("//set");
|
||||
assert!(!dispatcher.commands.contains_key("//set"));
|
||||
assert!(!dispatcher.commands.contains_key("/set"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,20 @@ impl CommandDispatcher {
|
||||
/// off through the server configuration.
|
||||
#[must_use]
|
||||
pub fn is_disabled(&self, name: &str) -> bool {
|
||||
self.disabled.contains(name)
|
||||
if self.disabled.contains(name) {
|
||||
return true;
|
||||
}
|
||||
if name.starts_with('/') && self.disabled.contains(name.trim_start_matches('/')) {
|
||||
return true;
|
||||
}
|
||||
if !name.starts_with('/') {
|
||||
let single = format!("/{name}");
|
||||
let double = format!("//{name}");
|
||||
if self.disabled.contains(&single) || self.disabled.contains(&double) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns `true` if a command (or alias) with the given name is registered
|
||||
@@ -184,13 +197,9 @@ impl CommandDispatcher {
|
||||
}
|
||||
|
||||
/// Extracts the command name (the first whitespace-separated token) from a
|
||||
/// raw input string, ignoring any leading slash.
|
||||
/// raw input string.
|
||||
fn command_name(input: &str) -> &str {
|
||||
input
|
||||
.trim_start_matches('/')
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
input.split_whitespace().next().unwrap_or("")
|
||||
}
|
||||
|
||||
/// Registers a command which can then be dispatched.
|
||||
@@ -200,7 +209,51 @@ impl CommandDispatcher {
|
||||
/// unregister a command. This is due to redirection to
|
||||
/// potentially unregistered (freed) nodes.
|
||||
pub fn register(&mut self, command_node: impl Into<CommandDetachedNode>) -> CommandNodeId {
|
||||
self.tree.add_child_to_root(command_node)
|
||||
let node = command_node.into();
|
||||
let name = node.meta.literal.to_string();
|
||||
let main_node_id = self.tree.add_child_to_root(node);
|
||||
|
||||
// For double-slash or slash-prefixed commands (e.g. //set or /set),
|
||||
// automatically register the alternate slash variant as an alias.
|
||||
if let Some(stripped) = name.strip_prefix("//") {
|
||||
let single_slash = format!("/{stripped}");
|
||||
if self.tree.get(&single_slash).is_none() {
|
||||
let main_node = &self.tree[main_node_id];
|
||||
let description = main_node.meta.description.clone();
|
||||
let mut alias = crate::command::argument_builder::CommandArgumentBuilder::new(
|
||||
single_slash,
|
||||
description,
|
||||
);
|
||||
if let Some(executor) = &main_node.owned.command {
|
||||
alias = alias.executes_arc(executor.clone());
|
||||
alias = alias.overwrite_requirements(main_node.owned.requirements.clone());
|
||||
}
|
||||
alias = alias.redirect(crate::command::node::Redirection::Local(
|
||||
main_node_id.into(),
|
||||
));
|
||||
self.tree.add_child_to_root(alias.build());
|
||||
}
|
||||
} else if let Some(stripped) = name.strip_prefix('/') {
|
||||
let double_slash = format!("//{stripped}");
|
||||
if self.tree.get(&double_slash).is_none() {
|
||||
let main_node = &self.tree[main_node_id];
|
||||
let description = main_node.meta.description.clone();
|
||||
let mut alias = crate::command::argument_builder::CommandArgumentBuilder::new(
|
||||
double_slash,
|
||||
description,
|
||||
);
|
||||
if let Some(executor) = &main_node.owned.command {
|
||||
alias = alias.executes_arc(executor.clone());
|
||||
alias = alias.overwrite_requirements(main_node.owned.requirements.clone());
|
||||
}
|
||||
alias = alias.redirect(crate::command::node::Redirection::Local(
|
||||
main_node_id.into(),
|
||||
));
|
||||
self.tree.add_child_to_root(alias.build());
|
||||
}
|
||||
}
|
||||
|
||||
main_node_id
|
||||
}
|
||||
|
||||
/// Registers a command which can then be dispatched, along with its
|
||||
@@ -457,8 +510,19 @@ impl CommandDispatcher {
|
||||
"Source provided to this command was a dummy source"
|
||||
);
|
||||
|
||||
if let Some(sliced) = input.strip_prefix("/") {
|
||||
input = sliced;
|
||||
// If input starts with '/', but the command with that leading slash is NOT
|
||||
// registered, while the stripped command IS registered (or if it's an unknown command
|
||||
// starting with a single slash, e.g. from console input), strip one leading slash.
|
||||
// For double-slash commands like WorldEdit's `//set`, the client sends `/set`, which
|
||||
// matches a registered `/set` or `//set` command and preserves the slash.
|
||||
if let Some(sliced) = input.strip_prefix('/') {
|
||||
let first_token = input.split_whitespace().next().unwrap_or("");
|
||||
let sliced_token = sliced.split_whitespace().next().unwrap_or("");
|
||||
if !self.has_command(first_token)
|
||||
&& (self.has_command(sliced_token) || !first_token.starts_with("//"))
|
||||
{
|
||||
input = sliced;
|
||||
}
|
||||
}
|
||||
|
||||
// A command that has been turned off in the configuration must behave as
|
||||
@@ -1259,4 +1323,21 @@ mod test {
|
||||
Ok(1)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn double_slash_command_execution() {
|
||||
let mut dispatcher = CommandDispatcher::new();
|
||||
let executor: for<'c> fn(&'c CommandContext) -> CommandExecutorResult<'c> =
|
||||
|_| Box::pin(async move { Ok(42) });
|
||||
|
||||
dispatcher.register(
|
||||
CommandArgumentBuilder::new("//set", "WorldEdit set command").executes(executor),
|
||||
);
|
||||
|
||||
let source = CommandSource::dummy();
|
||||
// Direct execution with //set
|
||||
assert_eq!(dispatcher.execute_input("//set", &source).await, Ok(42));
|
||||
// Execution via /set alias (as sent by Java client for //set)
|
||||
assert_eq!(dispatcher.execute_input("/set", &source).await, Ok(42));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user