chore(bedrock): Update most of the packets to mirror the official docs (#3044)

* chore(bedrock): Update most of the packets to mirror the official docs
more closely.

* Fix typo

* Fix CCreativeContent

* Undo unrelated `registry.rs` change

* Update WIT to merged PR

---------

Signed-off-by: Demetrius Kanios <demetrius@kanios.net>
This commit is contained in:
Demetrius Kanios
2026-08-25 09:06:23 -07:00
committed by GitHub
parent a2881a96fd
commit 24ae9faa4f
127 changed files with 1856 additions and 1959 deletions

View File

@@ -1,73 +1,38 @@
// Last verified for v2169
use crate::{
codec::{var_long::VarLong, var_ulong::VarULong},
serial::PacketWrite,
};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::math::{vector2::Vector2, vector3::Vector3};
use super::{
common::EntityLink,
set_actor_data::{EntityMetadata, PropertySyncData},
common::ActorLink,
set_actor_data::{PropertySyncData, SyncedActorDataList},
};
#[derive(PacketWrite)]
#[packet(13)]
pub struct CAddActor {
pub entity_unique_id: VarLong,
pub entity_runtime_id: VarULong,
pub entity_type: String,
pub target_actor_id: VarLong,
pub target_runtime_id: VarULong,
pub actor_type: String,
pub position: Vector3<f32>,
pub velocity: Vector3<f32>,
pub pitch: f32,
pub yaw: f32,
pub head_yaw: f32,
pub body_yaw: f32,
pub attributes: Vec<AttributeValue>,
pub metadata: EntityMetadata,
pub rotation: Vector2<f32>,
pub y_head_rotation: f32,
pub y_body_rotation: f32,
pub attributes_list: Vec<SyncedAttribute>,
pub actor_data: SyncedActorDataList,
pub synced_properties: PropertySyncData,
pub links: Vec<EntityLink>,
}
impl CAddActor {
#[allow(clippy::too_many_arguments)]
#[must_use]
pub const fn new(
entity_unique_id: VarLong,
entity_runtime_id: VarULong,
entity_type: String,
position: Vector3<f32>,
velocity: Vector3<f32>,
pitch: f32,
yaw: f32,
head_yaw: f32,
body_yaw: f32,
attributes: Vec<AttributeValue>,
metadata: EntityMetadata,
synced_properties: PropertySyncData,
links: Vec<EntityLink>,
) -> Self {
Self {
entity_unique_id,
entity_runtime_id,
entity_type,
position,
velocity,
pitch,
yaw,
head_yaw,
body_yaw,
attributes,
metadata,
synced_properties,
links,
}
}
pub actor_links: Vec<ActorLink>,
}
#[derive(PacketWrite)]
pub struct AttributeValue {
pub name: String,
pub min: f32,
pub value: f32,
pub max: f32,
pub struct SyncedAttribute {
pub attribute_name: String,
pub min_value: f32,
pub current_value: f32,
pub max_value: f32,
}

View File

@@ -1,21 +1,23 @@
// TODO: update inventory
use crate::{
bedrock::network_item::ItemStackWrapper,
codec::{var_long::VarLong, var_ulong::VarULong},
serial::PacketWrite,
};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use super::set_actor_data::EntityMetadata;
use crate::bedrock::network_item::ItemStackWrapper;
use super::set_actor_data::SyncedActorDataList;
#[derive(PacketWrite)]
#[packet(15)]
pub struct CAddItemActor {
pub entity_unique_id: VarLong,
pub entity_runtime_id: VarULong,
pub target_actor_id: VarLong,
pub target_runtime_id: VarULong,
pub item: ItemStackWrapper,
pub position: Vector3<f32>,
pub velocity: Vector3<f32>,
pub metadata: EntityMetadata,
pub from_fishing: bool,
pub entity_data: SyncedActorDataList,
pub is_from_fishing: bool,
}

View File

@@ -1,110 +1,38 @@
use crate::{
bedrock::network_item::NetworkItemDescriptor,
codec::{var_int::VarInt, var_uint::VarUInt, var_ulong::VarULong},
bedrock::{client::GameType, network_item::NetworkItemStackDescriptor},
codec::var_ulong::VarULong,
serial::PacketWrite,
};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use std::io::{Error, Write};
use pumpkin_util::math::{vector2::Vector2, vector3::Vector3};
use uuid::Uuid;
use super::{
common::{AbilityLayer, BuildPlatform, EntityLink},
set_actor_data::EntityMetadata,
common::{ActorLink, BuildPlatform, SerializedAbilitiesData},
set_actor_data::PropertySyncData,
set_actor_data::SyncedActorDataList,
};
#[derive(PacketWrite)]
#[packet(12)]
pub struct CAddPlayer {
pub uuid: Uuid,
pub username: String,
pub entity_runtime_id: VarULong,
pub player_name: String,
pub target_runtime_id: VarULong,
pub platform_chat_id: String,
pub position: Vector3<f32>,
pub velocity: Vector3<f32>,
pub pitch: f32,
pub yaw: f32,
pub head_yaw: f32,
pub held_item: NetworkItemDescriptor,
pub game_mode: VarInt,
pub metadata: EntityMetadata,
pub properties: EntityProperties,
pub ability_data: AbilityData,
pub links: Vec<EntityLink>,
pub rotation: Vector2<f32>,
pub y_head_rotation: f32,
// TODO: update inventory
pub carried_item: NetworkItemStackDescriptor,
pub player_game_type: GameType,
pub entity_data: SyncedActorDataList,
pub synced_properties: PropertySyncData,
pub abilities_data: SerializedAbilitiesData,
pub actor_links: Vec<ActorLink>,
pub device_id: String,
pub build_platform: BuildPlatform,
}
impl CAddPlayer {
#[allow(clippy::too_many_arguments)]
#[must_use]
pub const fn new(
uuid: Uuid,
username: String,
entity_runtime_id: VarULong,
platform_chat_id: String,
position: Vector3<f32>,
velocity: Vector3<f32>,
pitch: f32,
yaw: f32,
head_yaw: f32,
held_item: NetworkItemDescriptor,
game_mode: VarInt,
metadata: EntityMetadata,
properties: EntityProperties,
ability_data: AbilityData,
links: Vec<EntityLink>,
device_id: String,
build_platform: BuildPlatform,
) -> Self {
Self {
uuid,
username,
entity_runtime_id,
platform_chat_id,
position,
velocity,
pitch,
yaw,
head_yaw,
held_item,
game_mode,
metadata,
properties,
ability_data,
links,
device_id,
build_platform,
}
}
}
#[derive(Default, Clone)]
pub struct EntityProperties {
pub ints: Vec<(VarUInt, VarInt)>,
pub floats: Vec<(VarUInt, f32)>,
}
impl PacketWrite for EntityProperties {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarUInt(self.ints.len() as u32).write(writer)?;
for (id, val) in &self.ints {
id.write(writer)?;
val.write(writer)?;
}
VarUInt(self.floats.len() as u32).write(writer)?;
for (id, val) in &self.floats {
id.write(writer)?;
val.write(writer)?;
}
Ok(())
}
}
#[derive(Default, Clone, PacketWrite)]
pub struct AbilityData {
pub entity_unique_id: i64,
pub player_permissions: u8,
pub command_permissions: u8,
pub layers: Vec<AbilityLayer>,
}

View File

@@ -1,4 +1,10 @@
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
// Last verified for v2169
use crate::{
bedrock::{client::CommandPermissionLevel, enum_as_str::EnumAsStr},
codec::var_uint::VarUInt,
serial::PacketWrite,
};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
@@ -6,66 +12,60 @@ use pumpkin_macros::packet;
pub struct CAvailableCommands {
pub enum_values: Vec<String>,
pub chained_subcommand_values: Vec<String>,
pub suffixes: Vec<String>,
pub enums: Vec<CommandEnum>,
pub chained_subcommands: Vec<ChainedSubcommand>,
pub commands: Vec<Command>,
pub soft_enums: Vec<SoftEnum>,
pub constraints: Vec<CommandEnumConstraint>,
pub post_fixes: Vec<String>,
pub enum_data: Vec<EnumData>,
pub chained_subcommand_data: Vec<ChainedSubcommandData>,
pub commands: Vec<CommandData>,
pub soft_enums: Vec<SoftEnumData>,
pub constraints: Vec<ConstrainedValueData>,
}
#[derive(PacketWrite)]
pub struct EnumData {
pub name: String,
pub values: Vec<u32>,
}
// Represents a subcommand that can chain commands, e.g. /execute.
// Written as a flat list in section 3 of the packet; Commands reference
// entries by index via ChainedSubcommandOffsets.
#[derive(PacketWrite)]
pub struct ChainedSubcommand {
pub struct ChainedSubcommandData {
pub name: String,
pub values: Vec<ChainedSubcommandValue>,
pub subcommand_values: Vec<ChainedSubcommandRelationship>,
}
#[derive(PacketWrite)]
pub struct ChainedSubcommandValue {
/// Index into the `ChainedSubcommandValues` flat list — `VarUInt`
pub struct ChainedSubcommandRelationship {
/// Index into the `ChainedSubcommandValues` flat list
pub index: VarUInt,
/// Argument type flags (basic types only, no `ARG_FLAG`_* modifiers) — `VarUInt`
/// Argument type flags (basic types only, no `ARG_FLAG`_* modifiers)
pub value: VarUInt,
}
#[derive(PacketWrite)]
pub struct CommandEnum {
pub name: String,
pub value_indices: Vec<u32>,
}
#[derive(PacketWrite)]
pub struct Command {
pub struct CommandData {
pub name: String,
pub description: String,
/// LE u16 — putLShort
pub flags: u16,
/// Permission string (e.g. "any", "admin")
pub permission: String,
/// LE i32 — putLInt; -1 means no aliases
pub aliases_enum_index: i32,
/// LE u32 each — indices into the `chained_subcommands` flat list
pub chained_subcommand_offsets: Vec<u32>,
pub overloads: Vec<CommandOverload>,
pub permission_level: EnumAsStr<CommandPermissionLevel>,
/// -1 means no aliases
pub alias_enum: i32,
pub command_data_chained_subcommand_indexes: Vec<u32>,
pub overloads: Vec<OverloadData>,
}
#[derive(PacketWrite)]
pub struct CommandOverload {
/// Written as a single byte before parameter count ← MISSING in original
/// true = this overload uses chained subcommands instead of regular params
pub chaining: bool,
pub parameters: Vec<CommandParameter>,
pub struct OverloadData {
pub is_chaining: bool,
pub parameter_data: Vec<ParamData>,
}
#[derive(Clone, PacketWrite)]
pub struct CommandParameter {
pub struct ParamData {
pub name: String,
/// LE u32 — encodes type flags (`ARG_FLAG_VALID` | `ARG_FLAG_ENUM` | index, or raw type)
pub type_info: u32,
pub optional: bool,
/// encodes type flags (`ARG_FLAG_VALID` | `ARG_FLAG_ENUM` | index, or raw type)
pub parse_symbol: u32,
pub is_optional: bool,
/// Options byte (`ARG_FLAG`_* options) — putByte
pub options: u8,
}
@@ -99,24 +99,15 @@ pub mod arg_types {
pub const ARG_TYPE_COMMAND: u32 = 0x46;
}
pub mod command_permissions {
pub const ANY: &str = "any";
pub const GAME_DIRECTORS: &str = "gamedirectors";
pub const ADMIN: &str = "admin";
pub const HOST: &str = "host";
pub const OWNER: &str = "owner";
pub const INTERNAL: &str = "internal";
#[derive(Clone, PacketWrite)]
pub struct SoftEnumData {
pub enum_name: String,
pub enum_options: Vec<String>,
}
#[derive(Clone, PacketWrite)]
pub struct SoftEnum {
pub name: String,
pub values: Vec<String>,
}
#[derive(Clone, PacketWrite)]
pub struct CommandEnumConstraint {
pub affected_value_index: i32,
pub enum_index: i32,
pub constraints: Vec<u8>,
pub struct ConstrainedValueData {
pub enum_value_symbol: u32,
pub enum_symbol: u32,
pub constraint_indices: Vec<u8>,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_util::math::position::BlockPos;
@@ -8,14 +10,17 @@ use crate::serial::PacketWrite;
#[derive(PacketWrite)]
#[packet(56)]
pub struct CBlockActorData {
pub position: BlockPos,
pub data: NbtCompound,
pub block_position: BlockPos,
pub actor_data_tags: NbtCompound,
}
impl CBlockActorData {
#[must_use]
pub const fn new(position: BlockPos, data: NbtCompound) -> Self {
Self { position, data }
pub const fn new(block_position: BlockPos, actor_data_tags: NbtCompound) -> Self {
Self {
block_position,
actor_data_tags,
}
}
}
@@ -37,9 +42,12 @@ mod tests {
data.put_byte("color", 11);
let mut encoded = Vec::new();
CBlockActorData::new(BlockPos::new(1, 64, -2), data)
.write(&mut encoded)
.unwrap();
CBlockActorData {
block_position: BlockPos::new(1, 64, -2),
actor_data_tags: data,
}
.write(&mut encoded)
.unwrap();
assert_eq!(&encoded[..4], &[2, 128, 1, 3]);
let mut reader = NbtReadHelperBedrock::new(Cursor::new(&encoded[4..]));

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
@@ -7,20 +9,9 @@ use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(26)]
pub struct CBlockEvent {
pub position: BlockPos,
pub block_position: BlockPos,
pub event_type: VarInt,
pub event_data: VarInt,
}
impl CBlockEvent {
#[must_use]
pub const fn new(position: BlockPos, event_type: i32, event_data: i32) -> Self {
Self {
position,
event_type: VarInt(event_type),
event_data: VarInt(event_data),
}
}
pub event_value: VarInt,
}
#[cfg(test)]
@@ -35,9 +26,13 @@ mod tests {
assert_eq!(<CBlockEvent as Packet>::PACKET_ID, 26);
let mut encoded = Vec::new();
CBlockEvent::new(BlockPos::new(1, 64, -2), 1, 3)
.write(&mut encoded)
.unwrap();
CBlockEvent {
block_position: BlockPos::new(1, 64, -2),
event_type: 1.into(),
event_value: 3.into(),
}
.write(&mut encoded)
.unwrap();
assert_eq!(encoded, [2, 128, 1, 3, 2, 6]);
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
@@ -6,20 +8,8 @@ use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(61)]
pub struct CChangeDimension {
pub dimension: VarInt,
pub dimension_id: VarInt,
pub position: Vector3<f32>,
pub respawn: bool,
pub loading_screen_id: Option<u32>,
}
impl CChangeDimension {
#[must_use]
pub const fn new(dimension: i32, position: Vector3<f32>, respawn: bool) -> Self {
Self {
dimension: VarInt(dimension),
position,
respawn,
loading_screen_id: None,
}
}
}

View File

@@ -1,10 +1,11 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(70)]
pub struct CChunkRadiusUpdate {
// https://mojang.github.io/bedrock-protocol-docs/html/ChunkRadiusUpdatedPacket.html
pub struct CChunkRadiusUpdated {
pub chunk_radius: VarInt,
}

View File

@@ -1,28 +1,17 @@
use std::io::{Error, Write};
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
use crate::serial::PacketWrite;
#[derive(Clone, Debug)]
pub struct CacheBlob {
pub hash: u64,
pub payload: Vec<u8>,
#[derive(PacketWrite, Clone, Debug)]
pub struct MissingBlobData {
pub blob_id: u64,
pub blob_data: Vec<u8>,
}
#[derive(PacketWrite)]
#[packet(136)]
pub struct CClientCacheMissResponse<'a> {
pub blobs: &'a [CacheBlob],
}
impl PacketWrite for CClientCacheMissResponse<'_> {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarUInt(self.blobs.len() as u32).write(writer)?;
for blob in self.blobs {
writer.write_all(&blob.hash.to_le_bytes())?;
VarUInt(blob.payload.len() as u32).write(writer)?;
writer.write_all(&blob.payload)?;
}
Ok(())
}
pub struct CClientCacheMissResponse {
pub missing_blobs: Vec<MissingBlobData>,
}

View File

@@ -1,6 +1,11 @@
use std::io::{Error, Write};
use crate::{codec::var_long::VarLong, serial::PacketWrite};
use pumpkin_util::GameMode;
use crate::{
codec::{var_int::VarInt, var_long::VarLong},
serial::PacketWrite,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
@@ -11,7 +16,6 @@ pub enum BuildPlatform {
Osx = 3,
Amazon = 4,
GearVr = 5,
Hololens = 6,
Uwp = 7,
Win32 = 8,
Dedicated = 9,
@@ -29,8 +33,92 @@ impl PacketWrite for BuildPlatform {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum GameType {
Unknown = -1,
Survival = 0,
Creative = 1,
Adventure = 2,
Default = 5,
Spectator = 6,
//WorldDefault = 0,
}
impl PacketWrite for GameType {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarInt(*self as i32).write(writer)
}
}
impl From<GameMode> for GameType {
fn from(value: GameMode) -> Self {
match value {
GameMode::Survival => Self::Survival,
GameMode::Creative => Self::Creative,
GameMode::Adventure => Self::Adventure,
GameMode::Spectator => Self::Spectator,
}
}
}
#[derive(Clone, PacketWrite)]
pub struct SerializedAbilitiesData {
pub target_player_raw_id: i64,
pub player_permissions: PlayerPermissionLevel,
pub command_permissions: CommandPermissionLevel,
pub layers: Vec<SerializedAbilitiesDataSerializedLayer>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i8)]
pub enum PlayerPermissionLevel {
Visitor = 0,
Member = 1,
Operator = 2,
Custom = 3,
}
impl PacketWrite for PlayerPermissionLevel {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(*self as i8).write(writer)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum CommandPermissionLevel {
Any = 0,
GameDirectors = 1,
Admin = 2,
Host = 3,
Owner = 4,
Internal = 5,
}
#[allow(clippy::to_string_trait_impl)]
impl ToString for CommandPermissionLevel {
fn to_string(&self) -> String {
match self {
Self::Any => "any",
Self::GameDirectors => "gamedirectors",
Self::Admin => "admin",
Self::Host => "host",
Self::Owner => "owner",
Self::Internal => "internal",
}
.into()
}
}
impl PacketWrite for CommandPermissionLevel {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(*self as u8).write(writer)
}
}
#[derive(Default, Clone, PacketWrite)]
pub struct AbilityLayer {
pub struct SerializedAbilitiesDataSerializedLayer {
pub serialized_layer: u16,
pub abilities_set: u32,
pub ability_value: u32,
@@ -40,7 +128,7 @@ pub struct AbilityLayer {
}
#[derive(Default, Clone, PacketWrite)]
pub struct EntityLink {
pub struct ActorLink {
pub ridden_unique_id: VarLong,
pub rider_unique_id: VarLong,
pub link_type: u8,

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
@@ -6,7 +8,6 @@ use crate::{codec::var_long::VarLong, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(46)]
pub struct CContainerOpen {
// https://mojang.github.io/bedrock-protocol-docs/html/ContainerOpenPacket.html
pub container_id: u8,
pub container_type: u8,
pub position: BlockPos,

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::{vector2::Vector2, vector3::Vector3};
@@ -5,8 +7,7 @@ use crate::{codec::var_ulong::VarULong, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(161)]
pub struct CCorrectPlayerMove {
// https://mojang.github.io/bedrock-protocol-docs/html/CorrectPlayerMovePredictionPacket.html
pub struct CCorrectPlayerMovePrediction {
pub prediction_type: u8,
pub pos: Vector3<f32>,
pub pos_delta: Vector3<f32>,

View File

@@ -8,9 +8,8 @@ use crate::{
#[packet(145)]
pub struct CCreativeContent<'a> {
// https://mojang.github.io/bedrock-protocol-docs/html/CreativeContentPacket.html
pub groups: &'a [Group],
pub entries: &'a [Entry],
pub groups: &'a [CreativeGroupInfoPayload],
pub entries: &'a [CreativeItemEntryPayload],
}
impl PacketWrite for CCreativeContent<'_> {
@@ -28,44 +27,57 @@ impl PacketWrite for CCreativeContent<'_> {
}
}
#[derive(Copy, Clone)]
#[repr(i32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum CreativeCategory {
Construction = 1,
Nature = 2,
Equipment = 3,
Items = 4,
CommandOnly = 5,
Undefined = 6,
All,
Construction,
Nature,
Equipment,
Items,
ItemCommandOnly,
Undefined,
}
impl PacketWrite for CreativeCategory {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(*self as u8).write(writer)
match self {
Self::Construction
| Self::Nature
| Self::Equipment
| Self::Items
| Self::ItemCommandOnly => (*self as u8).write(writer),
_ => Err(Error::other("Invalid CreativeCategory to send")),
}
}
}
pub struct Group {
pub struct CreativeGroupInfoPayload {
pub creative_category: CreativeCategory,
pub name: String,
pub icon_item: NetworkItemDescriptor,
// TODO: update inventory
pub group_icon_item: NetworkItemDescriptor,
}
impl PacketWrite for Group {
impl PacketWrite for CreativeGroupInfoPayload {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.creative_category.write(writer)?;
self.name.write(writer)?;
self.icon_item.write_item_instance(writer)
self.group_icon_item.write_item_instance(writer)
}
}
pub struct Entry {
pub struct CreativeItemEntryPayload {
pub id: VarUInt,
// TODO: update inventory
pub item: NetworkItemDescriptor,
pub group_index: VarUInt,
}
impl PacketWrite for Entry {
impl PacketWrite for CreativeItemEntryPayload {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.id.write(writer)?;
self.item.write_item_instance(writer)?;

View File

@@ -1,18 +1,19 @@
// Last verified for v2169
use pumpkin_macros::packet;
use std::io::{Error, Write};
use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[packet(5)]
pub struct CDisconnectPlayer {
// https://mojang.github.io/bedrock-protocol-docs/html/DisconnectPacket.html
pub struct CDisconnect {
pub reason: VarInt,
pub skip_message: bool,
pub message: String,
pub filtered_message: String,
}
impl CDisconnectPlayer {
impl CDisconnect {
#[must_use]
pub const fn new(reason: i32, message: String) -> Self {
Self {
@@ -24,7 +25,7 @@ impl CDisconnectPlayer {
}
}
impl PacketWrite for CDisconnectPlayer {
impl PacketWrite for CDisconnect {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.reason.write(writer)?;
self.skip_message.write(writer)?;

View File

@@ -2,14 +2,26 @@ use pumpkin_macros::packet;
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
#[derive(PacketWrite, Default)]
#[packet(0x48)]
#[derive(PacketWrite)]
#[packet(72)]
pub struct CGamerulesChanged {
pub rule_data: GameRules,
pub rule_data: Vec<GameRule>,
}
#[derive(PacketWrite, Default)]
pub struct GameRules {
// TODO https://mojang.github.io/bedrock-protocol-docs/html/GameRulesChangedPacketData.html
pub list_size: VarUInt,
#[derive(PacketWrite)]
pub struct GameRule {
pub rule_name: String,
pub rule_can_be_modified: bool,
pub rule_value: RuleValue,
}
// TODO: flesh out RuleValue
pub enum RuleValue {
Null,
}
impl PacketWrite for RuleValue {
fn write<W: std::io::prelude::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
VarUInt(0).write(writer)
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{
@@ -9,7 +11,6 @@ use crate::{
#[derive(PacketWrite)]
#[packet(49)]
pub struct CInventoryContent {
// https://mojang.github.io/bedrock-protocol-docs/docs/InventoryContentPacket.html
pub container_id: VarUInt,
pub slots: Vec<NetworkItemStackDescriptor>,
pub full_container_name: FullContainerName,

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::{
bedrock::network_item::{FullContainerName, NetworkItemStackDescriptor},
codec::var_uint::VarUInt,
@@ -8,9 +10,9 @@ use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(50)]
pub struct CInventorySlot {
pub window_id: VarUInt,
pub inventory_slot: VarUInt,
pub container_name: Option<FullContainerName>,
pub storage: Option<NetworkItemStackDescriptor>,
pub container_id: VarUInt,
pub slot: VarUInt,
pub full_container_name: Option<FullContainerName>,
pub storage_item: Option<NetworkItemStackDescriptor>,
pub item: NetworkItemStackDescriptor,
}

View File

@@ -6,14 +6,16 @@ use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[packet(162)]
pub struct CItemRegistry {
// https://mojang.github.io/bedrock-protocol-docs/docs/ItemRegistryPacket.html
pub items: Vec<ItemDefinition>,
pub items: Vec<ItemData>,
}
#[derive(PacketWrite)]
pub struct ItemDefinition {
pub name: String,
pub id: i16,
pub component_based: bool,
pub struct ItemData {
pub item_name: String,
pub item_id: i16,
pub is_component_based: bool,
// TODO: ItemVersion enum
pub item_version: VarInt,
// Normally would be `Nbt`, but for simplicity elsewhere, this is preserialized (via `Nbt::write_bedrock`)

View File

@@ -9,10 +9,10 @@ use pumpkin_macros::packet;
#[derive(Debug, Clone)]
pub struct ItemStackResponseSlotInfo {
pub requested_slot: u8,
pub slot: u8,
pub hotbar_slot: u8,
pub count: u8,
pub item_stack_id: VarInt,
pub amount: u8,
pub item_stack_net_id: VarInt,
pub custom_name: String,
pub filtered_custom_name: String,
pub durability_correction: VarInt,
@@ -26,13 +26,13 @@ impl PacketWrite for ItemStackResponseSlotInfo {
"durability correction must fit in an i16",
));
}
self.requested_slot.write(writer)?;
self.slot.write(writer)?;
self.hotbar_slot.write(writer)?;
self.count.write(writer)?;
self.amount.write(writer)?;
true.write(writer)?;
(self.item_stack_id.0 > 0).write(writer)?;
if self.item_stack_id.0 > 0 {
self.item_stack_id.write(writer)?;
(self.item_stack_net_id.0 > 0).write(writer)?;
if self.item_stack_net_id.0 > 0 {
self.item_stack_net_id.write(writer)?;
}
self.custom_name.write(writer)?;
self.filtered_custom_name.write(writer)?;
@@ -42,26 +42,27 @@ impl PacketWrite for ItemStackResponseSlotInfo {
#[derive(PacketWrite, Debug, Clone)]
pub struct ItemStackResponseContainerInfo {
pub container_name: FullContainerName,
pub full_container_name: FullContainerName,
pub slots: Vec<ItemStackResponseSlotInfo>,
}
#[derive(Debug, Clone)]
pub struct ItemStackResponse {
pub struct ItemStackResponseInfo {
// TODO: proper enum
pub result: u8, // 0 = SUCCESS, 1 = ERROR
pub request_id: VarInt,
pub container_infos: Vec<ItemStackResponseContainerInfo>,
pub client_request_id: VarInt,
pub containers: Vec<ItemStackResponseContainerInfo>,
}
impl PacketWrite for ItemStackResponse {
impl PacketWrite for ItemStackResponseInfo {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.result.write(writer)?;
self.request_id.write(writer)?;
self.client_request_id.write(writer)?;
true.write(writer)?;
(!self.container_infos.is_empty()).write(writer)?;
if !self.container_infos.is_empty() {
VarUInt(self.container_infos.len() as u32).write(writer)?;
for info in &self.container_infos {
(!self.containers.is_empty()).write(writer)?;
if !self.containers.is_empty() {
VarUInt(self.containers.len() as u32).write(writer)?;
for info in &self.containers {
info.write(writer)?;
}
}
@@ -72,7 +73,7 @@ impl PacketWrite for ItemStackResponse {
#[derive(Debug, Clone)]
#[packet(148)]
pub struct CItemStackResponse {
pub responses: Vec<ItemStackResponse>,
pub responses: Vec<ItemStackResponseInfo>,
}
impl PacketWrite for CItemStackResponse {
@@ -98,10 +99,10 @@ mod tests {
#[test]
fn rejects_out_of_range_durability_correction() {
let slot = ItemStackResponseSlotInfo {
requested_slot: 0,
slot: 0,
hotbar_slot: 0,
count: 1,
item_stack_id: VarInt(1),
amount: 1,
item_stack_net_id: VarInt(1),
custom_name: String::new(),
filtered_custom_name: String::new(),
durability_correction: VarInt(32768),

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;

View File

@@ -1,20 +1,18 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use crate::{codec::var_int::VarInt, serial::PacketWrite};
/// Sent by the server to spawn a visual particle effect at a specific 3D location in the world.
///
/// Packet ID: `123`
/// Ref: <https://mojang.github.io/bedrock-protocol-docs/html/LevelSoundEventPacket.html>
#[derive(PacketWrite)]
#[packet(123)]
pub struct CLevelSoundEvent {
pub sound_id: String,
pub sound_event: String,
pub position: Vector3<f32>,
pub extra_data: VarInt,
pub entity_type: String,
pub is_baby_mob: bool,
pub data: VarInt,
pub actor_identifier: String,
pub is_baby: bool,
pub is_global: bool,
pub actor_unique_id: i64,
pub fire_at_position: Option<Vector3<f32>>,
@@ -29,11 +27,11 @@ mod tests {
assert_eq!(<CLevelSoundEvent as crate::Packet>::PACKET_ID, 123);
let packet = CLevelSoundEvent {
sound_id: "test".into(),
sound_event: "test".into(),
position: Vector3::new(1.0, 2.0, 3.0),
extra_data: VarInt(-1),
entity_type: "actor".into(),
is_baby_mob: true,
data: VarInt(-1),
actor_identifier: "actor".into(),
is_baby: true,
is_global: false,
actor_unique_id: 42,
fire_at_position: Some(Vector3::new(4.0, 5.0, 6.0)),

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{
@@ -8,12 +10,15 @@ use crate::{
#[derive(PacketWrite)]
#[packet(28)]
pub struct CMobEffect {
pub runtime_entity_id: VarULong,
pub target_runtime_id: VarULong,
// TODO: Event enum
pub event_id: u8,
pub effect_id: VarInt,
pub amplifier: VarInt,
pub particles: bool,
pub duration: VarInt,
pub effect_amplifier: VarInt,
pub show_particles: bool,
pub effect_duration_ticks: VarInt,
pub tick: VarULong,
pub ambient: bool,
}
@@ -22,28 +27,4 @@ impl CMobEffect {
pub const EVENT_ADD: u8 = 1;
pub const EVENT_MODIFY: u8 = 2;
pub const EVENT_REMOVE: u8 = 3;
#[expect(clippy::too_many_arguments)]
#[must_use]
pub const fn new(
runtime_entity_id: VarULong,
event_id: u8,
effect_id: VarInt,
amplifier: VarInt,
particles: bool,
duration: VarInt,
tick: VarULong,
ambient: bool,
) -> Self {
Self {
runtime_entity_id,
event_id,
effect_id,
amplifier,
particles,
duration,
tick,
ambient,
}
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::{
bedrock::network_item::NetworkItemStackDescriptor, codec::var_ulong::VarULong,
serial::PacketWrite,
@@ -7,39 +9,9 @@ use pumpkin_macros::packet;
#[derive(PacketWrite, Debug)]
#[packet(31)]
pub struct CMobEquipment {
pub entity_runtime_id: VarULong,
pub target_runtime_id: VarULong,
pub item: NetworkItemStackDescriptor,
pub inventory_slot: u8,
pub hotbar_slot: u8,
pub window_id: u8,
}
impl CMobEquipment {
#[must_use]
pub const fn new(
entity_runtime_id: u64,
item: NetworkItemStackDescriptor,
inventory_slot: u8,
hotbar_slot: u8,
window_id: u8,
) -> Self {
Self {
entity_runtime_id: VarULong(entity_runtime_id),
item,
inventory_slot,
hotbar_slot,
window_id,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::packet::Packet;
#[test]
fn mob_equipment_packet_id() {
assert_eq!(CMobEquipment::PACKET_ID, 31);
}
pub slot: u8,
pub selected_slot: u8,
pub container_id: u8,
}

View File

@@ -7,14 +7,14 @@ pub mod block_actor_data;
pub mod block_event;
pub mod boss_event;
pub mod change_dimension;
pub mod chunk_radius_update;
pub mod chunk_radius_updated;
pub mod client_cache_miss_response;
pub mod common;
pub mod container_open;
pub mod correct_player_move;
pub mod correct_player_move_prediction;
pub mod crafting_data;
pub mod creative_content;
pub mod disconnect_player;
pub mod disconnect;
pub mod gamerules_changed;
pub mod inventory_content;
pub mod inventory_slot;
@@ -35,16 +35,17 @@ pub mod play_status;
pub mod player_hotbar;
pub mod player_list;
pub mod remove_actor;
pub mod remove_objective;
pub mod resource_pack_stack;
pub mod resource_packs_info;
pub mod respawn;
pub mod scoreboard;
pub mod set_actor_data;
pub mod set_actor_link;
pub mod set_actor_motion;
pub mod set_difficulty;
pub mod set_display_objective;
pub mod set_health;
pub mod set_player_gamemode;
pub mod set_score;
pub mod set_spawn_position;
pub mod set_time;
pub mod set_title;
@@ -66,14 +67,14 @@ pub use block_actor_data::*;
pub use block_event::*;
pub use boss_event::*;
pub use change_dimension::*;
pub use chunk_radius_update::*;
pub use chunk_radius_updated::*;
pub use client_cache_miss_response::*;
pub use common::*;
pub use container_open::*;
pub use correct_player_move::*;
pub use correct_player_move_prediction::*;
pub use crafting_data::*;
pub use creative_content::*;
pub use disconnect_player::*;
pub use disconnect::*;
pub use gamerules_changed::*;
pub use inventory_content::*;
pub use inventory_slot::*;
@@ -94,16 +95,17 @@ pub use play_status::*;
pub use player_hotbar::*;
pub use player_list::*;
pub use remove_actor::*;
pub use remove_objective::*;
pub use resource_pack_stack::*;
pub use resource_packs_info::*;
pub use respawn::*;
pub use scoreboard::*;
pub use set_actor_data::*;
pub use set_actor_link::*;
pub use set_actor_motion::*;
pub use set_difficulty::*;
pub use set_display_objective::*;
pub use set_health::*;
pub use set_player_gamemode::*;
pub use set_score::*;
pub use set_spawn_position::*;
pub use set_time::*;
pub use set_title::*;

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
use pumpkin_macros::packet;
@@ -5,5 +7,5 @@ use pumpkin_macros::packet;
#[derive(PacketWrite)]
pub struct CModalFormRequest {
pub form_id: VarUInt,
pub form_data: String,
pub form_ui_json: String,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::{codec::var_ulong::VarULong, serial::PacketWrite};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
@@ -5,35 +7,16 @@ use pumpkin_util::math::vector3::Vector3;
#[derive(PacketWrite)]
#[packet(18)]
pub struct CMoveActorAbsolute {
pub entity_runtime_id: VarULong,
pub flags: u8,
pub actor_runtime_id: VarULong,
pub header: u8,
pub position: Vector3<f32>,
pub pitch: u8,
pub yaw: u8,
pub head_yaw: u8,
pub rotation_x: u8,
pub rotation_y: u8,
pub rotation_y_head: u8,
}
impl CMoveActorAbsolute {
pub const FLAG_ON_GROUND: u8 = 0x01;
pub const FLAG_TELEPORT: u8 = 0x02;
pub const FLAG_FORCE_MOVE: u8 = 0x04;
#[must_use]
pub const fn new(
entity_runtime_id: VarULong,
flags: u8,
position: Vector3<f32>,
pitch: u8,
yaw: u8,
head_yaw: u8,
) -> Self {
Self {
entity_runtime_id,
flags,
position,
pitch,
yaw,
head_yaw,
}
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::serial::PacketWrite;
@@ -6,28 +8,12 @@ use crate::serial::PacketWrite;
#[packet(143)]
pub struct CNetworkSettings {
pub compression_threshold: u16,
// TODO: CompressionAlgorithm enum
/// `ZLib` = 0, Snappy = 1, None = 255
pub compression_method: u16,
pub compression_algorithm: u16,
pub client_throttle_enabled: bool,
pub client_throttle_threshold: u8,
pub client_throttle_scalar: f32,
}
impl CNetworkSettings {
#[must_use]
pub const fn new(
compression_threshold: u16,
compression_method: u16,
client_throttle_enabled: bool,
client_throttle_threshold: u8,
client_throttle_scalar: f32,
) -> Self {
Self {
compression_threshold,
compression_method,
client_throttle_enabled,
client_throttle_threshold,
client_throttle_scalar,
}
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use std::io::{Error, Write};
use pumpkin_macros::packet;
@@ -5,6 +7,7 @@ use pumpkin_macros::packet;
use crate::serial::PacketWrite;
#[derive(Clone, Copy)]
#[repr(i32)]
#[packet(2)]
pub enum CPlayStatus {
LoginSuccess = 0,

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
@@ -7,5 +9,5 @@ use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
pub struct CPlayerHotbar {
pub selected_slot: VarUInt,
pub container_id: u8,
pub should_select_block: bool,
pub should_select_slot: bool,
}

View File

@@ -1,15 +1,17 @@
// Last verified for v2169
use crate::{codec::var_long::VarLong, serial::PacketWrite};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(14)]
pub struct CRemoveActor {
pub entity_unique_id: VarLong,
pub target_actor_id: VarLong,
}
impl CRemoveActor {
#[must_use]
pub const fn new(entity_unique_id: VarLong) -> Self {
Self { entity_unique_id }
pub const fn new(target_actor_id: VarLong) -> Self {
Self { target_actor_id }
}
}

View File

@@ -0,0 +1,10 @@
// Last verified for v2169
use crate::serial::PacketWrite;
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(106)]
pub struct CRemoveObjective {
pub objective_name: String,
}

View File

@@ -1,9 +1,11 @@
// Last verified for v2169
use crate::{bedrock::client::start_game::Experiments, serial::PacketWrite};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
pub struct ResourcePackStackEntry {
pub uuid: String,
pub struct PackInstanceId {
pub pack_id: String,
pub version: String,
pub sub_pack_name: String,
}
@@ -11,28 +13,9 @@ pub struct ResourcePackStackEntry {
#[derive(PacketWrite)]
#[packet(7)]
pub struct CResourcePackStackPacket {
pub resource_pack_required: bool,
pub resource_packs: Vec<ResourcePackStackEntry>,
pub game_version: String,
pub texture_pack_required: bool,
pub texture_pack_list: Vec<PackInstanceId>,
pub base_game_version: String,
pub experiments: Experiments,
pub include_editor_packs: bool,
}
impl CResourcePackStackPacket {
#[must_use]
pub const fn new(
resource_pack_required: bool,
resource_packs: Vec<ResourcePackStackEntry>,
game_version: String,
experiments: Experiments,
include_editor_packs: bool,
) -> Self {
Self {
resource_pack_required,
resource_packs,
game_version,
experiments,
include_editor_packs,
}
}
}

View File

@@ -1,49 +1,44 @@
// Last verified for v2169
use crate::serial::PacketWrite;
use pumpkin_macros::packet;
use std::io::{Error, Write};
#[derive(PacketWrite)]
pub struct ResourcePackEntry {
pub uuid: uuid::Uuid,
pub version: String,
pub size: u64,
pub struct PackInfoData {
pub pack_id_version: PackIdVersion,
pub pack_size: u64,
pub content_key: String,
pub sub_pack_name: String,
pub content_id: String,
pub subpack_name: String,
pub content_identity: String,
pub has_scripts: bool,
pub addon_pack: bool,
pub rtx_enabled: bool,
pub download_url: String,
pub is_addon_pack: bool,
pub is_ray_tracing_capable: bool,
pub cdn_url: String,
}
#[derive(PacketWrite)]
#[packet(6)]
pub struct CResourcePacksInfo {
pub resource_pack_required: bool,
pub has_addon_packs: bool,
pub has_scripts: bool,
pub is_vibrant_visuals_force_disabled: bool,
pub world_template_id: uuid::Uuid,
pub world_template_version: String,
pub resource_packs: Vec<ResourcePackEntry>,
pub force_disable_vibrant_visuals: bool,
pub world_template_id_and_version: PackIdVersion,
pub resource_packs: Vec<PackInfoData>,
}
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)?;
#[derive(PacketWrite)]
pub struct PackIdVersion {
pub pack_uuid: uuid::Uuid,
pub pack_version: String,
}
self.world_template_id.write(writer)?;
self.world_template_version.write(writer)?;
crate::codec::var_uint::VarUInt(self.resource_packs.len() as u32).write(writer)?;
for entry in &self.resource_packs {
entry.write(writer)?;
impl PackIdVersion {
#[must_use]
pub const fn new(pack_uuid: uuid::Uuid, pack_version: String) -> Self {
Self {
pack_uuid,
pack_version,
}
Ok(())
}
}

View File

@@ -1,49 +0,0 @@
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use crate::{bedrock::respawn::RespawnState, codec::var_ulong::VarULong, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(45)]
pub struct CRespawn {
pub position: Vector3<f32>,
pub state: RespawnState,
pub player_runtime_id: VarULong,
}
impl CRespawn {
#[must_use]
pub const fn new(
position: Vector3<f32>,
state: RespawnState,
player_runtime_id: VarULong,
) -> Self {
Self {
position,
state,
player_runtime_id,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{bedrock::server::respawn::SRespawn, serial::PacketRead};
#[test]
fn respawn_packet_roundtrip() {
let packet = CRespawn::new(
Vector3::new(1.5, 64.0, -2.25),
RespawnState::ReadyToSpawn,
VarULong(42),
);
let mut encoded = Vec::new();
packet.write(&mut encoded).unwrap();
let decoded = SRespawn::read(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded.position, packet.position);
assert_eq!(decoded.state, packet.state);
assert_eq!(decoded.player_runtime_id.0, packet.player_runtime_id.0);
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use std::{collections::HashMap, io::Write};
use crate::{
@@ -9,34 +11,34 @@ use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
use std::io::Error;
#[derive(PacketWrite)]
#[packet(39)] // ProtocolInfo::SET_ACTOR_DATA_PACKET is 39
#[packet(39)]
pub struct CSetActorData {
/// The unique runtime ID of the entity being updated
pub actor_runtime_id: VarULong,
pub target_runtime_id: VarULong,
/// A map of entity metadata properties (e.g., flags, name tags, scale)
pub metadata: EntityMetadata,
pub actor_data: SyncedActorDataList,
/// Dynamic properties synced between client and server
pub synced_properties: PropertySyncData,
/// The server tick at which this update occurred
pub tick: VarULong,
}
pub struct EntityMetadata(pub HashMap<u32, MetadataValue>);
pub struct SyncedActorDataList(pub HashMap<u32, MetadataValue>);
impl Default for EntityMetadata {
impl Default for SyncedActorDataList {
fn default() -> Self {
Self::new()
}
}
impl EntityMetadata {
impl SyncedActorDataList {
#[must_use]
pub fn new() -> Self {
Self(HashMap::new())
}
}
impl EntityMetadata {
impl SyncedActorDataList {
pub fn set(&mut self, key: u32, value: MetadataValue) {
self.0.insert(key, value);
}
@@ -55,7 +57,7 @@ impl EntityMetadata {
self.0.insert(key, MetadataValue::Byte(new_value));
} else {
let current_value = match self.0.get(&key) {
Some(MetadataValue::Long(v)) => *v,
Some(MetadataValue::Int64(v)) => *v,
_ => 0,
};
let new_value = if value {
@@ -63,12 +65,12 @@ impl EntityMetadata {
} else {
current_value & !(1i64 << index)
};
self.0.insert(key, MetadataValue::Long(new_value));
self.0.insert(key, MetadataValue::Int64(new_value));
}
}
}
impl PacketWrite for EntityMetadata {
impl PacketWrite for SyncedActorDataList {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarUInt(self.0.len() as u32).write(writer)?;
@@ -90,8 +92,8 @@ pub enum MetadataValue {
Float(f32),
String(String),
CompoundTag,
BlockPos(BlockPos),
Long(i64),
ItemPos(BlockPos),
Int64(i64),
Vec3(Vector3<f32>),
}
@@ -105,8 +107,8 @@ impl MetadataValue {
Self::Float(_) => 3,
Self::String(_) => 4,
Self::CompoundTag => 5,
Self::BlockPos(_) => 6,
Self::Long(_) => 7,
Self::ItemPos(_) => 6,
Self::Int64(_) => 7,
Self::Vec3(_) => 8,
}
}
@@ -116,39 +118,34 @@ impl MetadataValue {
Self::Byte(v) => v.write(writer),
Self::Short(v) => v.write(writer),
Self::Int(v) => VarInt(*v).write(writer),
Self::Float(v) => writer.write_all(&v.to_le_bytes()),
Self::Float(v) => v.write(writer),
Self::String(v) => v.write(writer),
Self::CompoundTag => Err(Error::other("CompoundTag not implemented")),
Self::BlockPos(v) => v.write(writer),
Self::Long(v) => VarLong(*v).write(writer),
Self::Vec3(v) => {
writer.write_all(&v.x.to_le_bytes())?;
writer.write_all(&v.y.to_le_bytes())?;
writer.write_all(&v.z.to_le_bytes())
}
Self::ItemPos(v) => v.write(writer),
Self::Int64(v) => VarLong(*v).write(writer),
Self::Vec3(v) => v.write(writer),
}
}
}
#[derive(Default)]
pub struct PropertySyncData {
pub int_properties: std::collections::HashMap<u32, i32>,
pub float_properties: std::collections::HashMap<u32, f32>,
pub int_entries_list: std::collections::HashMap<u32, i32>,
pub float_entries_list: std::collections::HashMap<u32, f32>,
}
impl PacketWrite for PropertySyncData {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
// Int Properties
VarUInt(self.int_properties.len() as u32).write(writer)?;
for (key, value) in &self.int_properties {
VarUInt(self.int_entries_list.len() as u32).write(writer)?;
for (key, value) in &self.int_entries_list {
VarUInt(*key).write(writer)?;
VarInt(*value).write(writer)?; // Signed VarInt
VarInt(*value).write(writer)?;
}
// Float Properties
VarUInt(self.float_properties.len() as u32).write(writer)?;
for (key, value) in &self.float_properties {
VarUInt(self.float_entries_list.len() as u32).write(writer)?;
for (key, value) in &self.float_entries_list {
VarUInt(*key).write(writer)?;
writer.write_all(&value.to_le_bytes())?; // LE Float
value.write(writer)?;
}
Ok(())
}
@@ -431,11 +428,11 @@ pub mod entity_data_flag {
#[cfg(test)]
mod tests {
use super::{EntityMetadata, entity_data_key};
use super::{SyncedActorDataList, entity_data_key};
#[test]
fn partial_metadata_does_not_reset_flags() {
let metadata = EntityMetadata::new();
let metadata = SyncedActorDataList::new();
assert!(!metadata.0.contains_key(&entity_data_key::FLAGS));
assert!(!metadata.0.contains_key(&entity_data_key::FLAGS_TWO));

View File

@@ -1,13 +1,11 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{bedrock::client::common::EntityLink, serial::PacketWrite};
use crate::{bedrock::client::common::ActorLink, serial::PacketWrite};
/// Sent by the server to set the entity an actor is riding or to unmount an actor.
///
/// Packet ID: `41`
/// Ref: <https://mojang.github.io/bedrock-protocol-docs/html/SetActorLinkPacket.html>
#[derive(PacketWrite)]
#[packet(41)]
pub struct CSetActorLink {
pub link: EntityLink,
pub link: ActorLink,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
@@ -10,14 +12,3 @@ pub struct CSetActorMotion {
pub motion: Vector3<f32>,
pub tick: VarULong,
}
impl CSetActorMotion {
#[must_use]
pub const fn new(target_runtime_id: VarULong, motion: Vector3<f32>, tick: VarULong) -> Self {
Self {
target_runtime_id,
motion,
tick,
}
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
@@ -7,12 +9,3 @@ use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
pub struct CSetDifficulty {
pub difficulty: VarUInt,
}
impl CSetDifficulty {
#[must_use]
pub const fn new(difficulty: u32) -> Self {
Self {
difficulty: VarUInt(difficulty),
}
}
}

View File

@@ -0,0 +1,14 @@
// Last verified for v2169
use crate::{codec::var_int::VarInt, serial::PacketWrite};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(107)]
pub struct CSetDisplayObjective {
pub display_slot_name: String,
pub objective_name: String,
pub objective_display_name: String,
pub criteria_name: String,
pub sort_order: VarInt,
}

View File

@@ -1,18 +1,10 @@
// Last verified for v2169
use crate::{codec::var_int::VarInt, serial::PacketWrite};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(42)]
pub struct CSetHealth {
// https://mojang.github.io/bedrock-protocol-docs/html/SetHealthPacket.html
pub health: VarInt,
}
impl CSetHealth {
#[must_use]
pub const fn new(health: i32) -> Self {
Self {
health: VarInt(health),
}
}
}

View File

@@ -1,9 +1,10 @@
use crate::serial::PacketWrite;
// Last verified for v2169
use crate::{bedrock::client::GameType, serial::PacketWrite};
use pumpkin_macros::packet;
use pumpkin_util::GameMode;
#[derive(PacketWrite)]
#[packet(62)]
pub struct CSetPlayerGamemode {
pub gamemode: GameMode,
pub struct CSetPlayerGameType {
pub player_game_type: GameType,
}

View File

@@ -6,16 +6,6 @@ use crate::{
};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(107)]
pub struct CSetDisplayObjective {
pub display_slot: String,
pub objective_name: String,
pub display_name: String,
pub criteria_name: String,
pub sort_order: VarInt,
}
#[packet(108)]
pub struct CSetScore {
pub action: VarInt, // 0 = change, 1 = remove
@@ -92,17 +82,3 @@ impl ScoreEntry {
Ok(())
}
}
#[derive(PacketWrite)]
#[packet(106)]
pub struct CRemoveObjective {
pub objective_name: String,
}
impl CRemoveObjective {
pub fn new(objective_name: impl Into<String>) -> Self {
Self {
objective_name: objective_name.into(),
}
}
}

View File

@@ -1,3 +1,7 @@
// Last verified for v2169
use std::io::{Error, Write};
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
@@ -6,25 +10,21 @@ use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[derive(Clone, Copy, PacketWrite)]
#[packet(43)]
pub struct CSetSpawnPosition {
pub spawn_type: VarInt,
pub position: BlockPos,
pub dimension: VarInt,
pub spawn_position: BlockPos,
pub spawn_position_type: SpawnPositionType,
pub block_position: BlockPos,
pub dimension_type: VarInt,
pub spawn_block_pos: BlockPos,
}
impl CSetSpawnPosition {
#[must_use]
pub const fn new(
spawn_type: i32,
position: BlockPos,
dimension: i32,
spawn_position: BlockPos,
) -> Self {
Self {
spawn_type: VarInt(spawn_type),
position,
dimension: VarInt(dimension),
spawn_position,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum SpawnPositionType {
PlayerRespawn,
WorldRespawn,
}
impl PacketWrite for SpawnPositionType {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarInt(*self as i32).write(writer)
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketWrite};

View File

@@ -1,37 +1,61 @@
// Last verified for v2169
use std::io::{Error, Write};
use crate::{codec::var_int::VarInt, serial::PacketWrite};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(88)]
pub struct CSetTitle {
pub action_type: VarInt,
pub text: String,
pub fade_in_duration: VarInt,
pub remain_duration: VarInt,
pub fade_out_duration: VarInt,
pub title_type: TitleType,
pub title_text: String,
pub fade_in_time: VarInt,
pub stay_time: VarInt,
pub fade_out_time: VarInt,
pub xuid: String,
pub platform_online_id: String,
pub filtered_message: String,
pub filtered_title_message: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum TitleType {
Clear,
Reset,
Title,
Subtitle,
Actionbar,
Times,
TitleTextObject,
SubtitleTextObject,
ActionbarTextObject,
}
impl PacketWrite for TitleType {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarInt(*self as i32).write(writer)
}
}
impl CSetTitle {
#[must_use]
pub const fn new(
action_type: i32,
text: String,
fade_in_duration: i32,
remain_duration: i32,
fade_out_duration: i32,
title_type: TitleType,
title_text: String,
fade_in_time: i32,
stay_time: i32,
fade_out_time: i32,
) -> Self {
Self {
action_type: VarInt(action_type),
text,
fade_in_duration: VarInt(fade_in_duration),
remain_duration: VarInt(remain_duration),
fade_out_duration: VarInt(fade_out_duration),
title_type,
title_text,
fade_in_time: VarInt(fade_in_time),
stay_time: VarInt(stay_time),
fade_out_time: VarInt(fade_out_time),
xuid: String::new(),
platform_online_id: String::new(),
filtered_message: String::new(),
filtered_title_message: String::new(),
}
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::{
codec::{var_int::VarInt, var_ulong::VarULong},
serial::PacketWrite,
@@ -8,15 +10,5 @@ use pumpkin_macros::packet;
#[packet(75)]
pub struct CShowCredits {
pub player_runtime_id: VarULong,
pub status: VarInt,
}
impl CShowCredits {
#[must_use]
pub const fn new(player_runtime_id: VarULong, status: VarInt) -> Self {
Self {
player_runtime_id,
status,
}
}
pub credits_state: VarInt,
}

View File

@@ -1,15 +1,12 @@
use std::io::{Error, Write};
use crate::{
bedrock::client::gamerules_changed::GameRules,
bedrock::client::{GameType, gamerules_changed::GameRule},
codec::{var_int::VarInt, var_long::VarLong, var_uint::VarUInt, var_ulong::VarULong},
serial::PacketWrite,
};
use pumpkin_macros::packet;
use pumpkin_util::{
GameMode,
math::{position::BlockPos, vector3::Vector3},
};
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
use uuid::Uuid;
#[derive(PacketWrite)]
@@ -22,7 +19,7 @@ pub struct CStartGame {
// The runtime ID is unique for each world session, and
// entities are generally identified in packets using this runtime ID.
pub runtime_entity_id: VarULong,
pub player_gamemode: GameMode,
pub player_gamemode: GameType,
pub position: Vector3<f32>,
pub pitch: f32,
pub yaw: f32,
@@ -113,7 +110,7 @@ pub struct LevelSettings {
// Level Settings
pub generator_type: VarInt,
pub world_gamemode: GameMode,
pub world_gamemode: GameType,
pub hardcore: bool,
pub difficulty: VarInt,
pub spawn_position: BlockPos,
@@ -135,7 +132,7 @@ pub struct LevelSettings {
pub commands_enabled: bool,
pub is_texture_packs_required: bool,
pub rule_data: GameRules,
pub rule_data: Vec<GameRule>,
pub experiments: Experiments,
pub bonus_chest: bool,
@@ -167,13 +164,30 @@ pub struct LevelSettings {
pub allow_anonymous_block_drops_in_editor_worlds: bool,
}
#[derive(Default, PacketWrite)]
#[derive(Default)]
pub struct Experiments {
//TODO! https://mojang.github.io/bedrock-protocol-docs/html/Experiments.html
pub names_size: u32,
pub toggles: Vec<ExperimentToggle>,
pub experiments_ever_toggled: bool,
}
impl PacketWrite for Experiments {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(self.toggles.len() as u32).write(writer)?;
for toggle in &self.toggles {
toggle.write(writer)?;
}
self.experiments_ever_toggled.write(writer)?;
Ok(())
}
}
#[derive(PacketWrite)]
pub struct ExperimentToggle {
pub name: String,
pub enabled: bool,
}
#[derive(Clone, Copy)]
pub enum GamePublishSetting {
NoMultiPlay = 0,

View File

@@ -1,19 +1,11 @@
// Last verified for v2169
use crate::{codec::var_ulong::VarULong, serial::PacketWrite};
use pumpkin_macros::packet;
#[derive(PacketWrite)]
#[packet(17)]
pub struct CTakeItemActor {
// https://github.com/Sandertv/gophertunnel/blob/master/minecraft/protocol/packet/take_item_actor.go
pub item_runtime_id: VarULong,
pub actor_runtime_id: VarULong,
}
impl CTakeItemActor {
#[must_use]
pub const fn new(item_runtime_id: VarULong, actor_runtime_id: VarULong) -> Self {
Self {
item_runtime_id,
actor_runtime_id,
}
}
}

View File

@@ -6,15 +6,15 @@ use crate::serial::PacketWrite;
#[packet(85)]
pub struct CTransfer {
pub address: String,
pub port: u16,
pub server_address: String,
pub server_port: u16,
pub reload_world: bool,
}
impl PacketWrite for CTransfer {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.address.write(writer)?;
self.port.write(writer)?;
self.server_address.write(writer)?;
self.server_port.write(writer)?;
self.reload_world.write(writer)?;
// Optional GatheringsConfigurationJoinInfo.
false.write(writer)
@@ -23,10 +23,10 @@ impl PacketWrite for CTransfer {
impl CTransfer {
#[must_use]
pub const fn new(address: String, port: u16, reload_world: bool) -> Self {
pub const fn new(server_address: String, server_port: u16, reload_world: bool) -> Self {
Self {
address,
port,
server_address,
server_port,
reload_world,
}
}

View File

@@ -1,20 +1,16 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::serial::PacketWrite;
use super::common::AbilityLayer;
use crate::{bedrock::client::SerializedAbilitiesData, serial::PacketWrite};
#[packet(187)]
#[derive(PacketWrite)]
pub struct CUpdateAbilities {
// https://mojang.github.io/bedrock-protocol-docs/html/UpdateAbilitiesPacket.html
// https://mojang.github.io/bedrock-protocol-docs/html/SerializedAbilitiesData.html
pub target_player_raw_id: i64,
pub player_permission: u8,
pub command_permission: u8,
pub layers: Vec<AbilityLayer>,
pub data: SerializedAbilitiesData,
}
// TODO: confirm these
#[repr(u32)]
pub enum Ability {
Build = 0,

View File

@@ -1,20 +1,19 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{
codec::{var_uint::VarUInt, var_ulong::VarULong},
serial::PacketWrite,
};
use crate::{codec::var_ulong::VarULong, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(29)]
pub struct CUpdateAttributes {
pub runtime_id: VarULong,
pub attributes: Vec<Attribute>,
pub player_tick: VarULong,
pub target_runtime_id: VarULong,
pub attribute_list: Vec<AttributeData>,
pub tick: VarULong,
}
#[derive(PacketWrite)]
pub struct Attribute {
pub struct AttributeData {
pub min_value: f32,
pub max_value: f32,
pub current_value: f32,
@@ -22,5 +21,15 @@ pub struct Attribute {
pub default_max_value: f32,
pub default_value: f32,
pub name: String,
pub modifiers_list_size: VarUInt,
pub modifiers: Vec<AttributeModifier>,
}
#[derive(PacketWrite)]
pub struct AttributeModifier {
pub id: String,
pub name: String,
pub amount: f32,
pub operation: i32,
pub operand: i32,
pub is_serializable: bool,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
@@ -6,7 +8,7 @@ use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
#[derive(PacketWrite)]
#[packet(21)]
pub struct CUpdateBlock {
pub position: BlockPos,
pub block_position: BlockPos,
pub block_runtime_id: VarUInt,
pub flags: VarUInt,
pub layer: VarUInt,
@@ -14,14 +16,14 @@ pub struct CUpdateBlock {
impl CUpdateBlock {
#[must_use]
pub const fn new(position: BlockPos, block_runtime_id: u32) -> Self {
Self::with_layer(position, block_runtime_id, 0)
pub const fn new(block_position: BlockPos, block_runtime_id: u32) -> Self {
Self::with_layer(block_position, block_runtime_id, 0)
}
#[must_use]
pub const fn with_layer(position: BlockPos, block_runtime_id: u32, layer: u32) -> Self {
pub const fn with_layer(block_position: BlockPos, block_runtime_id: u32, layer: u32) -> Self {
Self {
position,
block_position,
block_runtime_id: VarUInt(block_runtime_id),
flags: VarUInt(0x3), // neighbors | network
layer: VarUInt(layer),

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_nbt::compound::NbtCompound;

View File

@@ -0,0 +1,44 @@
use crate::serial::{PacketRead, PacketWrite};
use std::str::FromStr;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct EnumAsStr<T>(T);
impl<T: FromStr> FromStr for EnumAsStr<T>
where
std::io::Error: From<T::Err>,
{
type Err = std::io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(T::from_str(s)?))
}
}
#[allow(clippy::to_string_trait_impl)]
impl<T: ToString> ToString for EnumAsStr<T> {
fn to_string(&self) -> String {
self.0.to_string()
}
}
impl<T: FromStr> PacketRead for EnumAsStr<T>
where
std::io::Error: From<T::Err>,
{
fn read<R: std::io::Read>(reader: &mut R) -> Result<Self, std::io::Error> {
Self::from_str(&String::read(reader)?)
}
}
impl<T: ToString> PacketWrite for EnumAsStr<T> {
fn write<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
self.to_string().write(writer)
}
}
impl<T> From<T> for EnumAsStr<T> {
fn from(value: T) -> Self {
Self(value)
}
}

View File

@@ -1,8 +1,8 @@
pub mod client;
pub mod enum_as_str;
pub mod network_item;
pub mod packet_decoder;
pub mod packet_encoder;
pub mod respawn;
pub mod server;
pub mod status;

View File

@@ -1,31 +0,0 @@
use std::io::{Error, ErrorKind, Read, Write};
use crate::serial::{PacketRead, PacketWrite};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum RespawnState {
SearchingForSpawn = 0,
ReadyToSpawn = 1,
ClientReadyToSpawn = 2,
}
impl PacketRead for RespawnState {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
match u8::read(reader)? {
0 => Ok(Self::SearchingForSpawn),
1 => Ok(Self::ReadyToSpawn),
2 => Ok(Self::ClientReadyToSpawn),
state => Err(Error::new(
ErrorKind::InvalidData,
format!("invalid Bedrock respawn state {state}"),
)),
}
}
}
impl PacketWrite for RespawnState {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(*self as u8).write(writer)
}
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use std::io::{Error, Read, Write};
use pumpkin_macros::packet;
@@ -11,79 +13,79 @@ use crate::{
#[derive(Debug, PacketRead, PacketWrite)]
#[packet(27)]
pub struct SActorEvent {
pub entity_runtime_id: VarULong,
pub event_type: ActorEventType,
pub event_data: VarInt,
pub target_runtime_id: VarULong,
pub event_id: ActorEventID,
pub data: VarInt,
pub fire_at_position: Option<Vector3<f32>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ActorEventType {
None = 0,
Jump = 1,
Hurt = 2,
Death = 3,
StartAttacking = 4,
StopAttacking = 5,
TamingFailed = 6,
TamingSucceeded = 7,
ShakeWetness = 8,
pub enum ActorEventID {
None,
Jump,
Hurt,
Death,
StartAttacking,
StopAttacking,
TamingFailed,
TamingSucceeded,
ShakeWetness,
EatGrass = 10,
FishhookBubble = 11,
FishhookFishPosition = 12,
FishhookHookTime = 13,
FishhookTease = 14,
SquidFleeing = 15,
ZombieConverting = 16,
PlayAmbient = 17,
SpawnAlive = 18,
StartOfferFlower = 19,
StopOfferFlower = 20,
LoveHearts = 21,
VillagerAngry = 22,
VillagerHappy = 23,
WitchHatMagic = 24,
FireworksExplode = 25,
InLoveHearts = 26,
SilverfishMergeAnimation = 27,
GuardianAttackSound = 28,
DrinkPotion = 29,
ThrowPotion = 30,
CartWithPrimeTNT = 31,
PrimeCreeper = 32,
AirSupply = 33,
AddPlayerLevels = 34,
GuardianMiningFatigue = 35,
AgentSwingArm = 36,
DragonStartDeathAnim = 37,
GroundDust = 38,
Shake = 39,
FishhookBubble,
FishhookFishPos,
FishhookHookTime,
FishhookTease,
SquidFleeing,
ZombieConverting,
PlayAmbient,
SpawnAlive,
StartOfferFlower,
StopOfferFlower,
LoveHearts,
VillagerAngry,
VillagerHappy,
WitchHatMagic,
FireworksExplode,
InLoveHearts,
SilverfishMergeAnimation,
GuardianAttackSound,
DrinkPotion,
ThrowPotion,
PrimeTNTCart,
PrimeCreeper,
AirSupply,
DeprecatedAddPlayerLevels,
GuardianMiningFatigue,
AgentSwingArm,
DragonStartDeathAnim,
GroundDust,
Shake,
Feed = 57,
BabyAge = 60,
InstantDeath = 61,
NotifyTrade = 62,
LeashDestroyed = 63,
CaravanUpdated = 64,
TalismanActivate = 65,
UpdateStructureFeature = 66,
PlayerSpawnedMob = 67,
Puke = 68,
UpdateStackSize = 69,
StartSwimming = 70,
BalloonPop = 71,
TreasureHunt = 72,
SummonAgent = 73,
FinishedChargingItem = 74,
InstantDeath,
NotifyTrade,
LeashDestroyed,
CaravanUpdated,
TalismanActivate,
DeprecatedUpdateStructureFeature,
PlayerSpawnedMob,
Puke,
UpdateStackSize,
StartSwimming,
BalloonPop,
TreasureHunt,
SummonAgent,
FinishedChargingItem,
ActorGrowUp = 76,
VibrationDetected = 77,
DrinkMilk = 78,
ShakeWetnessStop = 79,
KineticDamageDealt = 80,
HurtWithoutReceivingDamage = 81,
VibrationDetected,
DrinkMilk,
ShakeWetnessStop,
KineticDamageDealt,
HurtWithoutReceivingDamage,
}
impl PacketRead for ActorEventType {
impl PacketRead for ActorEventID {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
Ok(match u8::read(reader)? {
0 => Self::None,
@@ -97,7 +99,7 @@ impl PacketRead for ActorEventType {
8 => Self::ShakeWetness,
10 => Self::EatGrass,
11 => Self::FishhookBubble,
12 => Self::FishhookFishPosition,
12 => Self::FishhookFishPos,
13 => Self::FishhookHookTime,
14 => Self::FishhookTease,
15 => Self::SquidFleeing,
@@ -116,10 +118,10 @@ impl PacketRead for ActorEventType {
28 => Self::GuardianAttackSound,
29 => Self::DrinkPotion,
30 => Self::ThrowPotion,
31 => Self::CartWithPrimeTNT,
31 => Self::PrimeTNTCart,
32 => Self::PrimeCreeper,
33 => Self::AirSupply,
34 => Self::AddPlayerLevels,
34 => Self::DeprecatedAddPlayerLevels,
35 => Self::GuardianMiningFatigue,
36 => Self::AgentSwingArm,
37 => Self::DragonStartDeathAnim,
@@ -132,7 +134,7 @@ impl PacketRead for ActorEventType {
63 => Self::LeashDestroyed,
64 => Self::CaravanUpdated,
65 => Self::TalismanActivate,
66 => Self::UpdateStructureFeature,
66 => Self::DeprecatedUpdateStructureFeature,
67 => Self::PlayerSpawnedMob,
68 => Self::Puke,
69 => Self::UpdateStackSize,
@@ -152,7 +154,7 @@ impl PacketRead for ActorEventType {
}
}
impl PacketWrite for ActorEventType {
impl PacketWrite for ActorEventID {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(*self as u8).write(writer)
}
@@ -166,21 +168,21 @@ mod tests {
fn reads_feed_event() {
let packet = SActorEvent::read(&mut b"\x019\x80\x80\x90\x11\0".as_slice()).unwrap();
assert_eq!(packet.entity_runtime_id, VarULong(1));
assert_eq!(packet.event_type, ActorEventType::Feed);
assert_eq!(packet.event_data, VarInt(17_956_864));
assert_eq!(packet.target_runtime_id, VarULong(1));
assert_eq!(packet.event_id, ActorEventID::Feed);
assert_eq!(packet.data, VarInt(17_956_864));
assert_eq!(packet.fire_at_position, None);
}
#[test]
fn feed_event_wire_value_is_bidirectional() {
let mut encoded = Vec::new();
ActorEventType::Feed.write(&mut encoded).unwrap();
ActorEventID::Feed.write(&mut encoded).unwrap();
assert_eq!(encoded, [57]);
assert_eq!(
ActorEventType::read(&mut encoded.as_slice()).unwrap(),
ActorEventType::Feed
ActorEventID::read(&mut encoded.as_slice()).unwrap(),
ActorEventID::Feed
);
}
}

View File

@@ -1,8 +1,14 @@
use std::io::{Error, Read, Write};
// Last verified for v2169
use std::{
io::{Error, Read, Write},
str::FromStr,
};
use pumpkin_macros::packet;
use crate::{
bedrock::enum_as_str::EnumAsStr,
codec::var_ulong::VarULong,
serial::{PacketRead, PacketWrite},
};
@@ -39,21 +45,22 @@ impl PacketWrite for AnimateAction {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum AnimateSwingSource {
None = 1,
Build = 2,
Mine = 3,
Interact = 4,
Attack = 5,
UseItem = 6,
ThrowItem = 7,
DropItem = 8,
Event = 9,
pub enum ActorSwingSource {
None,
Build,
Mine,
Interact,
Attack,
UseItem,
ThrowItem,
DropItem,
Event,
}
impl PacketRead for AnimateSwingSource {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
match String::read(reader)?.as_str() {
impl FromStr for ActorSwingSource {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"none" => Ok(Self::None),
"build" => Ok(Self::Build),
"mine" => Ok(Self::Mine),
@@ -68,8 +75,9 @@ impl PacketRead for AnimateSwingSource {
}
}
impl PacketWrite for AnimateSwingSource {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
#[allow(clippy::to_string_trait_impl)]
impl ToString for ActorSwingSource {
fn to_string(&self) -> String {
match self {
Self::None => "none",
Self::Build => "build",
@@ -81,7 +89,7 @@ impl PacketWrite for AnimateSwingSource {
Self::DropItem => "dropitem",
Self::Event => "event",
}
.write(writer)
.into()
}
}
@@ -89,9 +97,9 @@ impl PacketWrite for AnimateSwingSource {
#[packet(44)]
pub struct SAnimate {
pub action: AnimateAction,
pub runtime_entity_id: VarULong,
pub target_actor_runtime_id: VarULong,
pub data: f32,
pub swing_source: Option<AnimateSwingSource>,
pub swing_source: Option<EnumAsStr<ActorSwingSource>>,
}
#[cfg(test)]
@@ -102,9 +110,9 @@ mod tests {
fn animate_uses_cereal_swing_source_encoding() {
let packet = SAnimate {
action: AnimateAction::SwingArm,
runtime_entity_id: VarULong(42),
target_actor_runtime_id: VarULong(42),
data: 0.0,
swing_source: Some(AnimateSwingSource::Attack),
swing_source: Some(ActorSwingSource::Attack.into()),
};
let mut encoded = Vec::new();
packet.write(&mut encoded).unwrap();
@@ -113,16 +121,16 @@ mod tests {
let decoded = SAnimate::read(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded.action, AnimateAction::SwingArm);
assert_eq!(decoded.runtime_entity_id, VarULong(42));
assert_eq!(decoded.target_actor_runtime_id, VarULong(42));
assert_eq!(decoded.data, 0.0);
assert_eq!(decoded.swing_source, Some(AnimateSwingSource::Attack));
assert_eq!(decoded.swing_source, Some(ActorSwingSource::Attack.into()));
}
#[test]
fn animate_omits_absent_swing_source_value() {
let packet = SAnimate {
action: AnimateAction::NoAction,
runtime_entity_id: VarULong(1),
target_actor_runtime_id: VarULong(1),
data: 0.0,
swing_source: None,
};

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
@@ -6,7 +8,7 @@ use crate::serial::PacketRead;
#[derive(Debug, PacketRead)]
#[packet(34)]
pub struct SBlockPickRequest {
pub block_pos: BlockPos,
pub add_block_nbt: bool,
pub hotbar_slot: u8,
pub position: BlockPos,
pub with_data: bool,
pub max_slots: u8,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use std::io::{Error, Read};
use pumpkin_macros::packet;
@@ -21,9 +23,7 @@ impl PacketRead for SClientCacheBlobStatus {
}
let mut miss_hashes = Vec::with_capacity(miss_count.min(256));
for _ in 0..miss_count {
let mut bytes = [0u8; 8];
reader.read_exact(&mut bytes)?;
miss_hashes.push(u64::from_le_bytes(bytes));
miss_hashes.push(u64::read(reader)?);
}
let hit_count = VarUInt::read(reader)?.0 as usize;
@@ -35,9 +35,7 @@ impl PacketRead for SClientCacheBlobStatus {
}
let mut hit_hashes = Vec::with_capacity(hit_count.min(256));
for _ in 0..hit_count {
let mut bytes = [0u8; 8];
reader.read_exact(&mut bytes)?;
hit_hashes.push(u64::from_le_bytes(bytes));
hit_hashes.push(u64::read(reader)?);
}
Ok(Self {

View File

@@ -1,9 +1,10 @@
// Last verified for v2169
use crate::serial::PacketRead;
use pumpkin_macros::packet;
#[derive(PacketRead)]
#[packet(129)]
pub struct SClientCacheStatus {
// https://mojang.github.io/bedrock-protocol-docs/html/ClientCacheStatusPacket.html
pub cache_supported: bool,
pub is_cache_supported: bool,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use std::borrow::Cow;
use uuid::Uuid;
@@ -8,10 +10,17 @@ use crate::serial::{PacketRead, PacketReadSlice};
#[packet(77)]
pub struct SCommandRequest<'a> {
pub command: Cow<'a, str>,
pub command_type: Cow<'a, str>,
pub command_uuid: Uuid,
pub request_id: Cow<'a, str>,
pub player_actor_unique_id: i64,
pub is_internal_source: bool,
pub origin: CommandOriginData<'a>,
pub is_internal: bool,
// TODO: enum CurrentCmdVersion
pub version: Cow<'a, str>,
}
#[derive(Debug, PacketRead, PacketReadSlice)]
pub struct CommandOriginData<'a> {
pub r#type: Cow<'a, str>,
pub uuid: Uuid,
pub request_id: Cow<'a, str>,
pub player_id: i64,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::serial::{PacketRead, PacketWrite};
@@ -5,8 +7,7 @@ use crate::serial::{PacketRead, PacketWrite};
#[derive(Debug, PacketWrite, PacketRead)]
#[packet(47)]
pub struct SContainerClose {
// https://mojang.github.io/bedrock-protocol-docs/html/ContainerClosePacket.html
pub container_id: u8,
pub container_type: u8,
pub server_initiated: bool,
pub server_initiated_close: bool,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::codec::var_uint::VarUInt;
use crate::codec::var_ulong::VarULong;
use crate::serial::{PacketRead, PacketReadSlice, PacketWrite};
@@ -10,9 +12,9 @@ pub const EMOTE_FLAG_MUTE_CHAT: u8 = 1 << 1;
#[derive(Debug, PacketRead, PacketReadSlice, PacketWrite)]
#[packet(138)]
pub struct SEmote<'a> {
pub runtime_entity_id: VarULong,
pub emote_length: VarUInt,
pub actor_runtime_id: VarULong,
pub emote_id: Cow<'a, str>,
pub emote_length_ticks: VarUInt,
pub xuid: Cow<'a, str>,
pub platform_id: Cow<'a, str>,
pub flags: u8,

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use uuid::Uuid;
use crate::{
@@ -9,8 +11,8 @@ use pumpkin_macros::packet;
#[derive(Debug, PacketRead, PacketWrite)]
#[packet(152)]
pub struct SEmoteList {
pub runtime_entity_id: VarULong,
pub emote_pieces: Vec<Uuid>,
pub runtime_id: VarULong,
pub emote_piece_ids: Vec<Uuid>,
}
#[cfg(test)]
@@ -21,8 +23,8 @@ mod tests {
#[test]
fn emote_list_serialization() {
let packet = SEmoteList {
runtime_entity_id: VarULong(123),
emote_pieces: vec![Uuid::new_v4(), Uuid::new_v4()],
runtime_id: VarULong(123),
emote_piece_ids: vec![Uuid::new_v4(), Uuid::new_v4()],
};
let mut buf = Vec::new();
@@ -31,7 +33,7 @@ mod tests {
let mut reader = Cursor::new(buf);
let decoded = SEmoteList::read(&mut reader).unwrap();
assert_eq!(packet.runtime_entity_id.0, decoded.runtime_entity_id.0);
assert_eq!(packet.emote_pieces, decoded.emote_pieces);
assert_eq!(packet.runtime_id.0, decoded.runtime_id.0);
assert_eq!(packet.emote_piece_ids, decoded.emote_piece_ids);
}
}

View File

@@ -0,0 +1,39 @@
// Last verified for v2169
use std::io::{Error, Read};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use crate::{codec::var_ulong::VarULong, serial::PacketRead};
#[derive(Debug, PacketRead)]
#[packet(33)]
pub struct SInteract {
pub action: Action,
pub target_runtime_id: VarULong,
pub position: Option<Vector3<f32>>,
}
#[derive(Debug)]
#[repr(u8)]
pub enum Action {
Invalid = 0,
StopRiding = 3,
InteractUpdate = 4,
NpcOpen = 5,
OpenInventory = 6,
}
impl PacketRead for Action {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
match u8::read(reader)? {
0 => Ok(Self::Invalid),
3 => Ok(Self::StopRiding),
4 => Ok(Self::InteractUpdate),
5 => Ok(Self::NpcOpen),
6 => Ok(Self::OpenInventory),
_ => Err(Error::other("")),
}
}
}

View File

@@ -1,48 +0,0 @@
use std::io::{Error, Read};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use crate::{codec::var_ulong::VarULong, serial::PacketRead};
#[derive(Debug, PacketRead)]
#[packet(33)]
pub struct SInteraction {
// https://mojang.github.io/bedrock-protocol-docs/html/InteractPacket.html
pub action: Action,
pub target_runtime_id: VarULong,
pub position: Option<Vector3<f32>>,
}
#[derive(Debug)]
#[repr(i8)]
pub enum Action {
Invalid = 0,
Interact = 1,
// No longer used in newer versions
Attack = 2,
StopRiding = 3,
InteractUpdate = 4,
NpcOpen = 5,
OpenInventory = 6,
}
impl PacketRead for Action {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let mut byte = [0];
reader.read_exact(&mut byte)?;
let this = match byte[0] {
0 => Self::Invalid,
1 => Self::Interact,
2 => Self::Attack,
3 => Self::StopRiding,
4 => Self::InteractUpdate,
5 => Self::NpcOpen,
6 => Self::OpenInventory,
_ => return Err(Error::other("")),
};
Ok(this)
}
}

View File

@@ -1,3 +1,7 @@
// Last verified for v2169
use std::io::{Error, Read};
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketRead};
@@ -5,16 +9,32 @@ use crate::{codec::var_int::VarInt, serial::PacketRead};
#[derive(PacketRead)]
#[packet(312)]
pub struct SLoadingScreen {
// https://mojang.github.io/bedrock-protocol-docs/html/ServerboundLoadingScreenPacket.html
// Loading Screen Packet Type
// 0: Inavil, 1: Start, 2: End
status: VarInt,
_id: Option<u32>,
loading_screen_packet_type: LoadingScreenPacketType,
_loading_screen_id: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum LoadingScreenPacketType {
StartLoadingScreen = 0,
EndLoadingScreen = 1,
}
impl PacketRead for LoadingScreenPacketType {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
match VarInt::read(reader)?.0 {
0 => Ok(Self::StartLoadingScreen),
1 => Ok(Self::EndLoadingScreen),
val => Err(Error::other(format!(
"Invalid LoadingScreenPacketType: {val}"
))),
}
}
}
impl SLoadingScreen {
#[must_use]
pub const fn is_loading_done(&self) -> bool {
self.status.0 == 2
pub fn is_loading_done(&self) -> bool {
self.loading_screen_packet_type == LoadingScreenPacketType::EndLoadingScreen
}
}

View File

@@ -1,36 +1,19 @@
// Last verified for v2169
use crate::{
bedrock::network_item::NetworkItemStackDescriptor, codec::var_ulong::VarULong,
serial::PacketRead,
};
use pumpkin_macros::packet;
use std::io::{Error, Read};
#[derive(Debug)]
#[derive(Debug, PacketRead)]
#[packet(31)]
pub struct SMobEquipment {
pub entity_runtime_id: VarULong,
pub item: NetworkItemStackDescriptor,
pub inventory_slot: u8,
pub hotbar_slot: u8,
pub window_id: u8,
}
impl PacketRead for SMobEquipment {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let entity_runtime_id = VarULong::read(reader)?;
let item = NetworkItemStackDescriptor::read(reader)?;
let inventory_slot = u8::read(reader)?;
let hotbar_slot = u8::read(reader)?;
let window_id = u8::read(reader)?;
Ok(Self {
entity_runtime_id,
item,
inventory_slot,
hotbar_slot,
window_id,
})
}
pub slot: u8,
pub selected_slot: u8,
pub container_id: u8,
}
#[cfg(test)]
@@ -54,9 +37,9 @@ mod tests {
assert_eq!(packet.entity_runtime_id.0, 42);
assert_eq!(packet.item.id, 0);
assert_eq!(packet.inventory_slot, 3);
assert_eq!(packet.hotbar_slot, 4);
assert_eq!(packet.window_id, 5);
assert_eq!(packet.slot, 3);
assert_eq!(packet.selected_slot, 4);
assert_eq!(packet.container_id, 5);
assert_eq!(reader.position(), reader.get_ref().len() as u64);
}
}

View File

@@ -7,7 +7,7 @@ pub mod command_request;
pub mod container_close;
pub mod emote;
pub mod emote_list;
pub mod interaction;
pub mod interact;
pub mod inventory_transaction;
pub mod item_stack_request;
pub mod loading_screen;
@@ -21,7 +21,7 @@ pub mod player_hotbar;
pub mod request_ability;
pub mod request_chunk_radius;
pub mod request_network_settings;
pub mod resource_pack_response;
pub mod resource_pack_client_response;
pub mod respawn;
pub mod set_local_player_as_initialized;
pub mod set_player_inventory_options;
@@ -36,7 +36,7 @@ pub use command_request::*;
pub use container_close::*;
pub use emote::*;
pub use emote_list::*;
pub use interaction::{Action as InteractAction, SInteraction};
pub use interact::{Action as InteractAction, SInteract};
pub use inventory_transaction::*;
pub use item_stack_request::*;
pub use loading_screen::*;
@@ -44,13 +44,13 @@ pub use login::*;
pub use mob_equipment::*;
pub use modal_form_response::*;
pub use packet_violation_warning::*;
pub use player_action::{Action as PlayerActionType, SPlayerAction};
pub use player_action::{PlayerActionType, SPlayerAction};
pub use player_auth_input::*;
pub use player_hotbar::*;
pub use request_ability::*;
pub use request_chunk_radius::*;
pub use request_network_settings::*;
pub use resource_pack_response::*;
pub use resource_pack_client_response::*;
pub use respawn::*;
pub use set_local_player_as_initialized::*;
pub use set_player_inventory_options::*;

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use crate::codec::var_uint::VarUInt;
use crate::serial::{PacketRead, PacketReadSlice};
use pumpkin_macros::packet;
@@ -7,6 +9,8 @@ use std::borrow::Cow;
#[packet(101)]
pub struct SModalFormResponse<'a> {
pub form_id: VarUInt,
pub form_data: Option<Cow<'a, str>>,
pub cancel_reason: Option<u8>,
pub json_response: Option<Cow<'a, str>>,
// TODO: enum ModalFormCancelReason
pub form_cancel_reason: Option<u8>,
}

View File

@@ -1,25 +1,16 @@
use std::io::{Error, Read};
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketRead};
#[derive(Debug)]
#[derive(Debug, PacketRead)]
#[packet(156)]
pub struct SPacketViolationWarning {
// TODO: enum PacketViolationType
pub violation_type: VarInt,
pub severity: VarInt,
pub packet_id: VarInt,
pub context: String,
}
impl PacketRead for SPacketViolationWarning {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
Ok(Self {
violation_type: VarInt::read(reader)?,
severity: VarInt::read(reader)?,
packet_id: VarInt::read(reader)?,
context: String::read(reader)?,
})
}
// TODO: enum PacketViolationSeverity
pub violation_severity: VarInt,
pub violation_packet_id: VarInt,
pub violation_context: String,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use std::io::{Error, Read};
use pumpkin_macros::packet;
@@ -11,92 +13,92 @@ use crate::{
#[derive(Debug, PacketRead)]
#[packet(36)]
pub struct SPlayerAction {
pub runtime_id: VarULong,
pub action: Action,
pub block_pos: BlockPos,
pub player_runtime_id: VarULong,
pub action: PlayerActionType,
pub block_position: BlockPos,
pub result_pos: BlockPos,
pub face: VarInt,
}
#[derive(Debug)]
#[repr(i32)]
pub enum Action {
pub enum PlayerActionType {
Unknown = -1,
StartBreak = 0,
AbortBreak = 1,
StopBreak = 2,
GetUpdatedBlock = 3,
StartDestroyBlock,
AbortDestroyBlock,
StopDestroyBlock,
GetUpdatedBlock,
/// Seems to be not used, or atleast not send by client
DropItem = 4,
StartSleeping = 5,
StopSleeping = 6,
Respawn = 7,
Jump = 8,
StartSprint = 9,
StopSprint = 10,
StartSneak = 11,
StopSneak = 12,
CreativePlayerDestroyBlock = 13,
DimensionChangeAck = 14,
StartGlide = 15,
StopGlide = 16,
BuildDenied = 17,
CrackBreak = 18,
ChangeSkin = 19,
SetEnchantmentSeed = 20,
Swimming = 21,
StopSwimming = 22,
StartSpinAttack = 23,
StopSpinAttack = 24,
InteractBlock = 25,
PredictDestroyBlock = 26,
ContinueDestroyBlock = 27,
StartItemUseOn = 28,
StopItemUseOn = 29,
HandledTeleport = 30,
MissedSwing = 31,
StartCrawling = 32,
StopCrawling = 33,
StartFlying = 34,
StopFlying = 35,
ClientAckServerData = 36,
StartUsingItem = 37,
InternalUpdate = 38,
Count = 39,
DropItem,
StartSleeping,
StopSleeping,
Respawn,
StartJump,
StartSprinting,
StopSprinting,
StartSneaking,
StopSneaking,
CreativeDestroyBlock,
ChangeDimensionAck,
StartGliding,
StopGliding,
DenyDestroyBlock,
CrackBlock,
ChangeSkin,
UpdatedEnchantingSeed,
StartSwimming,
StopSwimming,
StartSpinAttack,
StopSpinAttack,
InteractWithBlock,
PredictDestroyBlock,
ContinueDestroyBlock,
StartItemUseOn,
StopItemUseOn,
HandledTeleport,
MissedSwing,
StartCrawling,
StopCrawling,
StartFlying,
StopFlying,
ClientAckServerData,
StartUsingItem,
InternalUpdate,
Count,
}
impl TryFrom<i32> for Action {
impl TryFrom<i32> for PlayerActionType {
type Error = String;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
-1 => Ok(Self::Unknown),
0 => Ok(Self::StartBreak),
1 => Ok(Self::AbortBreak),
2 => Ok(Self::StopBreak),
0 => Ok(Self::StartDestroyBlock),
1 => Ok(Self::AbortDestroyBlock),
2 => Ok(Self::StopDestroyBlock),
3 => Ok(Self::GetUpdatedBlock),
4 => Ok(Self::DropItem),
5 => Ok(Self::StartSleeping),
6 => Ok(Self::StopSleeping),
7 => Ok(Self::Respawn),
8 => Ok(Self::Jump),
9 => Ok(Self::StartSprint),
10 => Ok(Self::StopSprint),
11 => Ok(Self::StartSneak),
12 => Ok(Self::StopSneak),
13 => Ok(Self::CreativePlayerDestroyBlock),
14 => Ok(Self::DimensionChangeAck),
15 => Ok(Self::StartGlide),
16 => Ok(Self::StopGlide),
17 => Ok(Self::BuildDenied),
18 => Ok(Self::CrackBreak),
8 => Ok(Self::StartJump),
9 => Ok(Self::StartSprinting),
10 => Ok(Self::StopSprinting),
11 => Ok(Self::StartSneaking),
12 => Ok(Self::StopSneaking),
13 => Ok(Self::CreativeDestroyBlock),
14 => Ok(Self::ChangeDimensionAck),
15 => Ok(Self::StartGliding),
16 => Ok(Self::StopGliding),
17 => Ok(Self::DenyDestroyBlock),
18 => Ok(Self::CrackBlock),
19 => Ok(Self::ChangeSkin),
20 => Ok(Self::SetEnchantmentSeed),
21 => Ok(Self::Swimming),
20 => Ok(Self::UpdatedEnchantingSeed),
21 => Ok(Self::StartSwimming),
22 => Ok(Self::StopSwimming),
23 => Ok(Self::StartSpinAttack),
24 => Ok(Self::StopSpinAttack),
25 => Ok(Self::InteractBlock),
25 => Ok(Self::InteractWithBlock),
26 => Ok(Self::PredictDestroyBlock),
27 => Ok(Self::ContinueDestroyBlock),
28 => Ok(Self::StartItemUseOn),
@@ -116,7 +118,7 @@ impl TryFrom<i32> for Action {
}
}
impl PacketRead for Action {
impl PacketRead for PlayerActionType {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let action = VarInt::read(reader)?;

View File

@@ -1,15 +1,14 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_uint::VarUInt, serial::PacketRead};
/// Sent by the Bedrock client when the player changes their active hotbar slot.
///
/// Packet ID: `48`
/// Ref: <https://mojang.github.io/bedrock-protocol-docs/html/PlayerHotbarPacket.html>
#[derive(PacketRead)]
#[packet(48)]
pub struct SPlayerHotbar {
pub selected_slot: VarUInt,
pub container_id: u8,
pub select_slot: bool,
pub should_select_slot: bool,
}

View File

@@ -1,3 +1,5 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketRead};
@@ -5,7 +7,6 @@ use crate::{codec::var_int::VarInt, serial::PacketRead};
#[derive(PacketRead, Debug)]
#[packet(69)]
pub struct SRequestChunkRadius {
// https://mojang.github.io/bedrock-protocol-docs/html/RequestChunkRadiusPacket.html
pub chunk_radius: VarInt,
pub max_radius: u8,
pub max_chunk_radius: u8,
}

View File

@@ -1,10 +1,12 @@
// Last verified for v2169
use pumpkin_macros::packet;
use crate::serial::PacketRead;
#[derive(PacketRead)]
#[packet(0xC1)]
#[packet(193)]
pub struct SRequestNetworkSettings {
#[serial(big_endian)]
pub protocol_version: i32,
pub client_network_version: i32,
}

View File

@@ -4,13 +4,13 @@ use crate::{codec::var_uint::VarUInt, serial::PacketRead};
use pumpkin_macros::packet;
#[packet(8)]
pub struct SResourcePackResponse {
pub struct SResourcePackClientResponse {
pub response: u8,
pub download_size: u16,
pub pack_ids: Vec<String>,
}
impl PacketRead for SResourcePackResponse {
impl PacketRead for SResourcePackClientResponse {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let encoded_status = VarUInt::read(reader)?.0;
let response = encoded_status
@@ -47,7 +47,7 @@ impl PacketRead for SResourcePackResponse {
}
}
impl SResourcePackResponse {
impl SResourcePackClientResponse {
pub const STATUS_REFUSED: u8 = 1;
pub const STATUS_SEND_PACKS: u8 = 2;
pub const STATUS_HAVE_ALL_PACKS: u8 = 3;

View File

@@ -1,12 +1,69 @@
// Last verified for v2169
use std::io::{Error, ErrorKind, Read, Write};
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use crate::{bedrock::respawn::RespawnState, codec::var_ulong::VarULong, serial::PacketRead};
use crate::{
codec::var_ulong::VarULong,
serial::{PacketRead, PacketWrite},
};
#[derive(PacketRead)]
#[derive(PacketRead, PacketWrite)]
#[packet(45)]
pub struct SRespawn {
pub position: Vector3<f32>,
pub state: RespawnState,
pub player_runtime_id: VarULong,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum RespawnState {
SearchingForSpawn,
ReadyToSpawn,
ClientReadyToSpawn,
}
impl PacketRead for RespawnState {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
match u8::read(reader)? {
0 => Ok(Self::SearchingForSpawn),
1 => Ok(Self::ReadyToSpawn),
2 => Ok(Self::ClientReadyToSpawn),
state => Err(Error::new(
ErrorKind::InvalidData,
format!("invalid Bedrock respawn state {state}"),
)),
}
}
}
impl PacketWrite for RespawnState {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
(*self as u8).write(writer)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::serial::PacketRead;
#[test]
fn respawn_packet_roundtrip() {
let packet = SRespawn {
position: Vector3::new(1.5, 64.0, -2.25),
state: RespawnState::ReadyToSpawn,
player_runtime_id: VarULong(42),
};
let mut encoded = Vec::new();
packet.write(&mut encoded).unwrap();
let decoded = SRespawn::read(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded.position, packet.position);
assert_eq!(decoded.state, packet.state);
assert_eq!(decoded.player_runtime_id.0, packet.player_runtime_id.0);
}
}

View File

@@ -1,8 +1,10 @@
// Last verified for v2169
use crate::{codec::var_ulong::VarULong, serial::PacketRead};
use pumpkin_macros::packet;
#[derive(PacketRead)]
#[packet(113)]
pub struct SSetLocalPlayerAsInitialized {
pub runtime_entity_id: VarULong,
pub player_id: VarULong,
}

View File

@@ -1,12 +1,20 @@
// Last verified for v2169
use crate::{codec::var_int::VarInt, serial::PacketRead};
use pumpkin_macros::packet;
#[derive(PacketRead)]
#[packet(307)]
pub struct SSetPlayerInventoryOptions {
// TODO: enum InventoryLeftTabIndex
pub left_inventory_tab: VarInt,
// TODO: enum InventoryRightTabIndex
pub right_inventory_tab: VarInt,
pub filtering: bool,
pub inventory_layout: VarInt,
pub crafting_layout: VarInt,
// TODO: enum InventoryLayout
pub layout_inv: VarInt,
// TODO: enum InventoryLayout
pub layout_craft: VarInt,
}

View File

@@ -5,10 +5,7 @@ use std::{
};
use pumpkin_nbt::{Nbt, NbtCompound};
use pumpkin_util::{
GameMode,
math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
};
use pumpkin_util::math::{position::BlockPos, vector2::Vector2, vector3::Vector3};
use crate::{
codec::{var_int::VarInt, var_uint::VarUInt},
@@ -190,19 +187,6 @@ impl PacketWrite for SocketAddr {
}
}
impl PacketWrite for GameMode {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarInt(match self {
Self::Survival => 0,
Self::Creative => 1,
Self::Adventure => 2,
// I have no idea why
Self::Spectator => 6,
})
.write(writer)
}
}
impl PacketWrite for Cow<'_, str> {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.as_ref().write(writer)

View File

@@ -1,4 +1,5 @@
use pumpkin_protocol::{
bedrock::client::CommandPermissionLevel,
codec::var_int::VarInt,
java::client::play::{
ArgumentType, CCommands, ProtoNode, ProtoNodeType, StringProtoArgBehavior,
@@ -15,8 +16,7 @@ use crate::command::node::{
use crate::entity::player::Player;
use crate::server::Server;
use pumpkin_protocol::bedrock::client::available_commands::{
CAvailableCommands, Command, CommandEnum, CommandOverload, CommandParameter, arg_flags,
arg_types, command_permissions,
CAvailableCommands, CommandData, EnumData, OverloadData, ParamData, arg_flags, arg_types,
};
use pumpkin_protocol::java::client::play::SuggestionProviders;
@@ -315,7 +315,7 @@ fn nodes_to_proto_node_builders<'a>(
struct BuilderContext<'a> {
enum_values: &'a mut Vec<String>,
enums: &'a mut Vec<CommandEnum>,
enums: &'a mut Vec<EnumData>,
}
#[expect(clippy::too_many_lines)]
@@ -327,8 +327,8 @@ pub async fn send_bedrock_commands_packet(
let cmd_src = super::CommandSender::Player(player.clone());
let mut enum_values: Vec<String> = Vec::new();
let mut enums: Vec<CommandEnum> = Vec::new();
let mut commands: Vec<Command> = Vec::new();
let mut enums: Vec<EnumData> = Vec::new();
let mut commands: Vec<CommandData> = Vec::new();
let fallback_dispatcher = &dispatcher.fallback_dispatcher;
for key in fallback_dispatcher.commands.keys() {
@@ -359,13 +359,13 @@ pub async fn send_bedrock_commands_packet(
let overloads = build_overloads_from_nodes(&tree.nodes, &tree.children, &mut ctx);
commands.push(Command {
commands.push(CommandData {
name: key.clone(),
description: String::new(),
flags: 0,
permission: command_permissions::ANY.to_string(),
aliases_enum_index: -1,
chained_subcommand_offsets: Vec::new(),
permission_level: CommandPermissionLevel::Any.into(),
alias_enum: -1,
command_data_chained_subcommand_indexes: Vec::new(),
overloads,
});
}
@@ -419,13 +419,13 @@ pub async fn send_bedrock_commands_packet(
let overloads =
build_overloads_from_attached_nodes(&tree_nodes, &child_ids, is_executable, &mut ctx);
commands.push(Command {
commands.push(CommandData {
name,
description: String::new(),
flags: 0,
permission: command_permissions::ANY.to_string(),
aliases_enum_index: -1,
chained_subcommand_offsets: Vec::new(),
permission_level: CommandPermissionLevel::Any.into(),
alias_enum: -1,
command_data_chained_subcommand_indexes: Vec::new(),
overloads,
});
}
@@ -433,9 +433,9 @@ pub async fn send_bedrock_commands_packet(
let packet = CAvailableCommands {
enum_values,
chained_subcommand_values: Vec::new(),
suffixes: Vec::new(),
chained_subcommands: Vec::new(),
enums,
post_fixes: Vec::new(),
chained_subcommand_data: Vec::new(),
enum_data: enums,
commands,
soft_enums: Vec::new(),
constraints: Vec::new(),
@@ -450,13 +450,13 @@ fn build_overloads_from_nodes(
nodes: &[Node],
children: &[usize],
ctx: &mut BuilderContext,
) -> Vec<CommandOverload> {
) -> Vec<OverloadData> {
let mut overloads = Vec::new();
collect_overloads_from_nodes(nodes, children, &mut Vec::new(), &mut overloads, ctx);
if overloads.is_empty() {
overloads.push(CommandOverload {
chaining: false,
parameters: Vec::new(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: Vec::new(),
});
}
overloads
@@ -465,8 +465,8 @@ fn build_overloads_from_nodes(
fn collect_overloads_from_nodes(
nodes: &[Node],
children: &[usize],
current_params: &mut Vec<CommandParameter>,
overloads: &mut Vec<CommandOverload>,
current_params: &mut Vec<ParamData>,
overloads: &mut Vec<OverloadData>,
ctx: &mut BuilderContext,
) {
let mut has_executable = false;
@@ -485,22 +485,22 @@ fn collect_overloads_from_nodes(
std::slice::from_ref(string),
);
let mut params = current_params.clone();
params.push(CommandParameter {
params.push(ParamData {
name: string.clone(),
type_info: arg_flags::ARG_FLAG_VALID
parse_symbol: arg_flags::ARG_FLAG_VALID
| arg_flags::ARG_FLAG_ENUM
| enum_idx as u32,
optional: false,
is_optional: false,
options: 0,
});
collect_overloads_from_nodes(nodes, &node.children, &mut params, overloads, ctx);
}
NodeType::Argument { name, consumer, .. } => {
let mut params = current_params.clone();
params.push(CommandParameter {
params.push(ParamData {
name: name.clone(),
type_info: bedrock_param_type(&consumer.get_client_side_parser()),
optional: false,
parse_symbol: bedrock_param_type(&consumer.get_client_side_parser()),
is_optional: false,
options: 0,
});
collect_overloads_from_nodes(nodes, &node.children, &mut params, overloads, ctx);
@@ -512,9 +512,9 @@ fn collect_overloads_from_nodes(
}
if has_executable {
overloads.push(CommandOverload {
chaining: false,
parameters: current_params.clone(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: current_params.clone(),
});
}
}
@@ -524,19 +524,19 @@ fn build_overloads_from_attached_nodes(
child_ids: &[NodeId],
is_root_executable: bool,
ctx: &mut BuilderContext,
) -> Vec<CommandOverload> {
) -> Vec<OverloadData> {
let mut overloads = Vec::new();
if is_root_executable {
overloads.push(CommandOverload {
chaining: false,
parameters: Vec::new(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: Vec::new(),
});
}
collect_overloads_from_attached(tree, child_ids, &Vec::new(), &mut overloads, ctx);
if overloads.is_empty() {
overloads.push(CommandOverload {
chaining: false,
parameters: Vec::new(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: Vec::new(),
});
}
overloads
@@ -545,8 +545,8 @@ fn build_overloads_from_attached_nodes(
fn collect_overloads_from_attached(
tree: &[&AttachedNode],
child_ids: &[NodeId],
current_params: &[CommandParameter],
overloads: &mut Vec<CommandOverload>,
current_params: &[ParamData],
overloads: &mut Vec<OverloadData>,
ctx: &mut BuilderContext,
) {
for &child_id in child_ids {
@@ -563,19 +563,19 @@ fn collect_overloads_from_attached(
&[name.to_string()],
);
let mut params = current_params.to_vec();
params.push(CommandParameter {
params.push(ParamData {
name: name.to_string(),
type_info: arg_flags::ARG_FLAG_VALID
parse_symbol: arg_flags::ARG_FLAG_VALID
| arg_flags::ARG_FLAG_ENUM
| enum_idx as u32,
optional: false,
is_optional: false,
options: 0,
});
let grandchild_ids: Vec<NodeId> = node.children_ref().values().copied().collect();
if lit.owned.command.is_some() {
overloads.push(CommandOverload {
chaining: false,
parameters: params.clone(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: params.clone(),
});
}
collect_overloads_from_attached(tree, &grandchild_ids, &params, overloads, ctx);
@@ -589,19 +589,19 @@ fn collect_overloads_from_attached(
&[name.to_string()],
);
let mut params = current_params.to_vec();
params.push(CommandParameter {
params.push(ParamData {
name: name.to_string(),
type_info: arg_flags::ARG_FLAG_VALID
parse_symbol: arg_flags::ARG_FLAG_VALID
| arg_flags::ARG_FLAG_ENUM
| enum_idx as u32,
optional: false,
is_optional: false,
options: 0,
});
let grandchild_ids: Vec<NodeId> = node.children_ref().values().copied().collect();
if cmd.owned.command.is_some() {
overloads.push(CommandOverload {
chaining: false,
parameters: params.clone(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: params.clone(),
});
}
collect_overloads_from_attached(tree, &grandchild_ids, &params, overloads, ctx);
@@ -609,17 +609,17 @@ fn collect_overloads_from_attached(
AttachedNode::Argument(arg) => {
let parser = arg.meta.argument_type.client_side_parser();
let mut params = current_params.to_vec();
params.push(CommandParameter {
params.push(ParamData {
name: arg.meta.name.to_string(),
type_info: bedrock_param_type(&parser),
optional: false,
parse_symbol: bedrock_param_type(&parser),
is_optional: false,
options: 0,
});
let grandchild_ids: Vec<NodeId> = node.children_ref().values().copied().collect();
if arg.owned.command.is_some() {
overloads.push(CommandOverload {
chaining: false,
parameters: params.clone(),
overloads.push(OverloadData {
is_chaining: false,
parameter_data: params.clone(),
});
}
collect_overloads_from_attached(tree, &grandchild_ids, &params, overloads, ctx);
@@ -641,7 +641,7 @@ fn ensure_enum_value(enum_values: &mut Vec<String>, value: &str) -> u32 {
}
fn ensure_command_enum(
enums: &mut Vec<CommandEnum>,
enums: &mut Vec<EnumData>,
enum_values: &mut Vec<String>,
name: &str,
values: &[String],
@@ -650,14 +650,12 @@ fn ensure_command_enum(
return pos;
}
let value_indices: Vec<u32> = values
.iter()
.map(|val| ensure_enum_value(enum_values, val))
.collect();
enums.push(CommandEnum {
enums.push(EnumData {
name: name.to_string(),
value_indices,
values: values
.iter()
.map(|val| ensure_enum_value(enum_values, val))
.collect(),
});
enums.len() - 1

View File

@@ -94,10 +94,10 @@ pub async fn send_attribute_updates_for_living(
attributes: Vec<Attributes>,
) {
use pumpkin_protocol::bedrock::client::update_attributes::{
Attribute as BeAttribute, CUpdateAttributes as BePacket,
AttributeData as BeAttribute, CUpdateAttributes as BePacket,
};
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::codec::{var_uint::VarUInt, var_ulong::VarULong};
use pumpkin_protocol::codec::var_ulong::VarULong;
use pumpkin_protocol::java::client::play::AttributeModifier as JeAttrMod;
use pumpkin_protocol::java::client::play::CUpdateAttributes as JePacket;
use pumpkin_protocol::java::client::play::Property as JeProperty;
@@ -157,7 +157,7 @@ pub async fn send_attribute_updates_for_living(
name,
// Bedrock receives the already-computed effective value above. Do not advertise
// modifier entries until their payload is encoded as well.
modifiers_list_size: VarUInt(0),
modifiers: Vec::new(),
};
be_attributes.push(be_attribute);
@@ -167,9 +167,9 @@ pub async fn send_attribute_updates_for_living(
let runtime_id = living.entity.entity_id as u64;
let be_packet = BePacket {
runtime_id: VarULong(runtime_id),
attributes: be_attributes,
player_tick: VarULong(0),
target_runtime_id: VarULong(runtime_id),
attribute_list: be_attributes,
tick: VarULong(0),
};
living

View File

@@ -166,7 +166,7 @@ impl BreathManager {
let air = self.air_supply.load(Ordering::Relaxed).clamp(0, MAX_AIR);
let mut bedrock_meta =
pumpkin_protocol::bedrock::client::set_actor_data::EntityMetadata::new();
pumpkin_protocol::bedrock::client::set_actor_data::SyncedActorDataList::new();
bedrock_meta.set(
pumpkin_protocol::bedrock::client::set_actor_data::entity_data_key::AIR_SUPPLY,
pumpkin_protocol::bedrock::client::set_actor_data::MetadataValue::Short(air as i16),

View File

@@ -638,13 +638,13 @@ impl EntityBase for ItemEntity {
let runtime_id = entity.entity_id as u64;
let item_stack = self.item_stack.lock().await;
let packet = CAddItemActor {
entity_unique_id: VarLong(runtime_id as i64),
entity_runtime_id: VarULong(runtime_id),
target_actor_id: VarLong(runtime_id as i64),
target_runtime_id: VarULong(runtime_id),
item: ItemStackWrapper::from(&*item_stack),
position: entity.pos.load().to_f32_lossy(),
velocity: entity.velocity.load().to_f32_lossy(),
metadata: entity.bedrock_metadata(),
from_fishing: false,
entity_data: entity.bedrock_metadata(),
is_from_fishing: false,
};
if let Ok(data) = client.serialize_packet(&packet) {
client.send_game_packet(data).await;

View File

@@ -7,7 +7,7 @@ use pumpkin_inventory::build_equipment_slots;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::InventoryPlayer;
use pumpkin_protocol::bedrock::client::take_item_actor::CTakeItemActor;
use pumpkin_protocol::bedrock::server::actor_event::{ActorEventType, SActorEvent};
use pumpkin_protocol::bedrock::server::actor_event::{ActorEventID, SActorEvent};
use pumpkin_protocol::codec::var_ulong::VarULong;
use pumpkin_util::GameMode;
use pumpkin_util::Hand;
@@ -249,15 +249,16 @@ impl LivingEntity {
} else {
0
};
let be_packet = pumpkin_protocol::bedrock::client::CMobEquipment::new(
self.entity_id() as u64,
pumpkin_protocol::bedrock::network_item::NetworkItemStackDescriptor::from(
let be_packet = pumpkin_protocol::bedrock::client::CMobEquipment {
target_runtime_id: (self.entity_id() as u64).into(),
item: pumpkin_protocol::bedrock::network_item::NetworkItemStackDescriptor::from(
stack,
),
0,
0,
window_id,
);
slot: 0,
selected_slot: 0,
container_id: window_id,
};
self.entity
.world
.load()
@@ -305,10 +306,10 @@ impl LivingEntity {
self.entity.entity_id.into(),
VarInt(stack_amount as i32),
),
&CTakeItemActor::new(
VarULong(item.entity_id as u64),
VarULong(self.entity.entity_id as u64),
),
&CTakeItemActor {
item_runtime_id: VarULong(item.entity_id as u64),
actor_runtime_id: VarULong(self.entity.entity_id as u64),
},
);
}
@@ -343,10 +344,11 @@ impl LivingEntity {
.fetch_and(!mask, Ordering::Relaxed);
}
let mut meta = pumpkin_protocol::bedrock::client::set_actor_data::EntityMetadata::new();
let mut meta =
pumpkin_protocol::bedrock::client::set_actor_data::SyncedActorDataList::new();
meta.set(
pumpkin_protocol::bedrock::client::set_actor_data::entity_data_key::FLAGS,
pumpkin_protocol::bedrock::client::set_actor_data::MetadataValue::Long(
pumpkin_protocol::bedrock::client::set_actor_data::MetadataValue::Int64(
self.entity.bedrock_flags.load(Ordering::Relaxed),
),
);
@@ -712,16 +714,16 @@ impl LivingEntity {
flag,
);
let be_packet = pumpkin_protocol::bedrock::client::CMobEffect::new(
VarULong(self.entity.entity_id as u64),
pumpkin_protocol::bedrock::client::CMobEffect::EVENT_ADD,
VarInt(effect.effect_type.to_bedrock_id()),
VarInt(i32::from(effect.amplifier)),
effect.show_particles,
VarInt(effect.duration),
VarULong(0),
effect.ambient,
);
let be_packet = pumpkin_protocol::bedrock::client::CMobEffect {
target_runtime_id: VarULong(self.entity.entity_id as u64),
event_id: pumpkin_protocol::bedrock::client::CMobEffect::EVENT_ADD,
effect_id: VarInt(effect.effect_type.to_bedrock_id()),
effect_amplifier: VarInt(i32::from(effect.amplifier)),
show_particles: effect.show_particles,
effect_duration_ticks: VarInt(effect.duration),
tick: VarULong(0),
ambient: effect.ambient,
};
let chunk_pos = self.entity.chunk_pos.load();
self.entity
@@ -964,7 +966,7 @@ impl LivingEntity {
);
let be_packet = pumpkin_protocol::bedrock::server::animate::SAnimate {
action: pumpkin_protocol::bedrock::server::animate::AnimateAction::SwingArm,
runtime_entity_id: pumpkin_protocol::codec::var_ulong::VarULong(entity_id as u64),
target_actor_runtime_id: pumpkin_protocol::codec::var_ulong::VarULong(entity_id as u64),
data: 0.0,
swing_source: None,
};
@@ -1542,11 +1544,7 @@ impl LivingEntity {
self.update_death_stats(&*dyn_self, cause).await;
// Plays the death sound
world.send_entity_status(
&self.entity,
EntityStatus::Death,
Some(ActorEventType::Death),
);
world.send_entity_status(&self.entity, EntityStatus::Death, Some(ActorEventID::Death));
let looting_level;
let tool = if let Some(cause_ent) = cause {
if let Some(player) = cause_ent
@@ -1873,7 +1871,7 @@ impl LivingEntity {
self.entity.world.load().send_entity_status(
&self.entity,
EntityStatus::ProtectedFromDeath,
Some(ActorEventType::InstantDeath),
Some(ActorEventID::InstantDeath),
);
// Set Absorption, Regeneration, and Fire Resistance effects
@@ -2501,9 +2499,9 @@ impl EntityBase for LivingEntity {
- self.entity.yaw.load()
});
let hurt_event = SActorEvent {
entity_runtime_id: VarULong(entity_id as u64),
event_type: ActorEventType::Hurt,
event_data: VarInt(0),
target_runtime_id: VarULong(entity_id as u64),
event_id: ActorEventID::Hurt,
data: VarInt(0),
fire_at_position: None,
};
world
@@ -2912,7 +2910,7 @@ impl EntityBase for LivingEntity {
self.entity.world.load().send_entity_status(
&self.entity,
EntityStatus::Death,
Some(ActorEventType::Death),
Some(ActorEventID::Death),
);
self.entity.remove().await;
}

View File

@@ -603,7 +603,7 @@ pub trait Mob: EntityBase + Send + Sync {
&self,
) -> EntityBaseFuture<
'_,
Option<pumpkin_protocol::bedrock::client::set_actor_data::EntityMetadata>,
Option<pumpkin_protocol::bedrock::client::set_actor_data::SyncedActorDataList>,
> {
Box::pin(async { None })
}

View File

@@ -46,7 +46,7 @@ use pumpkin_protocol::{
},
move_player::CMovePlayer,
set_actor_data::{
CSetActorData, EntityMetadata, MetadataValue, PropertySyncData, entity_data_flag,
CSetActorData, MetadataValue, PropertySyncData, SyncedActorDataList, entity_data_flag,
entity_data_key,
},
},
@@ -221,7 +221,7 @@ pub trait EntityBase: Send + Sync + std::any::Any {
let is_baby = entity.age.load(Ordering::Relaxed) < 0;
if is_baby {
let mut bedrock_meta = EntityMetadata::new();
let mut bedrock_meta = SyncedActorDataList::new();
bedrock_meta.set_flag(entity_data_key::FLAGS, entity_data_flag::BABY as u8, true);
entity.send_meta_data(
&[Metadata::new(tracked_data::ageable_mob::DATA_BABY_ID, true)],
@@ -344,24 +344,23 @@ pub trait EntityBase: Send + Sync + std::any::Any {
{
metadata.0.extend(mob_metadata.0);
}
let packet = CAddActor::new(
VarLong(runtime_id as i64),
VarULong(runtime_id),
identifier.to_string(),
entity.pos.load().to_f32_lossy(),
entity.velocity.load().to_f32_lossy(),
entity.pitch.load(),
entity.yaw.load(),
entity.head_yaw.load(),
entity.body_yaw.load(),
Vec::new(),
metadata,
PropertySyncData {
int_properties: std::collections::HashMap::new(),
float_properties: std::collections::HashMap::new(),
let packet = CAddActor {
target_actor_id: VarLong(runtime_id as i64),
target_runtime_id: VarULong(runtime_id),
actor_type: identifier.to_string(),
position: entity.pos.load().to_f32_lossy(),
velocity: entity.velocity.load().to_f32_lossy(),
rotation: Vector2::new(entity.pitch.load(), entity.yaw.load()),
y_head_rotation: entity.head_yaw.load(),
y_body_rotation: entity.body_yaw.load(),
attributes_list: Vec::new(),
actor_data: metadata,
synced_properties: PropertySyncData {
int_entries_list: std::collections::HashMap::new(),
float_entries_list: std::collections::HashMap::new(),
},
Vec::new(),
);
actor_links: Vec::new(),
};
if let Ok(data) = client.serialize_packet(&packet) {
client.send_game_packet(data).await;
}
@@ -1101,7 +1100,7 @@ impl Entity {
self.world.store(world);
}
pub fn bedrock_metadata(&self) -> EntityMetadata {
pub fn bedrock_metadata(&self) -> SyncedActorDataList {
if self.bedrock_flags.load(Ordering::Relaxed) == 0 {
self.bedrock_flags.fetch_or(
(1i64 << entity_data_flag::HAS_GRAVITY)
@@ -1112,7 +1111,7 @@ impl Entity {
);
}
let mut metadata = EntityMetadata::new();
let mut metadata = SyncedActorDataList::new();
metadata.set(
entity_data_key::WIDTH,
MetadataValue::Float(self.entity_type.dimension[0]),
@@ -1124,11 +1123,11 @@ impl Entity {
metadata.set(entity_data_key::SCALE, MetadataValue::Float(1.0));
metadata.set(
entity_data_key::FLAGS,
MetadataValue::Long(self.bedrock_flags.load(Ordering::Relaxed)),
MetadataValue::Int64(self.bedrock_flags.load(Ordering::Relaxed)),
);
metadata.set(
entity_data_key::FLAGS_TWO,
MetadataValue::Long(self.bedrock_flags_two.load(Ordering::Relaxed)),
MetadataValue::Int64(self.bedrock_flags_two.load(Ordering::Relaxed)),
);
if let Some(name) = &**self.custom_name.load() {
@@ -1178,7 +1177,7 @@ impl Entity {
/// Sets a custom name for the entity, typically used with nametags
pub fn set_custom_name(&self, name: TextComponent) {
self.custom_name.store(Arc::new(Some(name.clone())));
let mut bedrock_meta = EntityMetadata::new();
let mut bedrock_meta = SyncedActorDataList::new();
bedrock_meta.set(
entity_data_key::NAME,
MetadataValue::String(name.clone().get_text()),
@@ -1205,7 +1204,7 @@ impl Entity {
pub fn set_custom_name_visible(&self, visible: bool) {
self.custom_name_visible.store(visible, Ordering::Relaxed);
let mut bedrock_meta = EntityMetadata::new();
let mut bedrock_meta = SyncedActorDataList::new();
if let Some(name) = &**self.custom_name.load() {
bedrock_meta.set(
entity_data_key::NAME,
@@ -1264,11 +1263,11 @@ impl Entity {
self.world.load().broadcast_to_chunk_editioned_sync(
chunk_pos,
&CEntityVelocity::new(self.entity_id.into(), velocity),
&CSetActorMotion::new(
VarULong(self.entity_id as u64),
Vector3::new(velocity.x as f32, velocity.y as f32, velocity.z as f32),
VarULong(0),
),
&CSetActorMotion {
target_runtime_id: VarULong(self.entity_id as u64),
motion: Vector3::new(velocity.x as f32, velocity.y as f32, velocity.z as f32),
tick: VarULong(0),
},
);
}
@@ -2639,7 +2638,7 @@ impl Entity {
// Only update and send metadata if the value changed
if new_frozen_ticks != old_frozen_ticks {
self.frozen_ticks.store(new_frozen_ticks, Ordering::Relaxed);
let mut bedrock_meta = EntityMetadata::new();
let mut bedrock_meta = SyncedActorDataList::new();
bedrock_meta.set(
entity_data_key::FREEZING_EFFECT_STRENGTH,
MetadataValue::Float(new_frozen_ticks as f32),
@@ -2971,21 +2970,21 @@ impl Entity {
let world = self.world.load();
let chunk_pos = self.chunk_pos.load();
let mut metadata = EntityMetadata(std::collections::HashMap::new());
let mut metadata = SyncedActorDataList(std::collections::HashMap::new());
metadata.set(
entity_data_key::FLAGS,
MetadataValue::Long(self.bedrock_flags.load(Ordering::Relaxed)),
MetadataValue::Int64(self.bedrock_flags.load(Ordering::Relaxed)),
);
metadata.set(
entity_data_key::FLAGS_TWO,
MetadataValue::Long(self.bedrock_flags_two.load(Ordering::Relaxed)),
MetadataValue::Int64(self.bedrock_flags_two.load(Ordering::Relaxed)),
);
let packet = CSetActorData {
actor_runtime_id: VarULong(self.entity_id as u64),
metadata,
target_runtime_id: VarULong(self.entity_id as u64),
actor_data: metadata,
synced_properties: PropertySyncData {
int_properties: std::collections::HashMap::new(),
float_properties: std::collections::HashMap::new(),
int_entries_list: std::collections::HashMap::new(),
float_entries_list: std::collections::HashMap::new(),
},
tick: VarULong(0),
};
@@ -3003,7 +3002,7 @@ impl Entity {
pub fn send_meta_data<T: MetadataSerializer>(
&self,
meta: &[Metadata<T>],
bedrock_meta: Option<&EntityMetadata>,
bedrock_meta: Option<&SyncedActorDataList>,
) {
let world = self.world.load();
let chunk_pos = self.chunk_pos.load();
@@ -3046,11 +3045,11 @@ impl Entity {
if let Some(bedrock_meta) = bedrock_meta {
let packet = CSetActorData {
actor_runtime_id: VarULong(self.entity_id as u64),
metadata: EntityMetadata(bedrock_meta.0.clone()),
target_runtime_id: VarULong(self.entity_id as u64),
actor_data: SyncedActorDataList(bedrock_meta.0.clone()),
synced_properties: PropertySyncData {
int_properties: std::collections::HashMap::new(),
float_properties: std::collections::HashMap::new(),
int_entries_list: std::collections::HashMap::new(),
float_entries_list: std::collections::HashMap::new(),
},
tick: VarULong(0),
};
@@ -3088,7 +3087,7 @@ impl Entity {
self.bounding_box.store(aabb);
self.entity_dimension.store(dimension);
let pose = pose as i32;
let mut bedrock_meta = EntityMetadata::new();
let mut bedrock_meta = SyncedActorDataList::new();
bedrock_meta.set(entity_data_key::POSE_INDEX, MetadataValue::Int(pose));
bedrock_meta.set(
entity_data_key::WIDTH,
@@ -3270,7 +3269,7 @@ impl Entity {
true,
);
let be_packet = pumpkin_protocol::bedrock::client::CSetActorLink {
link: pumpkin_protocol::bedrock::client::common::EntityLink {
link: pumpkin_protocol::bedrock::client::common::ActorLink {
ridden_unique_id: pumpkin_protocol::codec::var_long::VarLong(self.entity_id as i64),
rider_unique_id: pumpkin_protocol::codec::var_long::VarLong(
holder_entity.entity_id as i64,
@@ -3298,7 +3297,7 @@ impl Entity {
let je_packet =
pumpkin_protocol::java::client::play::CSetEntityLink::new(self.entity_id, -1, true);
let be_packet = pumpkin_protocol::bedrock::client::CSetActorLink {
link: pumpkin_protocol::bedrock::client::common::EntityLink {
link: pumpkin_protocol::bedrock::client::common::ActorLink {
ridden_unique_id: pumpkin_protocol::codec::var_long::VarLong(self.entity_id as i64),
rider_unique_id: pumpkin_protocol::codec::var_long::VarLong(-1),
link_type: 0, // Unlink

View File

@@ -5,7 +5,7 @@ use pumpkin_data::particle::Particle;
use pumpkin_data::sound::{Sound, SoundCategory};
use crate::entity::{EntityBaseFuture, mob::Mob, player::Player};
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_util::math::vector3::Vector3;
pub trait Animal: Mob {
@@ -62,7 +62,7 @@ pub trait Animal: Mob {
world.send_entity_status(
entity,
pumpkin_data::entity::EntityStatus::InLoveHearts,
Some(ActorEventType::InLoveHearts),
Some(ActorEventID::InLoveHearts),
);
world.spawn_particle(

View File

@@ -8,7 +8,7 @@ use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::tag::{self, Taggable};
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::java::client::play::Metadata;
use rand::RngExt;
@@ -485,13 +485,13 @@ impl Mob for CatEntity {
self.get_entity().world.load().send_entity_status(
self.get_entity(),
EntityStatus::TamingSucceeded,
Some(ActorEventType::TamingSucceeded),
Some(ActorEventID::TamingSucceeded),
);
} else {
self.get_entity().world.load().send_entity_status(
self.get_entity(),
EntityStatus::TamingFailed,
Some(ActorEventType::TamingFailed),
Some(ActorEventID::TamingFailed),
);
}

View File

@@ -8,7 +8,7 @@ use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::tag::{self, Taggable};
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_protocol::java::client::play::Metadata;
use rand::RngExt;
@@ -196,13 +196,13 @@ impl Mob for OcelotEntity {
self.get_entity().world.load().send_entity_status(
self.get_entity(),
EntityStatus::TrustingSucceeded,
Some(ActorEventType::TamingSucceeded),
Some(ActorEventID::TamingSucceeded),
);
} else {
self.get_entity().world.load().send_entity_status(
self.get_entity(),
EntityStatus::TrustingFailed,
Some(ActorEventType::TamingFailed),
Some(ActorEventID::TamingFailed),
);
}

View File

@@ -22,8 +22,8 @@ use pumpkin_inventory::screen_handler::{
};
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_protocol::bedrock::{
client::set_actor_data::{EntityMetadata, MetadataValue, entity_data_key},
server::actor_event::ActorEventType,
client::set_actor_data::{MetadataValue, SyncedActorDataList, entity_data_key},
server::actor_event::ActorEventID,
};
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::java::client::play::{CMerchantOffers, Metadata};
@@ -283,11 +283,11 @@ pub struct VillagerEntity {
}
impl VillagerEntity {
fn bedrock_metadata(data: VillagerData, xp: i32) -> EntityMetadata {
fn bedrock_metadata(data: VillagerData, xp: i32) -> SyncedActorDataList {
const PROFESSIONS: [i32; 15] = [0, 8, 11, 6, 7, 1, 2, 4, 12, 5, 13, 14, 3, 10, 9];
const REGIONS: [i32; 7] = [1, 2, 0, 3, 4, 5, 6];
let mut metadata = EntityMetadata::new();
let mut metadata = SyncedActorDataList::new();
metadata.set(
entity_data_key::VARIANT,
MetadataValue::Int(
@@ -1131,7 +1131,7 @@ impl VillagerEntity {
world.send_entity_status(
self.get_entity(),
pumpkin_data::entity::EntityStatus::VillagerHappy,
Some(ActorEventType::VillagerHappy),
Some(ActorEventID::VillagerHappy),
);
self.job_site_pending.store(false, Ordering::Relaxed);
if profession == VillagerProfession::None {
@@ -1156,7 +1156,7 @@ impl VillagerEntity {
entity.world.load().send_entity_status(
entity,
pumpkin_data::entity::EntityStatus::VillagerAngry,
Some(ActorEventType::VillagerAngry),
Some(ActorEventID::VillagerAngry),
);
entity.play_sound(pumpkin_data::sound::Sound::EntityVillagerNo);
}
@@ -1727,7 +1727,7 @@ impl Mob for VillagerEntity {
fn mob_bedrock_spawn_metadata(
&self,
) -> crate::entity::EntityBaseFuture<'_, Option<EntityMetadata>> {
) -> crate::entity::EntityBaseFuture<'_, Option<SyncedActorDataList>> {
Box::pin(async move {
Some(Self::bedrock_metadata(
*self.villager_data.lock().await,
@@ -1833,7 +1833,7 @@ impl Mob for VillagerEntity {
self.get_entity().world.load().send_entity_status(
self.get_entity(),
pumpkin_data::entity::EntityStatus::VillagerAngry,
Some(ActorEventType::VillagerAngry),
Some(ActorEventID::VillagerAngry),
);
})
}
@@ -1878,7 +1878,7 @@ impl Mob for VillagerEntity {
world.send_entity_status(
self.get_entity(),
pumpkin_data::entity::EntityStatus::VillagerHappy,
Some(ActorEventType::VillagerHappy),
Some(ActorEventID::VillagerHappy),
);
}

View File

@@ -23,13 +23,19 @@ use pumpkin_protocol::bedrock::client::play_status::CPlayStatus;
use pumpkin_protocol::bedrock::client::set_time::CSetTime;
use pumpkin_protocol::bedrock::client::update_abilities::{Ability, CUpdateAbilities};
use pumpkin_protocol::bedrock::client::{
AbilityLayer,
CommandPermissionLevel, PlayerPermissionLevel, SerializedAbilitiesData,
};
use pumpkin_protocol::bedrock::client::{
SerializedAbilitiesDataSerializedLayer,
move_player::CMovePlayer as CBedrockMovePlayer,
respawn::CRespawn as CBedrockRespawn,
update_attributes::{Attribute as BedrockAttribute, CUpdateAttributes as CBedrockAttributes},
update_attributes::{
AttributeData as BedrockAttribute, CUpdateAttributes as CBedrockAttributes,
},
};
use pumpkin_protocol::bedrock::server::{
respawn::{RespawnState, SRespawn as SBedrockRespawn},
text::SText,
};
use pumpkin_protocol::bedrock::respawn::RespawnState;
use pumpkin_protocol::bedrock::server::text::SText;
use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer;
use pumpkin_util::translation::Locale;
use pumpkin_util::version::JavaMinecraftVersion;
@@ -229,7 +235,7 @@ use pumpkin_nbt::tag::NbtTag;
use pumpkin_protocol::IdOr;
use pumpkin_protocol::SoundEvent;
use pumpkin_protocol::bedrock::client::container_open::CContainerOpen;
use pumpkin_protocol::bedrock::server::actor_event::{ActorEventType, SActorEvent};
use pumpkin_protocol::bedrock::server::actor_event::{ActorEventID, SActorEvent};
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::codec::var_long::VarLong;
use pumpkin_protocol::codec::var_ulong::VarULong;
@@ -1745,12 +1751,13 @@ impl Player {
pitch,
dimension.minecraft_name.to_owned(),
),
&pumpkin_protocol::bedrock::client::CSetSpawnPosition::new(
0, // Player spawn
block_pos,
bedrock_dimension,
block_pos,
),
&pumpkin_protocol::bedrock::client::CSetSpawnPosition {
spawn_position_type:
pumpkin_protocol::bedrock::client::SpawnPositionType::PlayerRespawn,
block_position: block_pos,
dimension_type: bedrock_dimension.into(),
spawn_block_pos: block_pos,
},
)
.await;
@@ -2223,7 +2230,7 @@ impl Player {
.enqueue_packet_editioned(
&CTitleText::new(text),
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
2,
pumpkin_protocol::bedrock::client::TitleType::Title,
text.clone().get_text(),
0,
0,
@@ -2237,7 +2244,7 @@ impl Player {
.enqueue_packet_editioned(
&CSubtitle::new(text),
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
3,
pumpkin_protocol::bedrock::client::TitleType::Subtitle,
text.clone().get_text(),
0,
0,
@@ -2251,7 +2258,7 @@ impl Player {
.enqueue_packet_editioned(
&CActionBar::new(text),
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
4,
pumpkin_protocol::bedrock::client::TitleType::Actionbar,
text.clone().get_text(),
0,
0,
@@ -2267,7 +2274,7 @@ impl Player {
self.enqueue_packet_editioned(
&CTitleAnimation::new(fade_in, stay, fade_out),
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
5,
pumpkin_protocol::bedrock::client::TitleType::Times,
String::new(),
fade_in,
stay,
@@ -2769,8 +2776,16 @@ impl Player {
let is_spectator = self.gamemode.load() == GameMode::Spectator;
// 1. Permission Mapping
let player_perm = if is_op { 2 } else { 1 }; // 1: Member, 2: Operator
let command_perm = u8::from(is_op); // 0: Normal, 1: Operator
let player_perm = if is_op {
PlayerPermissionLevel::Operator
} else {
PlayerPermissionLevel::Member
};
let command_perm = if is_op {
CommandPermissionLevel::GameDirectors
} else {
CommandPermissionLevel::Any
};
// 2. Build the Ability Bitmask
let mut ability_value: u32 = 0;
@@ -2808,7 +2823,7 @@ impl Player {
set_ability(Ability::NoClip, is_spectator);
// 3. Construct the Layers
let mut layers = vec![AbilityLayer {
let mut layers = vec![SerializedAbilitiesDataSerializedLayer {
serialized_layer: 0, // LAYER_BASE
// 0x3FFFF defines the first 18 bits as "provided" by this packet
abilities_set: (1 << Ability::AbilityCount as u32) - 1,
@@ -2819,7 +2834,7 @@ impl Player {
}];
if is_spectator {
layers.push(AbilityLayer {
layers.push(SerializedAbilitiesDataSerializedLayer {
serialized_layer: 1,
abilities_set: 1 << (Ability::Flying as u32),
ability_value: 1 << (Ability::Flying as u32),
@@ -2830,10 +2845,12 @@ impl Player {
}
let packet = CUpdateAbilities {
target_player_raw_id: self.entity_id().into(),
player_permission: player_perm,
command_permission: command_perm,
layers,
data: SerializedAbilitiesData {
target_player_raw_id: self.entity_id().into(),
player_permissions: player_perm,
command_permissions: command_perm,
layers,
},
};
if let Ok(data) = bedrock.serialize_packet(&packet) {
@@ -3000,9 +3017,9 @@ impl Player {
self.client
.enqueue_packet_editioned(
&CChangeDifficulty::new(level_info.difficulty as u8, level_info.difficulty_locked),
&pumpkin_protocol::bedrock::client::CSetDifficulty::new(
level_info.difficulty as u32,
),
&pumpkin_protocol::bedrock::client::CSetDifficulty {
difficulty: (level_info.difficulty as u32).into(),
},
)
.await;
}
@@ -3461,11 +3478,12 @@ impl Player {
0
};
let pos_f32 = Vector3::new(position.x as f32, position.y as f32, position.z as f32);
let change_dim_packet = pumpkin_protocol::bedrock::client::CChangeDimension::new(
bedrock_dimension,
pos_f32,
false,
);
let change_dim_packet = pumpkin_protocol::bedrock::client::CChangeDimension {
dimension_id: bedrock_dimension.into(),
position: pos_f32,
respawn: false,
loading_screen_id: None
};
if let Ok(data) = bedrock.serialize_packet(&change_dim_packet) {
bedrock.enqueue_packet(data).await;
}
@@ -3719,7 +3737,7 @@ impl Player {
default_max_value: max_value,
default_value,
name: name.to_string(),
modifiers_list_size: pumpkin_protocol::codec::var_uint::VarUInt(0),
modifiers: Vec::new(),
};
self.enqueue_packet_editioned(
@@ -3729,8 +3747,8 @@ impl Player {
self.hunger_manager.saturation.load(),
),
&CBedrockAttributes {
runtime_id: VarULong(self.entity_id() as u64),
attributes: vec![
target_runtime_id: VarULong(self.entity_id() as u64),
attribute_list: vec![
attribute(
"minecraft:health",
self.living_entity.health.load(),
@@ -3750,7 +3768,7 @@ impl Player {
5.0,
),
],
player_tick: VarULong(self.tick_counter.load(Ordering::Relaxed).max(0) as u64),
tick: VarULong(self.tick_counter.load(Ordering::Relaxed).max(0) as u64),
},
)
.await;
@@ -3761,15 +3779,15 @@ impl Player {
let entity = self.get_entity();
let position = entity.pos.load();
client
.send_packet(&CBedrockRespawn::new(
Vector3::new(
.send_packet(&SBedrockRespawn {
position: Vector3::new(
position.x as f32,
position.y as f32 + entity.entity_type.eye_height,
position.z as f32,
),
state,
VarULong(self.entity_id() as u64),
))
player_runtime_id: VarULong(self.entity_id() as u64),
})
.await;
}
}
@@ -4093,9 +4111,9 @@ impl Player {
.send_packet_now_editioned(
&CCombatDeath::new(self.entity_id().into(), &death_msg),
&SActorEvent {
entity_runtime_id: VarULong(self.entity_id() as u64),
event_type: ActorEventType::Death,
event_data: VarInt(0),
target_runtime_id: VarULong(self.entity_id() as u64),
event_id: ActorEventID::Death,
data: VarInt(0),
fire_at_position: None,
},
)
@@ -4184,8 +4202,8 @@ impl Player {
self.client
.enqueue_packet_editioned(
&CGameEvent::new(GameEvent::ChangeGameMode, gamemode as i32 as f32),
&pumpkin_protocol::bedrock::client::set_player_gamemode::CSetPlayerGamemode {
gamemode,
&pumpkin_protocol::bedrock::client::set_player_gamemode::CSetPlayerGameType {
player_game_type: gamemode.into(),
},
)
.await;
@@ -4837,7 +4855,7 @@ impl Player {
&pumpkin_protocol::bedrock::server::container_close::SContainerClose {
container_id: sync_id,
container_type: bedrock_window_type,
server_initiated: true,
server_initiated_close: true,
},
)
.await;
@@ -5462,7 +5480,7 @@ impl Player {
let be_packet = pumpkin_protocol::bedrock::server::animate::SAnimate {
action: pumpkin_protocol::bedrock::server::animate::AnimateAction::SwingArm,
runtime_entity_id: pumpkin_protocol::codec::var_ulong::VarULong(entity_id as u64),
target_actor_runtime_id: pumpkin_protocol::codec::var_ulong::VarULong(entity_id as u64),
data: 0.0,
swing_source: None,
};
@@ -6801,13 +6819,13 @@ impl InventoryPlayer for Player {
if let Some(slot_idx) = bedrock_inventory_slot(packet.slot) {
let item_desc = NetworkItemStackDescriptor::from(&*packet.slot_data.0);
let bedrock_packet = CInventorySlot {
window_id: VarUInt(0),
inventory_slot: VarUInt(slot_idx),
container_name: Some(FullContainerName {
container_id: VarUInt(0),
slot: VarUInt(slot_idx),
full_container_name: Some(FullContainerName {
container_name: ContainerName::Inventory,
dynamic_id: None,
}),
storage: None,
storage_item: None,
item: item_desc,
};
if let Ok(data) = bedrock.serialize_packet(&bedrock_packet) {
@@ -6847,13 +6865,13 @@ impl InventoryPlayer for Player {
if let Some((container_name, slot_id)) = bedrock_info {
let bedrock_packet = CInventorySlot {
window_id: VarUInt(window_id as u32),
inventory_slot: VarUInt(slot_id as u32),
container_name: Some(FullContainerName {
container_id: VarUInt(window_id as u32),
slot: VarUInt(slot_id as u32),
full_container_name: Some(FullContainerName {
container_name,
dynamic_id: None,
}),
storage: None,
storage_item: None,
item: item_desc,
};
if let Ok(data) = bedrock.serialize_packet(&bedrock_packet) {
@@ -6938,13 +6956,13 @@ impl InventoryPlayer for Player {
let item_stack = &*packet.item.0;
let item_desc = NetworkItemStackDescriptor::from(item_stack);
let bedrock_packet = CInventorySlot {
window_id: VarUInt(0),
inventory_slot: VarUInt(packet.slot.0 as u32),
container_name: Some(FullContainerName {
container_id: VarUInt(0),
slot: VarUInt(packet.slot.0 as u32),
full_container_name: Some(FullContainerName {
container_name: ContainerName::Inventory,
dynamic_id: None,
}),
storage: None,
storage_item: None,
item: item_desc,
};
if let Ok(data) = bedrock.serialize_packet(&bedrock_packet) {
@@ -6968,7 +6986,7 @@ impl InventoryPlayer for Player {
packet.slot as u32,
),
container_id: 0,
should_select_block: true,
should_select_slot: true,
},
)
.await;

View File

@@ -11,7 +11,7 @@ use crate::{
use pumpkin_data::entity::{EntityStatus, EntityType};
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer;
use pumpkin_protocol::java::client::play::Metadata;
use pumpkin_util::math::vector3::Vector3;
@@ -107,7 +107,7 @@ impl EntityBase for EggEntity {
world.send_entity_status(
self.get_entity(),
EntityStatus::Death,
Some(ActorEventType::Death),
Some(ActorEventID::Death),
);
// Decide spawn count per probabilities:

View File

@@ -13,7 +13,7 @@ use pumpkin_data::damage::DamageType;
use pumpkin_data::entity::{EntityPose, EntityStatus};
use pumpkin_data::particle::Particle;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_util::math::vector3::Vector3;
const GRAVITY: f64 = 0.03;
@@ -171,7 +171,7 @@ impl EntityBase for EnderPearlEntity {
.await;
}
world.send_entity_status(entity, EntityStatus::Death, Some(ActorEventType::Death));
world.send_entity_status(entity, EntityStatus::Death, Some(ActorEventID::Death));
})
}
}

View File

@@ -4,7 +4,7 @@ use crate::{
world::World,
};
use pumpkin_data::entity::EntityStatus;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_protocol::{codec::optional_int::OptionalInt, java::client::play::Metadata};
use pumpkin_util::{
math::vector3::Vector3,
@@ -85,7 +85,7 @@ impl FireworkRocketEntity {
world.send_entity_status(
entity,
EntityStatus::FireworksExplode,
Some(ActorEventType::FireworksExplode),
Some(ActorEventID::FireworksExplode),
);
// TODO: Explode/colors

View File

@@ -8,7 +8,7 @@ use crate::{
};
use pumpkin_data::entity::EntityStatus;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_protocol::java::client::play::CWorldEvent;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector2::{Vector2, to_chunk_pos};
@@ -112,7 +112,7 @@ impl EntityBase for LingeringPotionEntity {
world.send_entity_status(
self.get_entity(),
EntityStatus::Death,
Some(ActorEventType::Death),
Some(ActorEventID::Death),
);
// Read stored item stack and compute potion effects

View File

@@ -8,7 +8,7 @@ use crate::{
};
use pumpkin_data::damage::DamageType;
use pumpkin_data::entity::{EntityStatus, EntityType};
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_util::math::vector3::Vector3;
const GRAVITY: f64 = 0.03;
@@ -69,7 +69,7 @@ impl EntityBase for SnowballEntity {
world.send_entity_status(
self.get_entity(),
EntityStatus::Death,
Some(ActorEventType::Death),
Some(ActorEventID::Death),
);
// Handle entity-specific damage

View File

@@ -5,7 +5,7 @@ use pumpkin_data::entity::EntityStatus;
use pumpkin_data::particle::Particle;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventType;
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
use pumpkin_util::math::vector3::Vector3;
use rand::RngExt;
@@ -44,7 +44,7 @@ impl TntMinecart {
world.send_entity_status(
entity,
EntityStatus::TntPrime,
Some(ActorEventType::CartWithPrimeTNT),
Some(ActorEventID::PrimeTNTCart),
);
world.play_sound(
Sound::EntityTntPrimed,

Some files were not shown because too many files have changed in this diff Show More