fix: bedrock edition and port it to 1.21.30
This commit is contained in:
parent
9c70f09360
commit
d81acb0ab1
@ -29,7 +29,7 @@ impl PacketWrite for CreativeContent<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[expect(unused)]
|
#[allow(unused)]
|
||||||
enum CreativeCategory {
|
enum CreativeCategory {
|
||||||
Construction = 1,
|
Construction = 1,
|
||||||
Nature = 2,
|
Nature = 2,
|
||||||
|
|||||||
@ -4,14 +4,14 @@ use pumpkin_macros::packet;
|
|||||||
use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
|
use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codec::{bedrock_block_pos::NetworkPos, var_int::VarInt, var_uint::VarUInt},
|
codec::{var_int::VarInt, var_uint::VarUInt},
|
||||||
serial::PacketWrite,
|
serial::PacketWrite,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[packet(121)]
|
#[packet(121)]
|
||||||
pub struct CNetworkChunkPublisherUpdate {
|
pub struct CNetworkChunkPublisherUpdate {
|
||||||
// https://mojang.github.io/bedrock-protocol-docs/html/NetworkChunkPublisherUpdatePacket.html
|
// https://mojang.github.io/bedrock-protocol-docs/html/NetworkChunkPublisherUpdatePacket.html
|
||||||
pub pos_for_view: NetworkPos,
|
pub pos_for_view: BlockPos,
|
||||||
// Is in blocks, not chunks!
|
// Is in blocks, not chunks!
|
||||||
pub new_radius: VarUInt,
|
pub new_radius: VarUInt,
|
||||||
// TODO
|
// TODO
|
||||||
@ -21,8 +21,8 @@ pub struct CNetworkChunkPublisherUpdate {
|
|||||||
impl CNetworkChunkPublisherUpdate {
|
impl CNetworkChunkPublisherUpdate {
|
||||||
pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self {
|
pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos_for_view: NetworkPos(pos_for_view),
|
pos_for_view,
|
||||||
new_radius: VarUInt(new_radius),
|
new_radius: VarUInt(new_radius << 4),
|
||||||
server_build_chunk_list: Vec::new(),
|
server_build_chunk_list: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ impl CNetworkChunkPublisherUpdate {
|
|||||||
|
|
||||||
impl PacketWrite for CNetworkChunkPublisherUpdate {
|
impl PacketWrite for CNetworkChunkPublisherUpdate {
|
||||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
self.pos_for_view.write_signed(writer)?;
|
self.pos_for_view.write(writer)?;
|
||||||
self.new_radius.write(writer)?;
|
self.new_radius.write(writer)?;
|
||||||
|
|
||||||
(self.server_build_chunk_list.len() as u32).write(writer)?;
|
(self.server_build_chunk_list.len() as u32).write(writer)?;
|
||||||
|
|||||||
@ -6,10 +6,10 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(PacketWrite)]
|
#[derive(PacketWrite)]
|
||||||
#[packet(7)]
|
#[packet(7)]
|
||||||
/// https://mojang.github.io/bedrock-protocol-docs/html/ResourcePackStackPacket.html
|
|
||||||
pub struct CResourcePackStackPacket {
|
pub struct CResourcePackStackPacket {
|
||||||
|
// https://mojang.github.io/bedrock-protocol-docs/html/ResourcePackStackPacket.html
|
||||||
resource_pack_required: bool,
|
resource_pack_required: bool,
|
||||||
addons_list_size: VarUInt,
|
texture_pack_list_size: VarUInt,
|
||||||
game_version: String,
|
game_version: String,
|
||||||
experiments: Experiments,
|
experiments: Experiments,
|
||||||
/// When connecting to an Editor world, include the vanilla editor packs in the stack
|
/// When connecting to an Editor world, include the vanilla editor packs in the stack
|
||||||
@ -19,14 +19,14 @@ pub struct CResourcePackStackPacket {
|
|||||||
impl CResourcePackStackPacket {
|
impl CResourcePackStackPacket {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
resource_pack_required: bool,
|
resource_pack_required: bool,
|
||||||
addons_list_size: VarUInt,
|
texture_pack_list_size: VarUInt,
|
||||||
game_version: String,
|
game_version: String,
|
||||||
experiments: Experiments,
|
experiments: Experiments,
|
||||||
include_editor_packs: bool,
|
include_editor_packs: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
resource_pack_required,
|
resource_pack_required,
|
||||||
addons_list_size,
|
texture_pack_list_size,
|
||||||
game_version,
|
game_version,
|
||||||
experiments,
|
experiments,
|
||||||
include_editor_packs,
|
include_editor_packs,
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
use std::io::{Error, Write};
|
|
||||||
|
|
||||||
use crate::serial::PacketWrite;
|
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
|
||||||
|
use crate::serial::PacketWrite;
|
||||||
|
|
||||||
|
#[derive(PacketWrite)]
|
||||||
#[packet(6)]
|
#[packet(6)]
|
||||||
/// https://mojang.github.io/bedrock-protocol-docs/html/ResourcePacksInfoPacket.html
|
|
||||||
pub struct CResourcePacksInfo {
|
pub struct CResourcePacksInfo {
|
||||||
resource_pack_required: bool,
|
resource_pack_required: bool,
|
||||||
has_addon_packs: bool,
|
has_addon_packs: bool,
|
||||||
@ -12,36 +11,7 @@ pub struct CResourcePacksInfo {
|
|||||||
is_vibrant_visuals_force_disabled: bool,
|
is_vibrant_visuals_force_disabled: bool,
|
||||||
world_template_id: uuid::Uuid,
|
world_template_id: uuid::Uuid,
|
||||||
world_template_version: String,
|
world_template_version: String,
|
||||||
resource_packs_size: u16,
|
resource_packs_size: u16, // TODO: Add more
|
||||||
resource_packs: Vec<ResourcePack>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PacketWrite for CResourcePacksInfo {
|
|
||||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
|
||||||
self.resource_pack_required.write(writer)?;
|
|
||||||
self.has_addon_packs.write(writer)?;
|
|
||||||
self.has_scripts.write(writer)?;
|
|
||||||
self.is_vibrant_visuals_force_disabled.write(writer)?;
|
|
||||||
self.world_template_id.write(writer)?;
|
|
||||||
self.world_template_version.write(writer)?;
|
|
||||||
self.resource_packs_size.write(writer)?;
|
|
||||||
self.resource_packs.write(writer)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PacketWrite)]
|
|
||||||
pub struct ResourcePack {
|
|
||||||
pack_id: uuid::Uuid,
|
|
||||||
version: String,
|
|
||||||
size: u64,
|
|
||||||
content_key: String,
|
|
||||||
subpack_name: String,
|
|
||||||
content_identity: String,
|
|
||||||
has_scripts: bool,
|
|
||||||
is_addon_pack: bool,
|
|
||||||
is_raytracing_capable: bool,
|
|
||||||
cdn_url: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CResourcePacksInfo {
|
impl CResourcePacksInfo {
|
||||||
@ -52,7 +22,6 @@ impl CResourcePacksInfo {
|
|||||||
is_vibrant_visuals_force_disabled: bool,
|
is_vibrant_visuals_force_disabled: bool,
|
||||||
world_template_id: uuid::Uuid,
|
world_template_id: uuid::Uuid,
|
||||||
world_template_version: String,
|
world_template_version: String,
|
||||||
resource_packs: Vec<ResourcePack>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
resource_pack_required,
|
resource_pack_required,
|
||||||
@ -61,8 +30,8 @@ impl CResourcePacksInfo {
|
|||||||
is_vibrant_visuals_force_disabled,
|
is_vibrant_visuals_force_disabled,
|
||||||
world_template_id,
|
world_template_id,
|
||||||
world_template_version,
|
world_template_version,
|
||||||
resource_packs_size: resource_packs.len() as u16,
|
// TODO
|
||||||
resource_packs,
|
resource_packs_size: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,6 @@ pub struct CStartGame {
|
|||||||
|
|
||||||
pub current_level_time: u64,
|
pub current_level_time: u64,
|
||||||
pub enchantment_seed: VarInt,
|
pub enchantment_seed: VarInt,
|
||||||
|
|
||||||
pub block_properties_size: VarUInt,
|
pub block_properties_size: VarUInt,
|
||||||
//pub block_properties: [GG; 2],
|
//pub block_properties: [GG; 2],
|
||||||
pub multiplayer_correlation_id: String,
|
pub multiplayer_correlation_id: String,
|
||||||
@ -51,8 +50,7 @@ pub struct CStartGame {
|
|||||||
|
|
||||||
pub enable_clientside_generation: bool,
|
pub enable_clientside_generation: bool,
|
||||||
pub blocknetwork_ids_are_hashed: bool,
|
pub blocknetwork_ids_are_hashed: bool,
|
||||||
// NetworkPermissions
|
pub server_auth_sounds: bool,
|
||||||
pub disable_client_sounds: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PacketWrite)]
|
#[derive(PacketWrite)]
|
||||||
@ -115,7 +113,6 @@ pub struct LevelSettings {
|
|||||||
pub new_nether: bool,
|
pub new_nether: bool,
|
||||||
pub edu_shared_uri_button_name: String,
|
pub edu_shared_uri_button_name: String,
|
||||||
pub edu_shared_uri_link_uri: String,
|
pub edu_shared_uri_link_uri: String,
|
||||||
|
|
||||||
pub override_force_experimental_gameplay_has_value: bool,
|
pub override_force_experimental_gameplay_has_value: bool,
|
||||||
pub chat_restriction_level: i8,
|
pub chat_restriction_level: i8,
|
||||||
pub disable_player_interactions: bool,
|
pub disable_player_interactions: bool,
|
||||||
|
|||||||
@ -134,7 +134,7 @@ impl UDPNetworkDecoder {
|
|||||||
err => PacketDecodeError::MalformedLength(err.to_string()),
|
err => PacketDecodeError::MalformedLength(err.to_string()),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let packet_len = packet_len.0 as usize;
|
let packet_len = packet_len.0 as u64;
|
||||||
|
|
||||||
let var_header = VarUInt::decode(&mut reader)?;
|
let var_header = VarUInt::decode(&mut reader)?;
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ impl UDPNetworkDecoder {
|
|||||||
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
|
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
|
||||||
|
|
||||||
let payload = reader
|
let payload = reader
|
||||||
.read_boxed_slice(packet_len - var_header.written_size())
|
.read_boxed_slice(packet_len as usize - var_header.written_size())
|
||||||
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
||||||
|
|
||||||
Ok(RawPacket {
|
Ok(RawPacket {
|
||||||
|
|||||||
@ -1,97 +1,157 @@
|
|||||||
use std::io::{Error, Read, Write};
|
|
||||||
|
|
||||||
use pumpkin_macros::packet;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codec::var_uint::VarUInt,
|
codec::var_uint::VarUInt,
|
||||||
serial::{PacketRead, PacketWrite},
|
serial::{PacketRead, PacketWrite},
|
||||||
};
|
};
|
||||||
|
use pumpkin_macros::packet;
|
||||||
|
use std::io::{Error, ErrorKind, Read, Write};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[packet(9)]
|
#[packet(9)]
|
||||||
pub struct SText {
|
pub struct SText {
|
||||||
// https://mojang.github.io/bedrock-protocol-docs/html/TextPacket.html
|
pub needs_translation: bool,
|
||||||
pub r#type: TextPacketType,
|
pub r#type: TextPacketType,
|
||||||
pub localize: bool,
|
pub source_name: String,
|
||||||
pub player_name: String,
|
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub parameters: Vec<String>,
|
pub parameters: Vec<String>,
|
||||||
pub sender_xuid: String,
|
pub xuid: String,
|
||||||
pub platform_id: String,
|
pub platform_chat_id: String,
|
||||||
pub filtered_message: String,
|
pub filtered_message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SText {
|
impl SText {
|
||||||
pub fn new(message: String, player_name: String) -> Self {
|
pub fn new(message: String, source_name: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
needs_translation: false,
|
||||||
r#type: TextPacketType::Chat,
|
r#type: TextPacketType::Chat,
|
||||||
localize: false,
|
source_name,
|
||||||
player_name,
|
message: if message.is_empty() {
|
||||||
message,
|
" ".to_string()
|
||||||
|
} else {
|
||||||
|
message
|
||||||
|
},
|
||||||
parameters: Vec::new(),
|
parameters: Vec::new(),
|
||||||
sender_xuid: String::new(),
|
xuid: String::new(),
|
||||||
platform_id: String::new(),
|
platform_chat_id: String::new(),
|
||||||
filtered_message: String::new(),
|
filtered_message: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system_message(message: String) -> Self {
|
pub fn system_message(message: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r#type: TextPacketType::SystemMessage,
|
needs_translation: false,
|
||||||
localize: false,
|
r#type: TextPacketType::System,
|
||||||
player_name: String::new(),
|
source_name: String::new(),
|
||||||
message,
|
message: if message.is_empty() {
|
||||||
|
" ".to_string()
|
||||||
|
} else {
|
||||||
|
message
|
||||||
|
},
|
||||||
parameters: Vec::new(),
|
parameters: Vec::new(),
|
||||||
sender_xuid: String::new(),
|
xuid: String::new(),
|
||||||
platform_id: String::new(),
|
platform_chat_id: String::new(),
|
||||||
filtered_message: String::new(),
|
filtered_message: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_dummy_strings(category: u8) -> &'static [&'static str] {
|
||||||
|
match category {
|
||||||
|
0 => &[
|
||||||
|
"raw",
|
||||||
|
"tip",
|
||||||
|
"systemMessage",
|
||||||
|
"textObjectWhisper",
|
||||||
|
"textObjectAnnouncement",
|
||||||
|
"textObject",
|
||||||
|
],
|
||||||
|
1 => &["chat", "whisper", "announcement"],
|
||||||
|
2 => &["translate", "popup", "jukeboxPopup"],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_category(&self) -> u8 {
|
||||||
|
match self.r#type {
|
||||||
|
TextPacketType::Raw
|
||||||
|
| TextPacketType::Tip
|
||||||
|
| TextPacketType::System
|
||||||
|
| TextPacketType::JsonWhisper
|
||||||
|
| TextPacketType::JsonAnnouncement
|
||||||
|
| TextPacketType::Json => 0, // CATEGORY_MESSAGE_ONLY
|
||||||
|
|
||||||
|
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => 1, // CATEGORY_AUTHORED_MESSAGE
|
||||||
|
|
||||||
|
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => 2, // CATEGORY_MESSAGE_WITH_PARAMETERS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketRead for SText {
|
impl PacketRead for SText {
|
||||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
let r#type = TextPacketType::read(reader)?;
|
let needs_translation = bool::read(reader)?;
|
||||||
let localize = bool::read(reader)?;
|
|
||||||
|
|
||||||
let mut player_name = String::new();
|
let category = u8::read(reader)?;
|
||||||
let message;
|
|
||||||
|
let expected_dummies = Self::get_dummy_strings(category);
|
||||||
|
for &expected in expected_dummies {
|
||||||
|
let actual = String::read(reader)?;
|
||||||
|
if actual != expected {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
format!(
|
||||||
|
"Dummy string mismatch: expected {}, got {}",
|
||||||
|
expected, actual
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let r#type = TextPacketType::read(reader)?;
|
||||||
|
|
||||||
|
let mut source_name = String::new();
|
||||||
|
#[expect(unused)]
|
||||||
|
let mut message = String::new();
|
||||||
let mut parameters = Vec::new();
|
let mut parameters = Vec::new();
|
||||||
|
|
||||||
match r#type {
|
match r#type {
|
||||||
|
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => {
|
||||||
|
source_name = String::read(reader)?;
|
||||||
|
message = String::read(reader)?;
|
||||||
|
}
|
||||||
TextPacketType::Raw
|
TextPacketType::Raw
|
||||||
| TextPacketType::Tip
|
| TextPacketType::Tip
|
||||||
| TextPacketType::SystemMessage
|
| TextPacketType::System
|
||||||
| TextPacketType::TextObjectWhisper
|
| TextPacketType::JsonWhisper
|
||||||
| TextPacketType::TextObject
|
| TextPacketType::Json
|
||||||
| TextPacketType::TextObjectAnnouncement => {
|
| TextPacketType::JsonAnnouncement => {
|
||||||
message = String::read(reader)?;
|
message = String::read(reader)?;
|
||||||
}
|
}
|
||||||
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => {
|
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => {
|
||||||
player_name = String::read(reader)?;
|
|
||||||
message = String::read(reader)?;
|
|
||||||
}
|
|
||||||
TextPacketType::Translate | TextPacketType::Popup | TextPacketType::JukeboxPopup => {
|
|
||||||
message = String::read(reader)?;
|
message = String::read(reader)?;
|
||||||
let count = VarUInt::read(reader)?.0 as usize;
|
let count = VarUInt::read(reader)?.0 as usize;
|
||||||
parameters = Vec::with_capacity(count);
|
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
parameters.push(String::read(reader)?);
|
parameters.push(String::read(reader)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let sender_xuid = String::read(reader)?;
|
|
||||||
let platform_id = String::read(reader)?;
|
let xuid = String::read(reader)?;
|
||||||
let filtered_message = String::read(reader)?;
|
let platform_chat_id = String::read(reader)?;
|
||||||
|
|
||||||
|
let has_filtered = bool::read(reader)?;
|
||||||
|
let filtered_message = if has_filtered {
|
||||||
|
Some(String::read(reader)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
needs_translation,
|
||||||
r#type,
|
r#type,
|
||||||
localize,
|
source_name,
|
||||||
player_name,
|
|
||||||
message,
|
message,
|
||||||
parameters,
|
parameters,
|
||||||
sender_xuid,
|
xuid,
|
||||||
platform_id,
|
platform_chat_id,
|
||||||
filtered_message,
|
filtered_message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -99,22 +159,31 @@ impl PacketRead for SText {
|
|||||||
|
|
||||||
impl PacketWrite for SText {
|
impl PacketWrite for SText {
|
||||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
|
self.needs_translation.write(writer)?;
|
||||||
|
|
||||||
|
let category = self.get_category();
|
||||||
|
category.write(writer)?;
|
||||||
|
|
||||||
|
for &dummy in Self::get_dummy_strings(category) {
|
||||||
|
dummy.to_string().write(writer)?;
|
||||||
|
}
|
||||||
|
|
||||||
self.r#type.write(writer)?;
|
self.r#type.write(writer)?;
|
||||||
self.localize.write(writer)?;
|
|
||||||
match self.r#type {
|
match self.r#type {
|
||||||
|
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => {
|
||||||
|
self.source_name.write(writer)?;
|
||||||
|
self.message.write(writer)?;
|
||||||
|
}
|
||||||
TextPacketType::Raw
|
TextPacketType::Raw
|
||||||
| TextPacketType::Tip
|
| TextPacketType::Tip
|
||||||
| TextPacketType::SystemMessage
|
| TextPacketType::System
|
||||||
| TextPacketType::TextObjectWhisper
|
| TextPacketType::JsonWhisper
|
||||||
| TextPacketType::TextObject
|
| TextPacketType::Json
|
||||||
| TextPacketType::TextObjectAnnouncement => {
|
| TextPacketType::JsonAnnouncement => {
|
||||||
self.message.write(writer)?;
|
self.message.write(writer)?;
|
||||||
}
|
}
|
||||||
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => {
|
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => {
|
||||||
self.player_name.write(writer)?;
|
|
||||||
self.message.write(writer)?;
|
|
||||||
}
|
|
||||||
TextPacketType::Translate | TextPacketType::Popup | TextPacketType::JukeboxPopup => {
|
|
||||||
self.message.write(writer)?;
|
self.message.write(writer)?;
|
||||||
VarUInt(self.parameters.len() as u32).write(writer)?;
|
VarUInt(self.parameters.len() as u32).write(writer)?;
|
||||||
for param in &self.parameters {
|
for param in &self.parameters {
|
||||||
@ -122,47 +191,36 @@ impl PacketWrite for SText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.sender_xuid.write(writer)?;
|
|
||||||
self.platform_id.write(writer)?;
|
self.xuid.write(writer)?;
|
||||||
self.filtered_message.write(writer)
|
self.platform_chat_id.write(writer)?;
|
||||||
|
|
||||||
|
if let Some(msg) = &self.filtered_message {
|
||||||
|
true.write(writer)?;
|
||||||
|
msg.write(writer)?;
|
||||||
|
} else {
|
||||||
|
false.write(writer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum TextPacketType {
|
pub enum TextPacketType {
|
||||||
Raw = 0,
|
Raw = 0,
|
||||||
Chat = 1,
|
Chat = 1,
|
||||||
Translate = 2,
|
Translation = 2,
|
||||||
Popup = 3,
|
Popup = 3,
|
||||||
JukeboxPopup = 4,
|
JukeboxPopup = 4,
|
||||||
Tip = 5,
|
Tip = 5,
|
||||||
SystemMessage = 6,
|
System = 6,
|
||||||
Whisper = 7,
|
Whisper = 7,
|
||||||
Announcement = 8,
|
Announcement = 8,
|
||||||
TextObjectWhisper = 9,
|
JsonWhisper = 9,
|
||||||
TextObject = 10,
|
Json = 10,
|
||||||
TextObjectAnnouncement = 11,
|
JsonAnnouncement = 11,
|
||||||
}
|
|
||||||
|
|
||||||
impl PacketRead for TextPacketType {
|
|
||||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
|
||||||
Ok(match u8::read(reader)? {
|
|
||||||
0 => Self::Raw,
|
|
||||||
1 => Self::Chat,
|
|
||||||
2 => Self::Translate,
|
|
||||||
3 => Self::Popup,
|
|
||||||
4 => Self::JukeboxPopup,
|
|
||||||
5 => Self::Tip,
|
|
||||||
6 => Self::SystemMessage,
|
|
||||||
7 => Self::Whisper,
|
|
||||||
8 => Self::Announcement,
|
|
||||||
9 => Self::TextObjectWhisper,
|
|
||||||
10 => Self::TextObject,
|
|
||||||
11 => Self::TextObjectAnnouncement,
|
|
||||||
_ => return Err(Error::new(std::io::ErrorKind::InvalidData, "")),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketWrite for TextPacketType {
|
impl PacketWrite for TextPacketType {
|
||||||
@ -170,3 +228,23 @@ impl PacketWrite for TextPacketType {
|
|||||||
(*self as u8).write(writer)
|
(*self as u8).write(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PacketRead for TextPacketType {
|
||||||
|
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
match u8::read(reader)? {
|
||||||
|
0 => Ok(Self::Raw),
|
||||||
|
1 => Ok(Self::Chat),
|
||||||
|
2 => Ok(Self::Translation),
|
||||||
|
3 => Ok(Self::Popup),
|
||||||
|
4 => Ok(Self::JukeboxPopup),
|
||||||
|
5 => Ok(Self::Tip),
|
||||||
|
6 => Ok(Self::System),
|
||||||
|
7 => Ok(Self::Whisper),
|
||||||
|
8 => Ok(Self::Announcement),
|
||||||
|
9 => Ok(Self::JsonWhisper),
|
||||||
|
10 => Ok(Self::Json),
|
||||||
|
11 => Ok(Self::JsonAnnouncement),
|
||||||
|
_ => Err(Error::new(ErrorKind::InvalidData, "Unknown Text Type")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ pub type BlockStateId = u16;
|
|||||||
pub const CURRENT_MC_VERSION: &str = "1.21.11";
|
pub const CURRENT_MC_VERSION: &str = "1.21.11";
|
||||||
pub const LOWEST_SUPPRORTED_PROTOCOL_VERSION: u32 = 773;
|
pub const LOWEST_SUPPRORTED_PROTOCOL_VERSION: u32 = 773;
|
||||||
|
|
||||||
pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.32";
|
pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.130";
|
||||||
pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 898;
|
pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 898;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|||||||
@ -1785,18 +1785,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_system_message(&self, text: &TextComponent) {
|
pub async fn send_system_message(&self, text: &TextComponent) {
|
||||||
match &self.client {
|
self.send_system_message_raw(text, false).await;
|
||||||
ClientPlatform::Java(client) => {
|
|
||||||
client
|
|
||||||
.enqueue_packet(&CSystemChatMessage::new(text, false))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
ClientPlatform::Bedrock(client) => {
|
|
||||||
client
|
|
||||||
.send_game_packet(&SText::system_message(text.clone().get_text()))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_system_message_raw(&self, text: &TextComponent, overlay: bool) {
|
pub async fn send_system_message_raw(&self, text: &TextComponent, overlay: bool) {
|
||||||
@ -2508,13 +2497,6 @@ impl EntityBase for Player {
|
|||||||
if self.abilities.lock().await.invulnerable && damage_type != DamageType::GENERIC_KILL {
|
if self.abilities.lock().await.invulnerable && damage_type != DamageType::GENERIC_KILL {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let dyn_self = self
|
|
||||||
.living_entity
|
|
||||||
.entity
|
|
||||||
.world
|
|
||||||
.get_entity_by_id(self.living_entity.entity.entity_id)
|
|
||||||
.await
|
|
||||||
.expect("Entity not found in world");
|
|
||||||
let result = self
|
let result = self
|
||||||
.living_entity
|
.living_entity
|
||||||
.damage_with_context(caller, amount, damage_type, position, source, cause)
|
.damage_with_context(caller, amount, damage_type, position, source, cause)
|
||||||
@ -2523,8 +2505,7 @@ impl EntityBase for Player {
|
|||||||
let health = self.living_entity.health.load();
|
let health = self.living_entity.health.load();
|
||||||
if health <= 0.0 {
|
if health <= 0.0 {
|
||||||
let death_message =
|
let death_message =
|
||||||
LivingEntity::get_death_message(&*dyn_self, damage_type, source, cause)
|
LivingEntity::get_death_message(caller, damage_type, source, cause).await;
|
||||||
.await;
|
|
||||||
self.handle_killed(death_message).await;
|
self.handle_killed(death_message).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,14 +49,12 @@ struct CertificateChainPayload {
|
|||||||
|
|
||||||
impl BedrockClient {
|
impl BedrockClient {
|
||||||
pub async fn handle_request_network_settings(&self, _packet: SRequestNetworkSettings) {
|
pub async fn handle_request_network_settings(&self, _packet: SRequestNetworkSettings) {
|
||||||
log::debug!("Bedrock: Sending Network settings");
|
|
||||||
self.send_game_packet(&CNetworkSettings::new(0, 0, false, 0, 0.0))
|
self.send_game_packet(&CNetworkSettings::new(0, 0, false, 0, 0.0))
|
||||||
.await;
|
.await;
|
||||||
self.set_compression(CompressionInfo::default()).await;
|
self.set_compression(CompressionInfo::default()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_login(self: &Arc<Self>, packet: SLogin, server: &Server) -> Option<()> {
|
pub async fn handle_login(self: &Arc<Self>, packet: SLogin, server: &Server) -> Option<()> {
|
||||||
log::debug!("Bedrock: handle login");
|
|
||||||
match self.try_handle_login(packet, server).await {
|
match self.try_handle_login(packet, server).await {
|
||||||
Ok(()) => Some(()),
|
Ok(()) => Some(()),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@ -103,15 +101,7 @@ impl BedrockClient {
|
|||||||
self.write_game_packet_to_set(&CPlayStatus::LoginSuccess, &mut frame_set)
|
self.write_game_packet_to_set(&CPlayStatus::LoginSuccess, &mut frame_set)
|
||||||
.await;
|
.await;
|
||||||
self.write_game_packet_to_set(
|
self.write_game_packet_to_set(
|
||||||
&CResourcePacksInfo::new(
|
&CResourcePacksInfo::new(false, false, false, false, Uuid::default(), String::new()),
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
uuid::Uuid::default(),
|
|
||||||
String::new(),
|
|
||||||
Vec::new(),
|
|
||||||
),
|
|
||||||
&mut frame_set,
|
&mut frame_set,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@ -484,7 +484,6 @@ impl BedrockClient {
|
|||||||
packet: RawPacket,
|
packet: RawPacket,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let payload = &mut Cursor::new(&packet.payload);
|
let payload = &mut Cursor::new(&packet.payload);
|
||||||
log::error!("packet id {}", packet.id);
|
|
||||||
match packet.id {
|
match packet.id {
|
||||||
SRequestNetworkSettings::PACKET_ID => {
|
SRequestNetworkSettings::PACKET_ID => {
|
||||||
self.handle_request_network_settings(SRequestNetworkSettings::read(payload)?)
|
self.handle_request_network_settings(SRequestNetworkSettings::read(payload)?)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use std::num::NonZeroU32;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
@ -56,7 +57,10 @@ use pumpkin_data::{
|
|||||||
use pumpkin_data::{BlockDirection, BlockState};
|
use pumpkin_data::{BlockDirection, BlockState};
|
||||||
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
||||||
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
|
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
|
||||||
|
use pumpkin_protocol::bedrock::client::chunk_radius_update::CChunkRadiusUpdate;
|
||||||
|
use pumpkin_protocol::bedrock::client::network_chunk_publisher_update::CNetworkChunkPublisherUpdate;
|
||||||
use pumpkin_protocol::bedrock::client::start_game::CStartGame;
|
use pumpkin_protocol::bedrock::client::start_game::CStartGame;
|
||||||
|
use pumpkin_protocol::bedrock::frame_set::FrameSet;
|
||||||
use pumpkin_protocol::java::client::play::CPlayerSpawnPosition;
|
use pumpkin_protocol::java::client::play::CPlayerSpawnPosition;
|
||||||
use pumpkin_protocol::java::client::play::{CSetEntityMetadata, Metadata};
|
use pumpkin_protocol::java::client::play::{CSetEntityMetadata, Metadata};
|
||||||
use pumpkin_protocol::ser::serializer::Serializer;
|
use pumpkin_protocol::ser::serializer::Serializer;
|
||||||
@ -1161,7 +1165,7 @@ impl World {
|
|||||||
self.dimension.min_y
|
self.dimension.min_y
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub async fn spawn_bedrock_player(
|
pub async fn spawn_bedrock_player(
|
||||||
&self,
|
&self,
|
||||||
base_config: &BasicConfiguration,
|
base_config: &BasicConfiguration,
|
||||||
@ -1249,15 +1253,15 @@ impl World {
|
|||||||
entity_id: VarLong(runtime_id as _),
|
entity_id: VarLong(runtime_id as _),
|
||||||
runtime_entity_id: VarULong(runtime_id),
|
runtime_entity_id: VarULong(runtime_id),
|
||||||
player_gamemode: player.gamemode.load(),
|
player_gamemode: player.gamemode.load(),
|
||||||
position: Vector3::new(0.0, 100.0, 0.0),
|
position: Vector3::new(0.0, 200.0, 0.0),
|
||||||
pitch: 0.0,
|
pitch: 0.0,
|
||||||
yaw: 0.0,
|
yaw: 0.0,
|
||||||
level_settings,
|
level_settings,
|
||||||
level_id: String::new(),
|
level_id: String::new(),
|
||||||
level_name: "World".to_string(),
|
level_name: "Pumpkin world".to_string(),
|
||||||
premium_world_template_id: String::new(),
|
premium_world_template_id: String::new(),
|
||||||
is_trial: false,
|
is_trial: false,
|
||||||
rewind_history_size: VarInt(0),
|
rewind_history_size: VarInt(40),
|
||||||
server_authoritative_block_breaking: false,
|
server_authoritative_block_breaking: false,
|
||||||
current_level_time: self.level_time.lock().await.world_age as _,
|
current_level_time: self.level_time.lock().await.world_age as _,
|
||||||
enchantment_seed: VarInt(0),
|
enchantment_seed: VarInt(0),
|
||||||
@ -1278,10 +1282,15 @@ impl World {
|
|||||||
// TODO The client needs extra biome data for this
|
// TODO The client needs extra biome data for this
|
||||||
enable_clientside_generation: false,
|
enable_clientside_generation: false,
|
||||||
blocknetwork_ids_are_hashed: false,
|
blocknetwork_ids_are_hashed: false,
|
||||||
disable_client_sounds: false,
|
server_auth_sounds: false,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
// chunker::update_position(&player).await;
|
client
|
||||||
|
.send_game_packet(&CChunkRadiusUpdate {
|
||||||
|
chunk_radius: VarInt(player.config.read().await.view_distance.get().into()),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
chunker::update_position(&player).await;
|
||||||
client
|
client
|
||||||
.send_game_packet(&CreativeContent {
|
.send_game_packet(&CreativeContent {
|
||||||
groups: &[Group {
|
groups: &[Group {
|
||||||
@ -1293,8 +1302,20 @@ impl World {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let mut frame_set = FrameSet::default();
|
||||||
client
|
client
|
||||||
.send_game_packet(&CUpdateAttributes {
|
.write_game_packet_to_set(
|
||||||
|
&CNetworkChunkPublisherUpdate::new(
|
||||||
|
BlockPos::new(0, 200, 0),
|
||||||
|
NonZeroU32::from(player.config.read().await.view_distance).into(),
|
||||||
|
),
|
||||||
|
&mut frame_set,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
client
|
||||||
|
.write_game_packet_to_set(
|
||||||
|
&CUpdateAttributes {
|
||||||
runtime_id: VarULong(runtime_id),
|
runtime_id: VarULong(runtime_id),
|
||||||
attributes: vec![Attribute {
|
attributes: vec![Attribute {
|
||||||
min_value: 0.0,
|
min_value: 0.0,
|
||||||
@ -1307,15 +1328,22 @@ impl World {
|
|||||||
modifiers_list_size: VarUInt(0),
|
modifiers_list_size: VarUInt(0),
|
||||||
}],
|
}],
|
||||||
player_tick: VarULong(0),
|
player_tick: VarULong(0),
|
||||||
})
|
},
|
||||||
|
&mut frame_set,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
player.send_abilities_update().await;
|
|
||||||
|
client
|
||||||
|
.write_game_packet_to_set(&CPlayStatus::PlayerSpawn, &mut frame_set)
|
||||||
|
.await;
|
||||||
|
client.send_frame_set(frame_set, 0x84).await;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut abilities = player.abilities.lock().await;
|
let mut abilities = player.abilities.lock().await;
|
||||||
abilities.set_for_gamemode(player.gamemode.load());
|
abilities.set_for_gamemode(player.gamemode.load());
|
||||||
};
|
};
|
||||||
|
|
||||||
client.send_game_packet(&CPlayStatus::PlayerSpawn).await;
|
player.send_abilities_update().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
#[expect(clippy::too_many_lines)]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user