mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
Network Serialization Quality of Life and Safety Improvements (#701)
This commit is contained in:
@@ -7,7 +7,7 @@ use syn::{Ident, LitInt};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DamageTypeEntry {
|
||||
id: u32,
|
||||
id: u8,
|
||||
components: DamageTypeData,
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub effects: Option<DamageEffects>,
|
||||
pub message_id: &'static str,
|
||||
pub scaling: DamageScaling,
|
||||
pub id: u32,
|
||||
pub id: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
||||
@@ -34,16 +34,16 @@ pub(crate) fn build() -> TokenStream {
|
||||
let mut variants = TokenStream::new();
|
||||
|
||||
for (name, typee) in json.iter() {
|
||||
let i = typee.id;
|
||||
let i = typee.id as u8;
|
||||
let name = format_ident!("{}", name.to_uppercase());
|
||||
variants.extend([quote! {
|
||||
pub const #name: u32 = #i;
|
||||
pub const #name: u8 = #i;
|
||||
}]);
|
||||
}
|
||||
|
||||
let raw_id = json.len() as u32;
|
||||
let raw_id = json.len() as u8;
|
||||
variants.extend([quote! {
|
||||
pub const RAW: u32 = #raw_id; // One higher than highest vanilla id
|
||||
pub const RAW: u8 = #raw_id; // One higher than highest vanilla id
|
||||
}]);
|
||||
|
||||
quote! {
|
||||
|
||||
@@ -187,6 +187,7 @@ pub fn get_nbt_string<R: Read>(bytes: &mut NbtReadHelper<R>) -> Result<String, E
|
||||
Ok(string.to_string())
|
||||
}
|
||||
|
||||
// TODO: This is a bit hacky
|
||||
pub(crate) const NBT_ARRAY_TAG: &str = "__nbt_array";
|
||||
pub(crate) const NBT_INT_ARRAY_TAG: &str = "__nbt_int_array";
|
||||
pub(crate) const NBT_LONG_ARRAY_TAG: &str = "__nbt_long_array";
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::CONFIG_SELECT_KNOWN_PACKS;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, KnownPack,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::KnownPack;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(CONFIG_SELECT_KNOWN_PACKS)]
|
||||
pub struct CKnownPacks<'a> {
|
||||
pub known_packs: &'a [KnownPack<'a>],
|
||||
@@ -18,14 +15,3 @@ impl<'a> CKnownPacks<'a> {
|
||||
Self { known_packs }
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CKnownPacks<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_list::<KnownPack>(self.known_packs, |p, v| {
|
||||
p.write_string(v.namespace)?;
|
||||
p.write_string(v.id)?;
|
||||
p.write_string(v.version)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::CONFIG_REGISTRY_DATA;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
ClientPacket,
|
||||
codec::identifier::Identifier,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::{codec::identifier::Identifier, ser::network_serialize_no_prefix};
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(CONFIG_REGISTRY_DATA)]
|
||||
pub struct CRegistryData<'a> {
|
||||
pub registry_id: &'a Identifier,
|
||||
@@ -25,11 +20,14 @@ impl<'a> CRegistryData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RegistryEntry {
|
||||
pub entry_id: Identifier,
|
||||
#[serde(serialize_with = "network_serialize_no_prefix")]
|
||||
pub data: Option<Box<[u8]>>,
|
||||
}
|
||||
|
||||
// TODO: No unwraps
|
||||
impl RegistryEntry {
|
||||
pub fn from_nbt(name: &str, nbt: &impl Serialize) -> Self {
|
||||
let mut data_buf = Vec::new();
|
||||
@@ -48,14 +46,3 @@ impl RegistryEntry {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CRegistryData<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_identifier(self.registry_id)?;
|
||||
write.write_list::<RegistryEntry>(self.entries, |p, v| {
|
||||
p.write_identifier(&v.entry_id)?;
|
||||
p.write_option(&v.data, |p, v| p.write_slice(v))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Link, VarInt};
|
||||
use crate::Link;
|
||||
use pumpkin_data::packet::clientbound::CONFIG_SERVER_LINKS;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
@@ -6,12 +6,11 @@ use serde::Serialize;
|
||||
#[derive(Serialize)]
|
||||
#[packet(CONFIG_SERVER_LINKS)]
|
||||
pub struct CConfigServerLinks<'a> {
|
||||
links_count: &'a VarInt,
|
||||
links: &'a [Link<'a>],
|
||||
}
|
||||
|
||||
impl<'a> CConfigServerLinks<'a> {
|
||||
pub fn new(links_count: &'a VarInt, links: &'a [Link<'a>]) -> Self {
|
||||
Self { links_count, links }
|
||||
pub fn new(links: &'a [Link<'a>]) -> Self {
|
||||
Self { links }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{VarInt, codec::identifier::Identifier};
|
||||
use crate::codec::identifier::Identifier;
|
||||
use pumpkin_data::packet::clientbound::CONFIG_STORE_COOKIE;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
@@ -8,16 +8,11 @@ use pumpkin_macros::packet;
|
||||
/// The Notchian (vanilla) client only accepts cookies of up to 5 KiB in size.
|
||||
pub struct CStoreCookie<'a> {
|
||||
key: &'a Identifier,
|
||||
payload_length: VarInt,
|
||||
payload: &'a [u8], // 5120,
|
||||
}
|
||||
|
||||
impl<'a> CStoreCookie<'a> {
|
||||
pub fn new(key: &'a Identifier, payload: &'a [u8]) -> Self {
|
||||
Self {
|
||||
key,
|
||||
payload_length: VarInt(payload.len() as i32),
|
||||
payload,
|
||||
}
|
||||
Self { key, payload }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use pumpkin_world::block::registry;
|
||||
|
||||
use crate::{
|
||||
ClientPacket,
|
||||
codec::{identifier::Identifier, var_int::VarInt},
|
||||
codec::identifier::Identifier,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
|
||||
@@ -32,7 +32,10 @@ impl ClientPacket for CUpdateTags<'_> {
|
||||
p.write_identifier(&Identifier::vanilla(registry_key.identifier_string()))?;
|
||||
|
||||
let values = get_registry_key_tags(registry_key);
|
||||
p.write_var_int(&VarInt::from(values.len()))?;
|
||||
p.write_var_int(&values.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", values.len()))
|
||||
})?)?;
|
||||
|
||||
for (key, values) in values.iter() {
|
||||
// This is technically an `Identifier` but same thing
|
||||
p.write_string_bounded(key, u16::MAX as usize)?;
|
||||
@@ -43,7 +46,7 @@ impl ClientPacket for CUpdateTags<'_> {
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
p.write_var_int(&VarInt::from(id))
|
||||
p.write_var_int(&id.into())
|
||||
})?;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,11 @@ use pumpkin_data::packet::clientbound::LOGIN_HELLO;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[packet(LOGIN_HELLO)]
|
||||
pub struct CEncryptionRequest<'a> {
|
||||
pub server_id: &'a str, // 20
|
||||
pub public_key_length: VarInt,
|
||||
pub public_key: &'a [u8],
|
||||
pub verify_token_length: VarInt,
|
||||
pub verify_token: &'a [u8],
|
||||
pub should_authenticate: bool,
|
||||
}
|
||||
@@ -24,9 +20,7 @@ impl<'a> CEncryptionRequest<'a> {
|
||||
) -> Self {
|
||||
Self {
|
||||
server_id,
|
||||
public_key_length: public_key.len().into(),
|
||||
public_key,
|
||||
verify_token_length: verify_token.len().into(),
|
||||
verify_token,
|
||||
should_authenticate,
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::LOGIN_LOGIN_FINISHED;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, Property,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::Property;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(LOGIN_LOGIN_FINISHED)]
|
||||
pub struct CLoginSuccess<'a> {
|
||||
pub uuid: &'a uuid::Uuid,
|
||||
@@ -24,16 +21,3 @@ impl<'a> CLoginSuccess<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CLoginSuccess<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_uuid(self.uuid)?;
|
||||
write.write_string(self.username)?;
|
||||
write.write_list::<Property>(self.properties, |p, v| {
|
||||
p.write_string(&v.name)?;
|
||||
p.write_string(&v.value)?;
|
||||
p.write_option(&v.signature, |p, v| p.write_string(v))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::io::Write;
|
||||
|
||||
use crate::ClientPacket;
|
||||
use crate::client::play::bossevent_action::BosseventAction;
|
||||
use crate::ser::{NetworkWriteExt, WritingError};
|
||||
use crate::{ClientPacket, VarInt};
|
||||
use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
@@ -32,29 +32,29 @@ impl ClientPacket for CBossEvent<'_> {
|
||||
division,
|
||||
flags,
|
||||
} => {
|
||||
write.write_var_int(&VarInt::from(0u8))?;
|
||||
write.write_var_int(&0.into())?;
|
||||
write.write_slice(&title.encode())?;
|
||||
write.write_f32_be(*health)?;
|
||||
write.write_var_int(color)?;
|
||||
write.write_var_int(division)?;
|
||||
write.write_u8_be(*flags)
|
||||
}
|
||||
BosseventAction::Remove => write.write_var_int(&VarInt::from(1u8)),
|
||||
BosseventAction::Remove => write.write_var_int(&1.into()),
|
||||
BosseventAction::UpdateHealth(health) => {
|
||||
write.write_var_int(&VarInt::from(2u8))?;
|
||||
write.write_var_int(&2.into())?;
|
||||
write.write_f32_be(*health)
|
||||
}
|
||||
BosseventAction::UpdateTile(title) => {
|
||||
write.write_var_int(&VarInt::from(3u8))?;
|
||||
write.write_var_int(&3.into())?;
|
||||
write.write_slice(&title.encode())
|
||||
}
|
||||
BosseventAction::UpdateStyle { color, dividers } => {
|
||||
write.write_var_int(&VarInt::from(4u8))?;
|
||||
write.write_var_int(&4.into())?;
|
||||
write.write_var_int(color)?;
|
||||
write.write_var_int(dividers)
|
||||
}
|
||||
BosseventAction::UpdateFlags(flags) => {
|
||||
write.write_var_int(&VarInt::from(5u8))?;
|
||||
write.write_var_int(&5.into())?;
|
||||
write.write_u8_be(*flags)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct CChunkBatchEnd {
|
||||
}
|
||||
|
||||
impl CChunkBatchEnd {
|
||||
pub fn new(count: usize) -> Self {
|
||||
pub fn new(count: u16) -> Self {
|
||||
Self {
|
||||
batch_size: count.into(),
|
||||
}
|
||||
|
||||
@@ -53,7 +53,12 @@ impl ClientPacket for CChunkData<'_> {
|
||||
// TODO: Implement, currently default to full bright
|
||||
let chunk_light = vec![0xFFu8; chunk_light_len];
|
||||
|
||||
light_buf.write_var_int(&chunk_light_len.into())?;
|
||||
light_buf.write_var_int(&chunk_light_len.try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
chunk_light_len
|
||||
))
|
||||
})?)?;
|
||||
light_buf.write_slice(&chunk_light)?;
|
||||
|
||||
// Block count
|
||||
@@ -68,7 +73,12 @@ impl ClientPacket for CChunkData<'_> {
|
||||
data_buf.write_var_int(®istry_id.into())?;
|
||||
}
|
||||
NetworkPalette::Indirect(palette) => {
|
||||
data_buf.write_var_int(&palette.len().into())?;
|
||||
data_buf.write_var_int(&palette.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
palette.len()
|
||||
))
|
||||
})?)?;
|
||||
for registry_id in palette {
|
||||
data_buf.write_var_int(®istry_id.into())?;
|
||||
}
|
||||
@@ -89,7 +99,12 @@ impl ClientPacket for CChunkData<'_> {
|
||||
data_buf.write_var_int(®istry_id.into())?;
|
||||
}
|
||||
NetworkPalette::Indirect(palette) => {
|
||||
data_buf.write_var_int(&palette.len().into())?;
|
||||
data_buf.write_var_int(&palette.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
palette.len()
|
||||
))
|
||||
})?)?;
|
||||
for registry_id in palette {
|
||||
data_buf.write_var_int(®istry_id.into())?;
|
||||
}
|
||||
@@ -105,7 +120,12 @@ impl ClientPacket for CChunkData<'_> {
|
||||
}
|
||||
|
||||
// Chunk data
|
||||
write.write_var_int(&data_buf.len().into())?;
|
||||
write.write_var_int(&data_buf.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
data_buf.len()
|
||||
))
|
||||
})?)?;
|
||||
write.write_slice(&data_buf)?;
|
||||
|
||||
// TODO: block entities
|
||||
@@ -123,7 +143,12 @@ impl ClientPacket for CChunkData<'_> {
|
||||
write.write_bitset(&BitSet(Box::new([0])))?;
|
||||
|
||||
// Sky light
|
||||
write.write_var_int(&self.0.section.sections.len().into())?;
|
||||
write.write_var_int(&self.0.section.sections.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
self.0.section.sections.len()
|
||||
))
|
||||
})?)?;
|
||||
write.write_slice(&light_buf)?;
|
||||
|
||||
// Block Lighting
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_COMMAND_SUGGESTIONS;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, VarInt,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(PLAY_COMMAND_SUGGESTIONS)]
|
||||
pub struct CCommandSuggestions {
|
||||
id: VarInt,
|
||||
start: VarInt,
|
||||
length: VarInt,
|
||||
matches: Vec<CommandSuggestion>,
|
||||
matches: Box<[CommandSuggestion]>,
|
||||
}
|
||||
|
||||
impl CCommandSuggestions {
|
||||
pub fn new(id: VarInt, start: VarInt, length: VarInt, matches: Vec<CommandSuggestion>) -> Self {
|
||||
pub fn new(
|
||||
id: VarInt,
|
||||
start: VarInt,
|
||||
length: VarInt,
|
||||
matches: Box<[CommandSuggestion]>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
start,
|
||||
@@ -28,28 +30,7 @@ impl CCommandSuggestions {
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CCommandSuggestions {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_var_int(&self.id)?;
|
||||
write.write_var_int(&self.start)?;
|
||||
write.write_var_int(&self.length)?;
|
||||
|
||||
write.write_list(&self.matches, |write, suggestion| {
|
||||
write.write_string(&suggestion.suggestion)?;
|
||||
write.write_bool(suggestion.tooltip.is_some())?;
|
||||
if let Some(tooltip) = &suggestion.tooltip {
|
||||
write.write_slice(&tooltip.encode())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Serialize)]
|
||||
pub struct CommandSuggestion {
|
||||
pub suggestion: String,
|
||||
pub tooltip: Option<TextComponent>,
|
||||
|
||||
@@ -10,12 +10,12 @@ use crate::{
|
||||
|
||||
#[packet(PLAY_COMMANDS)]
|
||||
pub struct CCommands<'a> {
|
||||
pub nodes: Vec<ProtoNode<'a>>,
|
||||
pub nodes: Box<[ProtoNode<'a>]>,
|
||||
pub root_node_index: VarInt,
|
||||
}
|
||||
|
||||
impl<'a> CCommands<'a> {
|
||||
pub fn new(nodes: Vec<ProtoNode<'a>>, root_node_index: VarInt) -> Self {
|
||||
pub fn new(nodes: Box<[ProtoNode<'a>]>, root_node_index: VarInt) -> Self {
|
||||
Self {
|
||||
nodes,
|
||||
root_node_index,
|
||||
@@ -34,7 +34,7 @@ impl ClientPacket for CCommands<'_> {
|
||||
}
|
||||
|
||||
pub struct ProtoNode<'a> {
|
||||
pub children: Vec<VarInt>,
|
||||
pub children: Box<[VarInt]>,
|
||||
pub node_type: ProtoNodeType<'a>,
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,19 @@ use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_DATA;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::VarInt;
|
||||
use crate::{VarInt, ser::network_serialize_no_prefix};
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(PLAY_SET_ENTITY_DATA)]
|
||||
pub struct CSetEntityMetadata {
|
||||
entity_id: VarInt,
|
||||
metadata: Vec<u8>,
|
||||
// TODO: We should migrate the serialization of this into this file
|
||||
#[serde(serialize_with = "network_serialize_no_prefix")]
|
||||
metadata: Box<[u8]>,
|
||||
}
|
||||
|
||||
impl CSetEntityMetadata {
|
||||
pub fn new(entity_id: VarInt, metadata: Vec<u8>) -> Self {
|
||||
pub fn new(entity_id: VarInt, metadata: Box<[u8]>) -> Self {
|
||||
Self {
|
||||
entity_id,
|
||||
metadata,
|
||||
|
||||
@@ -11,7 +11,6 @@ use crate::{VarInt, codec::identifier::Identifier};
|
||||
pub struct CLogin<'a> {
|
||||
entity_id: i32,
|
||||
is_hardcore: bool,
|
||||
dimension_count: VarInt,
|
||||
dimension_names: &'a [Identifier],
|
||||
max_players: VarInt,
|
||||
view_distance: VarInt,
|
||||
@@ -61,7 +60,6 @@ impl<'a> CLogin<'a> {
|
||||
Self {
|
||||
entity_id,
|
||||
is_hardcore,
|
||||
dimension_count: VarInt(dimension_names.len() as i32),
|
||||
dimension_names,
|
||||
max_players,
|
||||
view_distance,
|
||||
|
||||
@@ -36,7 +36,14 @@ impl Serialize for CMultiBlockUpdate {
|
||||
let mut tuple = serializer.serialize_tuple(2 + self.positions_to_state_ids.len())?;
|
||||
|
||||
tuple.serialize_element(&vector3::packed_chunk_pos(&self.chunk_section))?;
|
||||
tuple.serialize_element(&VarInt::from(self.positions_to_state_ids.len() as i32))?;
|
||||
tuple.serialize_element(&VarInt(
|
||||
self.positions_to_state_ids.len().try_into().map_err(|_| {
|
||||
serde::ser::Error::custom(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
self.positions_to_state_ids.len()
|
||||
))
|
||||
})?,
|
||||
))?;
|
||||
|
||||
for (position, state_id) in &self.positions_to_state_ids {
|
||||
let long = ((*state_id as u64) << 12) | (*position as u64);
|
||||
|
||||
@@ -65,6 +65,7 @@ impl CPlayerChatMessage {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Check if we need this custom impl
|
||||
impl ClientPacket for CPlayerChatMessage {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
@@ -42,6 +42,7 @@ impl<'a> CPlayerInfoUpdate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check if we need this custom impl
|
||||
impl ClientPacket for CPlayerInfoUpdate<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
@@ -63,9 +64,19 @@ impl ClientPacket for CPlayerInfoUpdate<'_> {
|
||||
p.write_option(init_chat, |p, v| {
|
||||
p.write_uuid(&v.session_id)?;
|
||||
p.write_i64_be(v.expires_at)?;
|
||||
p.write_var_int(&v.public_key.len().into())?;
|
||||
p.write_var_int(&v.public_key.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} isn't representable as a VarInt",
|
||||
v.public_key.len()
|
||||
))
|
||||
})?)?;
|
||||
p.write_slice(&v.public_key)?;
|
||||
p.write_var_int(&v.signature.len().into())?;
|
||||
p.write_var_int(&v.signature.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} isn't representable as a VarInt",
|
||||
v.signature.len()
|
||||
))
|
||||
})?)?;
|
||||
p.write_slice(&v.signature)
|
||||
})?;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ impl<'a> CPlayerPosition<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Do we need a custom impl?
|
||||
impl ClientPacket for CPlayerPosition<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
@@ -2,22 +2,16 @@ use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_REMOVE;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::{Serialize, ser::SerializeSeq};
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(PLAY_PLAYER_INFO_REMOVE)]
|
||||
pub struct CRemovePlayerInfo<'a> {
|
||||
players_count: VarInt,
|
||||
#[serde(serialize_with = "serialize_slice_uuids")]
|
||||
players: &'a [uuid::Uuid],
|
||||
}
|
||||
|
||||
impl<'a> CRemovePlayerInfo<'a> {
|
||||
pub fn new(players_count: VarInt, players: &'a [uuid::Uuid]) -> Self {
|
||||
Self {
|
||||
players_count,
|
||||
players,
|
||||
}
|
||||
pub fn new(players: &'a [uuid::Uuid]) -> Self {
|
||||
Self { players }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,15 +7,11 @@ use crate::VarInt;
|
||||
#[derive(Serialize)]
|
||||
#[packet(PLAY_REMOVE_ENTITIES)]
|
||||
pub struct CRemoveEntities<'a> {
|
||||
entity_count: VarInt,
|
||||
entity_ids: &'a [VarInt],
|
||||
}
|
||||
|
||||
impl<'a> CRemoveEntities<'a> {
|
||||
pub fn new(entity_ids: &'a [VarInt]) -> Self {
|
||||
Self {
|
||||
entity_count: entity_ids.len().into(),
|
||||
entity_ids,
|
||||
}
|
||||
Self { entity_ids }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Link, VarInt};
|
||||
use crate::Link;
|
||||
use pumpkin_data::packet::clientbound::PLAY_SERVER_LINKS;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
@@ -6,12 +6,11 @@ use serde::Serialize;
|
||||
#[derive(Serialize)]
|
||||
#[packet(PLAY_SERVER_LINKS)]
|
||||
pub struct CPlayServerLinks<'a> {
|
||||
links_count: &'a VarInt,
|
||||
links: &'a [Link<'a>],
|
||||
}
|
||||
|
||||
impl<'a> CPlayServerLinks<'a> {
|
||||
pub fn new(links_count: &'a VarInt, links: &'a [Link<'a>]) -> Self {
|
||||
Self { links_count, links }
|
||||
pub fn new(links: &'a [Link<'a>]) -> Self {
|
||||
Self { links }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use serde::Serialize;
|
||||
pub struct CSetContainerContent<'a> {
|
||||
window_id: VarInt,
|
||||
state_id: VarInt,
|
||||
count: VarInt,
|
||||
slot_data: &'a [Slot],
|
||||
carried_item: &'a Slot,
|
||||
}
|
||||
@@ -25,7 +24,6 @@ impl<'a> CSetContainerContent<'a> {
|
||||
Self {
|
||||
window_id,
|
||||
state_id,
|
||||
count: slots.len().into(),
|
||||
slot_data: slots,
|
||||
carried_item,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{VarInt, codec::identifier::Identifier};
|
||||
use crate::codec::identifier::Identifier;
|
||||
use pumpkin_data::packet::clientbound::PLAY_STORE_COOKIE;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
@@ -9,16 +9,11 @@ use serde::Serialize;
|
||||
#[packet(PLAY_STORE_COOKIE)]
|
||||
pub struct CStoreCookie<'a> {
|
||||
key: &'a Identifier,
|
||||
payload_length: VarInt,
|
||||
payload: &'a [u8], // 5120,
|
||||
}
|
||||
|
||||
impl<'a> CStoreCookie<'a> {
|
||||
pub fn new(key: &'a Identifier, payload: &'a [u8]) -> Self {
|
||||
Self {
|
||||
key,
|
||||
payload_length: VarInt(payload.len() as i32),
|
||||
payload,
|
||||
}
|
||||
Self { key, payload }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ impl<'a> CTeleportEntity<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Do we need a custom impl?
|
||||
impl ClientPacket for CTeleportEntity<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
@@ -12,7 +12,10 @@ pub struct BitSet(pub Box<[i64]>);
|
||||
|
||||
impl BitSet {
|
||||
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
|
||||
write.write_var_int(&self.0.len().into())?;
|
||||
write.write_var_int(&self.0.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", self.0.len()))
|
||||
})?)?;
|
||||
|
||||
for b in &self.0 {
|
||||
write.write_i64_be(*b)?;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
use crate::VarInt;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_world::item::ItemStack;
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{
|
||||
Deserialize, Serialize, Serializer,
|
||||
de::{self, SeqAccess},
|
||||
ser,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Slot {
|
||||
pub item_count: VarInt,
|
||||
item_id: Option<VarInt>,
|
||||
num_components_to_add: Option<VarInt>,
|
||||
num_components_to_remove: Option<VarInt>,
|
||||
components_to_add: Option<Vec<(VarInt, ())>>, // The second type depends on the varint
|
||||
components_to_remove: Option<Vec<VarInt>>,
|
||||
pub enum Slot {
|
||||
NoItem,
|
||||
Item {
|
||||
// This also handles items on the ground which can have >64 items
|
||||
item_count: u32,
|
||||
item_id: u16,
|
||||
// TODO: Implement item components
|
||||
},
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Slot {
|
||||
@@ -27,7 +28,7 @@ impl<'de> Deserialize<'de> for Slot {
|
||||
type Value = Slot;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a valid VarInt encoded in a byte sequence")
|
||||
formatter.write_str("a valid Slot encoded in a byte sequence")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
@@ -37,39 +38,39 @@ impl<'de> Deserialize<'de> for Slot {
|
||||
let item_count = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("Failed to decode VarInt"))?;
|
||||
if item_count.0 == 0 {
|
||||
return Ok(Slot {
|
||||
item_count: 0.into(),
|
||||
item_id: None,
|
||||
num_components_to_add: None,
|
||||
num_components_to_remove: None,
|
||||
components_to_add: None,
|
||||
components_to_remove: None,
|
||||
});
|
||||
}
|
||||
let item_id = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("Failed to decode VarInt"))?;
|
||||
let num_components_to_add = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("Failed to decode VarInt"))?;
|
||||
let num_components_to_remove = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("Failed to decode VarInt"))?;
|
||||
if num_components_to_add.0 != 0 || num_components_to_remove.0 != 0 {
|
||||
return Err(de::Error::custom(
|
||||
"Slot components are currently unsupported",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Slot {
|
||||
item_count,
|
||||
item_id: Some(item_id),
|
||||
num_components_to_add: Some(num_components_to_add),
|
||||
num_components_to_remove: Some(num_components_to_remove),
|
||||
components_to_add: None,
|
||||
components_to_remove: None,
|
||||
})
|
||||
let slot = if item_count.0 == 0 {
|
||||
Slot::NoItem
|
||||
} else {
|
||||
let item_id = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("No item id VarInt!"))?;
|
||||
let num_components_to_add = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("No component add length VarInt!"))?;
|
||||
let num_components_to_remove = seq
|
||||
.next_element::<VarInt>()?
|
||||
.ok_or(de::Error::custom("No component remove length VarInt!"))?;
|
||||
|
||||
if num_components_to_add.0 != 0 || num_components_to_remove.0 != 0 {
|
||||
return Err(de::Error::custom(
|
||||
"Slot components are currently unsupported",
|
||||
));
|
||||
}
|
||||
|
||||
let item_id: u16 = item_id
|
||||
.0
|
||||
.try_into()
|
||||
.map_err(|_| de::Error::custom("Invalid item id!"))?;
|
||||
|
||||
Slot::Item {
|
||||
// i32 can always be u32
|
||||
item_count: item_count.0 as u32,
|
||||
item_id,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(slot)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,48 +83,33 @@ impl Serialize for Slot {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
if self.item_count == 0.into() {
|
||||
let mut s = serializer.serialize_seq(Some(1))?;
|
||||
s.serialize_element(&self.item_count)?;
|
||||
s.end()
|
||||
} else {
|
||||
match (&self.num_components_to_add, &self.num_components_to_remove) {
|
||||
(Some(to_add), Some(to_remove)) => {
|
||||
let mut s = serializer.serialize_seq(Some(6))?;
|
||||
s.serialize_element(&self.item_count)?;
|
||||
s.serialize_element(self.item_id.as_ref().unwrap())?;
|
||||
s.serialize_element(to_add)?;
|
||||
s.serialize_element(to_remove)?;
|
||||
s.serialize_element(self.components_to_add.as_ref().unwrap())?;
|
||||
s.serialize_element(self.components_to_remove.as_ref().unwrap())?;
|
||||
s.end()
|
||||
match self {
|
||||
Self::NoItem => VarInt(0).serialize(serializer),
|
||||
Self::Item {
|
||||
item_count,
|
||||
item_id,
|
||||
} => {
|
||||
// TODO: Components
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct NetworkRepr {
|
||||
item_count: VarInt,
|
||||
item_id: VarInt,
|
||||
components_to_add: VarInt,
|
||||
components_to_remove: VarInt,
|
||||
}
|
||||
(None, Some(to_remove)) => {
|
||||
let mut s = serializer.serialize_seq(Some(5))?;
|
||||
s.serialize_element(&self.item_count)?;
|
||||
s.serialize_element(self.item_id.as_ref().unwrap())?;
|
||||
s.serialize_element(&VarInt(0))?;
|
||||
s.serialize_element(to_remove)?;
|
||||
s.serialize_element(self.components_to_remove.as_ref().unwrap())?;
|
||||
s.end()
|
||||
}
|
||||
(Some(to_add), None) => {
|
||||
let mut s = serializer.serialize_seq(Some(5))?;
|
||||
s.serialize_element(&self.item_count)?;
|
||||
s.serialize_element(self.item_id.as_ref().unwrap())?;
|
||||
s.serialize_element(to_add)?;
|
||||
s.serialize_element(&VarInt(0))?;
|
||||
s.serialize_element(self.components_to_add.as_ref().unwrap())?;
|
||||
s.end()
|
||||
}
|
||||
(None, None) => {
|
||||
let mut s = serializer.serialize_seq(Some(4))?;
|
||||
s.serialize_element(&self.item_count)?;
|
||||
s.serialize_element(&self.item_id.as_ref().unwrap())?;
|
||||
s.serialize_element(&VarInt(0))?;
|
||||
s.serialize_element(&VarInt(0))?;
|
||||
s.end()
|
||||
|
||||
let item_count: i32 = (*item_count)
|
||||
.try_into()
|
||||
.map_err(|_| ser::Error::custom("Item count overflows an i32!"))?;
|
||||
|
||||
NetworkRepr {
|
||||
item_count: item_count.into(),
|
||||
item_id: (*item_id).into(),
|
||||
components_to_add: 0.into(),
|
||||
components_to_remove: 0.into(),
|
||||
}
|
||||
.serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,48 +117,36 @@ impl Serialize for Slot {
|
||||
|
||||
impl Slot {
|
||||
pub fn new(item_id: u16, count: u32) -> Self {
|
||||
Slot {
|
||||
item_count: count.into(),
|
||||
item_id: Some((item_id as i32).into()),
|
||||
// TODO: add these
|
||||
num_components_to_add: None,
|
||||
num_components_to_remove: None,
|
||||
components_to_add: None,
|
||||
components_to_remove: None,
|
||||
Self::Item {
|
||||
item_count: count,
|
||||
item_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_stack(self) -> Result<Option<ItemStack>, &'static str> {
|
||||
let item_id = self.item_id;
|
||||
let Some(item_id) = item_id else {
|
||||
return Ok(None);
|
||||
};
|
||||
let item_id = item_id.0.try_into().map_err(|_| "Item id too large")?;
|
||||
let item = Item::from_id(item_id).ok_or("Item id invalid")?;
|
||||
if self.item_count.0 > item.components.max_stack_size as i32 {
|
||||
Err("Oversized stack")
|
||||
} else {
|
||||
let stack = ItemStack {
|
||||
item,
|
||||
item_count: self
|
||||
.item_count
|
||||
.0
|
||||
.try_into()
|
||||
.map_err(|_| "Stack count too large")?,
|
||||
};
|
||||
Ok(Some(stack))
|
||||
match self {
|
||||
Self::NoItem => Ok(None),
|
||||
Self::Item {
|
||||
item_count,
|
||||
item_id,
|
||||
} => {
|
||||
let item = Item::from_id(item_id).ok_or("Item id invalid")?;
|
||||
if item_count > item.components.max_stack_size as u32 {
|
||||
Err("Stack item count greater than allowed")
|
||||
} else {
|
||||
let stack = ItemStack {
|
||||
item,
|
||||
// This is checked above
|
||||
item_count: item_count as u8,
|
||||
};
|
||||
Ok(Some(stack))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn empty() -> Self {
|
||||
Slot {
|
||||
item_count: VarInt(0),
|
||||
item_id: None,
|
||||
num_components_to_add: None,
|
||||
num_components_to_remove: None,
|
||||
components_to_add: None,
|
||||
components_to_remove: None,
|
||||
}
|
||||
Self::NoItem
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ impl VarInt {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Validate that the first byte will not overflow a i32
|
||||
pub fn decode(read: &mut impl Read) -> Result<Self, ReadingError> {
|
||||
let mut val = 0;
|
||||
for i in 0..Self::MAX_SIZE.get() {
|
||||
@@ -99,41 +100,40 @@ impl VarInt {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for VarInt {
|
||||
fn from(value: i32) -> Self {
|
||||
VarInt(value)
|
||||
}
|
||||
// Macros are needed because traits over generics succccccccccck
|
||||
macro_rules! gen_from {
|
||||
($ty: ty) => {
|
||||
impl From<$ty> for VarInt {
|
||||
fn from(value: $ty) -> Self {
|
||||
VarInt(value.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl From<u32> for VarInt {
|
||||
fn from(value: u32) -> Self {
|
||||
VarInt(value as i32)
|
||||
}
|
||||
gen_from!(i8);
|
||||
gen_from!(u8);
|
||||
gen_from!(i16);
|
||||
gen_from!(u16);
|
||||
gen_from!(i32);
|
||||
|
||||
macro_rules! gen_try_from {
|
||||
($ty: ty) => {
|
||||
impl TryFrom<$ty> for VarInt {
|
||||
type Error = <i32 as TryFrom<$ty>>::Error;
|
||||
|
||||
fn try_from(value: $ty) -> Result<Self, Self::Error> {
|
||||
Ok(VarInt(value.try_into()?))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl From<u8> for VarInt {
|
||||
fn from(value: u8) -> Self {
|
||||
VarInt(value as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for VarInt {
|
||||
fn from(value: u16) -> Self {
|
||||
VarInt(value as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for VarInt {
|
||||
fn from(value: usize) -> Self {
|
||||
VarInt(value as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VarInt> for i32 {
|
||||
fn from(value: VarInt) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
gen_try_from!(u32);
|
||||
gen_try_from!(i64);
|
||||
gen_try_from!(u64);
|
||||
gen_try_from!(isize);
|
||||
gen_try_from!(usize);
|
||||
|
||||
impl AsRef<i32> for VarInt {
|
||||
fn as_ref(&self) -> &i32 {
|
||||
|
||||
@@ -47,6 +47,7 @@ impl VarLong {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Validate that the first byte will not overflow a i64
|
||||
pub fn decode(read: &mut impl Read) -> Result<Self, ReadingError> {
|
||||
let mut val = 0;
|
||||
for i in 0..Self::MAX_SIZE.get() {
|
||||
|
||||
@@ -11,7 +11,6 @@ use ser::{NetworkWriteExt, ReadingError, WritingError, packet::Packet};
|
||||
use serde::{
|
||||
Deserialize, Serialize, Serializer,
|
||||
de::{DeserializeSeed, Visitor},
|
||||
ser::SerializeSeq,
|
||||
};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
@@ -86,7 +85,7 @@ where
|
||||
{
|
||||
enum IdOrStateDeserializer<T> {
|
||||
Init,
|
||||
Id(u32),
|
||||
Id(u16),
|
||||
Value(T),
|
||||
}
|
||||
|
||||
@@ -104,11 +103,15 @@ where
|
||||
IdOrStateDeserializer::Init => {
|
||||
// Get the VarInt
|
||||
let id = VarInt::deserialize(deserializer)?;
|
||||
assert!(id.0 >= 0);
|
||||
*self = IdOrStateDeserializer::<T>::Id(id.0 as u32);
|
||||
*self = IdOrStateDeserializer::<T>::Id(id.0.try_into().map_err(|_| {
|
||||
serde::de::Error::custom(format!(
|
||||
"{} cannot be mapped to a registry id",
|
||||
id.0
|
||||
))
|
||||
})?);
|
||||
}
|
||||
IdOrStateDeserializer::Id(id) => {
|
||||
assert!(*id == 0);
|
||||
debug_assert!(*id == 0);
|
||||
// Get the data
|
||||
let value = T::deserialize(deserializer)?;
|
||||
*self = IdOrStateDeserializer::Value(value);
|
||||
@@ -144,7 +147,7 @@ where
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub enum IdOr<T> {
|
||||
Id(u32),
|
||||
Id(u16),
|
||||
Value(T),
|
||||
}
|
||||
|
||||
@@ -168,10 +171,16 @@ impl<T: Serialize> Serialize for IdOr<T> {
|
||||
match self {
|
||||
IdOr::Id(id) => VarInt::from(*id + 1).serialize(serializer),
|
||||
IdOr::Value(value) => {
|
||||
let mut seq = serializer.serialize_seq(None)?;
|
||||
seq.serialize_element(&VarInt::from(0))?;
|
||||
seq.serialize_element(value)?;
|
||||
seq.end()
|
||||
#[derive(Serialize)]
|
||||
struct NetworkRepr<T: Serialize> {
|
||||
zero_id: VarInt,
|
||||
value: T,
|
||||
}
|
||||
NetworkRepr {
|
||||
zero_id: 0.into(),
|
||||
value,
|
||||
}
|
||||
.serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,6 +392,7 @@ pub struct Property {
|
||||
pub signature: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct KnownPack<'a> {
|
||||
pub namespace: &'a str,
|
||||
pub id: &'a str,
|
||||
|
||||
@@ -144,7 +144,12 @@ impl<W: AsyncWrite + Unpin> NetworkEncoder<W> {
|
||||
if data_len > MAX_PACKET_DATA_SIZE {
|
||||
return Err(PacketEncodeError::TooLong(data_len));
|
||||
}
|
||||
let data_len_var_int: VarInt = data_len.into();
|
||||
let data_len_var_int: VarInt = data_len.try_into().map_err(|_| {
|
||||
PacketEncodeError::Message(format!(
|
||||
"Packet data length is too large to fit in VarInt! ({})",
|
||||
data_len
|
||||
))
|
||||
})?;
|
||||
|
||||
if let Some((compression_threshold, compression_level)) = self.compression {
|
||||
if data_len >= compression_threshold {
|
||||
@@ -170,8 +175,15 @@ impl<W: AsyncWrite + Unpin> NetworkEncoder<W> {
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
debug_assert!(!compressed_buf.is_empty());
|
||||
|
||||
let full_packet_len_var_int: VarInt =
|
||||
(data_len_var_int.written_size() + compressed_buf.len()).into();
|
||||
let full_packet_len_var_int: VarInt = (data_len_var_int.written_size()
|
||||
+ compressed_buf.len())
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
PacketEncodeError::Message(format!(
|
||||
"Full packet length is too large to fit in VarInt! ({})",
|
||||
data_len
|
||||
))
|
||||
})?;
|
||||
|
||||
let complete_serialization_length =
|
||||
full_packet_len_var_int.written_size() + full_packet_len_var_int.0 as usize;
|
||||
@@ -197,8 +209,14 @@ impl<W: AsyncWrite + Unpin> NetworkEncoder<W> {
|
||||
// 0 to indicate uncompressed
|
||||
|
||||
let data_len_var_int: VarInt = 0.into();
|
||||
let full_packet_len_var_int: VarInt =
|
||||
(data_len_var_int.written_size() + data_len).into();
|
||||
let full_packet_len_var_int: VarInt = (data_len_var_int.written_size() + data_len)
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
PacketEncodeError::Message(format!(
|
||||
"Full packet length is too large to fit in VarInt! ({})",
|
||||
data_len
|
||||
))
|
||||
})?;
|
||||
|
||||
let complete_serialization_length =
|
||||
full_packet_len_var_int.written_size() + full_packet_len_var_int.0 as usize;
|
||||
|
||||
@@ -11,6 +11,17 @@ use thiserror::Error;
|
||||
pub mod packet;
|
||||
pub mod serializer;
|
||||
|
||||
// TODO: This is a bit hacky
|
||||
const NO_PREFIX_MARKER: &str = "__network_no_prefix";
|
||||
|
||||
pub fn network_serialize_no_prefix<T, S>(input: T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_newtype_struct(NO_PREFIX_MARKER, &input)
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ReadingError {
|
||||
#[error("EOF, Tried to read {0} but No bytes left to consume")]
|
||||
@@ -262,26 +273,55 @@ pub trait NetworkWriteExt {
|
||||
fn write_f64_be(&mut self, data: f64) -> Result<(), WritingError>;
|
||||
fn write_slice(&mut self, data: &[u8]) -> Result<(), WritingError>;
|
||||
|
||||
fn write_bool(&mut self, data: bool) -> Result<(), WritingError>;
|
||||
fn write_bool(&mut self, data: bool) -> Result<(), WritingError> {
|
||||
if data {
|
||||
self.write_u8_be(1)
|
||||
} else {
|
||||
self.write_u8_be(0)
|
||||
}
|
||||
}
|
||||
fn write_var_int(&mut self, data: &VarInt) -> Result<(), WritingError>;
|
||||
fn write_var_long(&mut self, data: &VarLong) -> Result<(), WritingError>;
|
||||
fn write_string_bounded(&mut self, data: &str, bound: usize) -> Result<(), WritingError>;
|
||||
fn write_string(&mut self, data: &str) -> Result<(), WritingError>;
|
||||
fn write_identifier(&mut self, data: &Identifier) -> Result<(), WritingError>;
|
||||
fn write_uuid(&mut self, data: &uuid::Uuid) -> Result<(), WritingError>;
|
||||
|
||||
fn write_uuid(&mut self, data: &uuid::Uuid) -> Result<(), WritingError> {
|
||||
let (first, second) = data.as_u64_pair();
|
||||
self.write_u64_be(first)?;
|
||||
self.write_u64_be(second)
|
||||
}
|
||||
|
||||
fn write_bitset(&mut self, bitset: &BitSet) -> Result<(), WritingError>;
|
||||
|
||||
fn write_option<G>(
|
||||
&mut self,
|
||||
data: &Option<G>,
|
||||
write: impl FnOnce(&mut Self, &G) -> Result<(), WritingError>,
|
||||
) -> Result<(), WritingError>;
|
||||
writer: impl FnOnce(&mut Self, &G) -> Result<(), WritingError>,
|
||||
) -> Result<(), WritingError> {
|
||||
if let Some(data) = data {
|
||||
self.write_bool(true)?;
|
||||
writer(self, data)
|
||||
} else {
|
||||
self.write_bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_list<G>(
|
||||
&mut self,
|
||||
data: &[G],
|
||||
write: impl Fn(&mut Self, &G) -> Result<(), WritingError>,
|
||||
) -> Result<(), WritingError>;
|
||||
list: &[G],
|
||||
writer: impl Fn(&mut Self, &G) -> Result<(), WritingError>,
|
||||
) -> Result<(), WritingError> {
|
||||
self.write_var_int(&list.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", list.len()))
|
||||
})?)?;
|
||||
|
||||
for data in list {
|
||||
writer(self, data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> NetworkWriteExt for W {
|
||||
@@ -339,14 +379,6 @@ impl<W: Write> NetworkWriteExt for W {
|
||||
self.write_all(data).map_err(WritingError::IoError)
|
||||
}
|
||||
|
||||
fn write_bool(&mut self, data: bool) -> Result<(), WritingError> {
|
||||
if data {
|
||||
self.write_u8_be(1)
|
||||
} else {
|
||||
self.write_u8_be(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_var_int(&mut self, data: &VarInt) -> Result<(), WritingError> {
|
||||
data.encode(self)
|
||||
}
|
||||
@@ -357,7 +389,10 @@ impl<W: Write> NetworkWriteExt for W {
|
||||
|
||||
fn write_string_bounded(&mut self, data: &str, bound: usize) -> Result<(), WritingError> {
|
||||
assert!(data.len() <= bound);
|
||||
self.write_var_int(&data.len().into())?;
|
||||
self.write_var_int(&data.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", data.len()))
|
||||
})?)?;
|
||||
|
||||
self.write_all(data.as_bytes())
|
||||
.map_err(WritingError::IoError)
|
||||
}
|
||||
@@ -370,41 +405,9 @@ impl<W: Write> NetworkWriteExt for W {
|
||||
data.encode(self)
|
||||
}
|
||||
|
||||
fn write_uuid(&mut self, data: &uuid::Uuid) -> Result<(), WritingError> {
|
||||
let (first, second) = data.as_u64_pair();
|
||||
self.write_u64_be(first)?;
|
||||
self.write_u64_be(second)
|
||||
}
|
||||
|
||||
fn write_bitset(&mut self, data: &BitSet) -> Result<(), WritingError> {
|
||||
data.encode(self)
|
||||
}
|
||||
|
||||
fn write_option<G>(
|
||||
&mut self,
|
||||
data: &Option<G>,
|
||||
writer: impl FnOnce(&mut Self, &G) -> Result<(), WritingError>,
|
||||
) -> Result<(), WritingError> {
|
||||
if let Some(data) = data {
|
||||
self.write_bool(true)?;
|
||||
writer(self, data)
|
||||
} else {
|
||||
self.write_bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_list<G>(
|
||||
&mut self,
|
||||
list: &[G],
|
||||
writer: impl Fn(&mut Self, &G) -> Result<(), WritingError>,
|
||||
) -> Result<(), WritingError> {
|
||||
self.write_var_int(&list.len().into())?;
|
||||
for data in list {
|
||||
writer(self, data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -2,10 +2,10 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{
|
||||
Serialize,
|
||||
ser::{self},
|
||||
ser::{self, Impossible},
|
||||
};
|
||||
|
||||
use super::{NetworkWriteExt, Write, WritingError};
|
||||
use super::{NO_PREFIX_MARKER, NetworkWriteExt, Write, WritingError};
|
||||
|
||||
pub struct Serializer<W: Write> {
|
||||
pub write: W,
|
||||
@@ -23,6 +23,198 @@ impl ser::Error for WritingError {
|
||||
}
|
||||
}
|
||||
|
||||
/// This serializer just writes a sequence without a varint prefix and defers the rest of the
|
||||
/// serialization to the wrapped serializer
|
||||
struct NonPrefixedSeqSerializer<'a, W: Write> {
|
||||
wrapped: &'a mut Serializer<W>,
|
||||
}
|
||||
|
||||
macro_rules! create_fail_method {
|
||||
($method: ident, $ty: ty) => {
|
||||
fn $method(self, _v: $ty) -> Result<Self::Ok, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence, but found {}!",
|
||||
stringify!($ty)
|
||||
)))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<W: Write> ser::SerializeSeq for NonPrefixedSeqSerializer<'_, W> {
|
||||
type Ok = ();
|
||||
type Error = WritingError;
|
||||
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
value.serialize(&mut *self.wrapped).map(|_| ())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> ser::Serializer for NonPrefixedSeqSerializer<'_, W> {
|
||||
type Ok = ();
|
||||
type Error = WritingError;
|
||||
|
||||
type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeStruct = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeMap = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTuple = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeSeq = Self;
|
||||
|
||||
create_fail_method!(serialize_bool, bool);
|
||||
create_fail_method!(serialize_bytes, &[u8]);
|
||||
create_fail_method!(serialize_char, char);
|
||||
create_fail_method!(serialize_f32, f32);
|
||||
create_fail_method!(serialize_f64, f64);
|
||||
create_fail_method!(serialize_i8, i8);
|
||||
create_fail_method!(serialize_i16, i16);
|
||||
create_fail_method!(serialize_i32, i32);
|
||||
create_fail_method!(serialize_i64, i64);
|
||||
create_fail_method!(serialize_u8, u8);
|
||||
create_fail_method!(serialize_u16, u16);
|
||||
create_fail_method!(serialize_u32, u32);
|
||||
create_fail_method!(serialize_u64, u64);
|
||||
create_fail_method!(serialize_str, &str);
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
Err(WritingError::Serde(
|
||||
"Expected a sequence but found a map!".into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T>(
|
||||
self,
|
||||
name: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a newtype struct {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a newtype variant {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
self.wrapped.serialize_none()
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
self.wrapped.serialize_bool(true)?;
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a struct {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a struct variant {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Err(WritingError::Serde(
|
||||
"Expected a sequence but found a tuple!".into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a tuple struct {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a tuple variant {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(WritingError::Serde(
|
||||
"Expected a sequence but found a unit!".into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a unit struct {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
Err(WritingError::Serde(format!(
|
||||
"Expected a sequence but found a unit variant {}!",
|
||||
name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
// General notes on the serializer:
|
||||
//
|
||||
// Primitives are written as-is
|
||||
@@ -87,13 +279,13 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
// TODO: This is super sketchy... is there a way to do it better? Can we choose what
|
||||
// serializer to use on a struct somehow from within the struct?
|
||||
if name == "TextComponent" {
|
||||
let mut buf = Vec::new();
|
||||
let mut nbt_serializer = pumpkin_nbt::serializer::Serializer::new(&mut buf, None);
|
||||
value
|
||||
.serialize(&mut nbt_serializer)
|
||||
.expect("Failed to serialize NBT for TextComponent within the network serializer");
|
||||
|
||||
self.serialize_bytes(&buf)
|
||||
let mut nbt_serializer =
|
||||
pumpkin_nbt::serializer::Serializer::new(&mut self.write, None);
|
||||
value.serialize(&mut nbt_serializer).map_err(|err| {
|
||||
WritingError::Serde(format!("Failed to serialize TextComponent NBT: {}", err))
|
||||
})
|
||||
} else if name == NO_PREFIX_MARKER {
|
||||
value.serialize(NonPrefixedSeqSerializer { wrapped: self })
|
||||
} else {
|
||||
value.serialize(self)
|
||||
}
|
||||
@@ -108,15 +300,26 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
self.write.write_var_int(&variant_index.into())?;
|
||||
self.write
|
||||
.write_var_int(&variant_index.try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", variant_index))
|
||||
})?)?;
|
||||
value.serialize(self)
|
||||
}
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
self.write.write_bool(false)
|
||||
}
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
// here is where all arrays/list getting written, usually we prefix the length of every length with an var int. The problem is
|
||||
// that byte arrays also getting thrown in here, and we don't want to prefix them
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
let Some(len) = len else {
|
||||
return Err(WritingError::Serde(
|
||||
"Sequences must have a known length".into(),
|
||||
));
|
||||
};
|
||||
|
||||
self.write.write_var_int(&len.try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", len))
|
||||
})?)?;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
@@ -163,7 +366,10 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
// Serialize ENUM index as varint
|
||||
self.write.write_var_int(&variant_index.into())?;
|
||||
self.write
|
||||
.write_var_int(&variant_index.try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", variant_index))
|
||||
})?)?;
|
||||
Ok(self)
|
||||
}
|
||||
fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
@@ -194,7 +400,10 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
_variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
// For ENUMs, only write enum index as varint
|
||||
self.write.write_var_int(&variant_index.into())
|
||||
self.write
|
||||
.write_var_int(&variant_index.try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", variant_index))
|
||||
})?)
|
||||
}
|
||||
fn is_human_readable(&self) -> bool {
|
||||
false
|
||||
|
||||
@@ -48,7 +48,7 @@ pub async fn send_c_commands_packet(player: &Arc<Player>, dispatcher: &CommandDi
|
||||
let mut proto_nodes = Vec::new();
|
||||
let root_node_index = root.build(&mut proto_nodes);
|
||||
|
||||
let packet = CCommands::new(proto_nodes, root_node_index.into());
|
||||
let packet = CCommands::new(proto_nodes.into(), root_node_index.try_into().unwrap());
|
||||
player.client.enqueue_packet(&packet).await;
|
||||
}
|
||||
|
||||
@@ -63,12 +63,12 @@ impl<'a> ProtoNodeBuilder<'a> {
|
||||
let mut children = Vec::new();
|
||||
for node in self.child_nodes {
|
||||
let i = node.build(buffer);
|
||||
children.push(i.into());
|
||||
children.push(i.try_into().unwrap());
|
||||
}
|
||||
|
||||
let i = buffer.len();
|
||||
buffer.push(ProtoNode {
|
||||
children,
|
||||
children: children.into(),
|
||||
node_type: self.node_type,
|
||||
});
|
||||
i
|
||||
|
||||
@@ -4,9 +4,10 @@ use crossbeam::atomic::AtomicCell;
|
||||
use pumpkin_data::damage::DamageType;
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
|
||||
// TODO: This entire thing should be atomic, not individual fields
|
||||
pub struct HungerManager {
|
||||
/// The current hunger level.
|
||||
pub level: AtomicCell<u32>,
|
||||
pub level: AtomicCell<u8>,
|
||||
/// The food saturation level.
|
||||
pub saturation: AtomicCell<f32>,
|
||||
pub exhaustion: AtomicCell<f32>,
|
||||
@@ -67,8 +68,10 @@ impl HungerManager {
|
||||
|
||||
#[async_trait]
|
||||
impl NBTStorage for HungerManager {
|
||||
// TODO: Proper value checks
|
||||
|
||||
async fn write_nbt(&self, nbt: &mut NbtCompound) {
|
||||
nbt.put_int("foodLevel", self.level.load() as i32);
|
||||
nbt.put_int("foodLevel", self.level.load().into());
|
||||
nbt.put_float("foodSaturationLevel", self.saturation.load());
|
||||
nbt.put_float("foodExhaustionLevel", self.exhaustion.load());
|
||||
nbt.put_int("foodTickTimer", self.tick_timer.load() as i32);
|
||||
@@ -76,7 +79,7 @@ impl NBTStorage for HungerManager {
|
||||
|
||||
async fn read_nbt(&mut self, nbt: &mut NbtCompound) {
|
||||
self.level
|
||||
.store(nbt.get_int("foodLevel").unwrap_or(20) as u32);
|
||||
.store(nbt.get_int("foodLevel").unwrap_or(20) as u8);
|
||||
self.saturation
|
||||
.store(nbt.get_float("foodSaturationLevel").unwrap_or(5.0));
|
||||
self.exhaustion
|
||||
|
||||
@@ -144,7 +144,7 @@ impl EntityBase for ItemEntity {
|
||||
.enqueue_packet(&CTakeItemEntity::new(
|
||||
self.entity.entity_id.into(),
|
||||
player.entity_id().into(),
|
||||
total_pick_up.into(),
|
||||
total_pick_up.try_into().unwrap(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ impl LivingEntity {
|
||||
.broadcast_packet_all(&CTakeItemEntity::new(
|
||||
item.entity_id.into(),
|
||||
self.entity.entity_id.into(),
|
||||
stack_amount.into(),
|
||||
stack_amount.try_into().unwrap(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ impl Entity {
|
||||
self.world
|
||||
.read()
|
||||
.await
|
||||
.broadcast_packet_all(&CSetEntityMetadata::new(self.entity_id.into(), buf))
|
||||
.broadcast_packet_all(&CSetEntityMetadata::new(self.entity_id.into(), buf.into()))
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{
|
||||
ops::AddAssign,
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32, Ordering},
|
||||
atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU8, AtomicU32, Ordering},
|
||||
},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
@@ -220,7 +220,7 @@ pub struct Player {
|
||||
/// The player's last known experience level.
|
||||
pub last_sent_xp: AtomicI32,
|
||||
pub last_sent_health: AtomicI32,
|
||||
pub last_sent_food: AtomicU32,
|
||||
pub last_sent_food: AtomicU8,
|
||||
pub last_food_saturation: AtomicBool,
|
||||
/// The player's permission level.
|
||||
pub permission_lvl: AtomicCell<PermissionLvl>,
|
||||
@@ -319,7 +319,7 @@ impl Player {
|
||||
chunk_manager: Mutex::new(ChunkManager::new(16)),
|
||||
last_sent_xp: AtomicI32::new(-1),
|
||||
last_sent_health: AtomicI32::new(-1),
|
||||
last_sent_food: AtomicU32::new(0),
|
||||
last_sent_food: AtomicU8::new(0),
|
||||
last_food_saturation: AtomicBool::new(true),
|
||||
has_played_before: AtomicBool::new(false),
|
||||
chat_session: Arc::new(Mutex::new(ChatSession::default())), // Placeholder value until the player actually sets their session id
|
||||
@@ -520,7 +520,7 @@ impl Player {
|
||||
) {
|
||||
self.client
|
||||
.enqueue_packet(&CSoundEffect::new(
|
||||
IdOr::Id(u32::from(sound_id)),
|
||||
IdOr::Id(sound_id),
|
||||
category,
|
||||
position,
|
||||
volume,
|
||||
@@ -581,7 +581,7 @@ impl Player {
|
||||
self.client.send_packet_now(&CChunkData(&chunk)).await;
|
||||
}
|
||||
self.client
|
||||
.send_packet_now(&CChunkBatchEnd::new(chunk_count))
|
||||
.send_packet_now(&CChunkBatchEnd::new(chunk_count as u16))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1232,7 +1232,7 @@ impl Player {
|
||||
pub async fn send_message(
|
||||
&self,
|
||||
message: &TextComponent,
|
||||
chat_type: u32,
|
||||
chat_type: u8,
|
||||
sender_name: &TextComponent,
|
||||
target_name: Option<&TextComponent>,
|
||||
) {
|
||||
|
||||
@@ -75,7 +75,7 @@ impl Player {
|
||||
inventory.increment_state_id();
|
||||
let packet = CSetContainerContent::new(
|
||||
id.into(),
|
||||
(inventory.state_id).into(),
|
||||
(inventory.state_id).try_into().unwrap(),
|
||||
&slots,
|
||||
&carried_item,
|
||||
);
|
||||
|
||||
@@ -7,7 +7,6 @@ use pumpkin_protocol::{
|
||||
config::{CConfigAddResourcePack, CConfigServerLinks, CKnownPacks, CUpdateTags},
|
||||
login::{CLoginSuccess, CSetCompression},
|
||||
},
|
||||
codec::var_int::VarInt,
|
||||
server::login::{SEncryptionResponse, SLoginCookieResponse, SLoginPluginResponse, SLoginStart},
|
||||
};
|
||||
use pumpkin_util::text::TextComponent;
|
||||
@@ -247,8 +246,10 @@ impl Client {
|
||||
async fn enable_compression(&self) {
|
||||
let compression = advanced_config().networking.packet_compression.info.clone();
|
||||
// We want to wait until we have sent the compression packet to the client
|
||||
self.send_packet_now(&CSetCompression::new(compression.threshold.into()))
|
||||
.await;
|
||||
self.send_packet_now(&CSetCompression::new(
|
||||
compression.threshold.try_into().unwrap(),
|
||||
))
|
||||
.await;
|
||||
self.set_compression(compression).await;
|
||||
}
|
||||
|
||||
@@ -340,15 +341,11 @@ impl Client {
|
||||
self.send_packet_now(&server.get_branding()).await;
|
||||
|
||||
if advanced_config().server_links.enabled {
|
||||
self.send_packet_now(&CConfigServerLinks::new(
|
||||
&VarInt(LINKS.len() as i32),
|
||||
&LINKS,
|
||||
))
|
||||
.await;
|
||||
self.send_packet_now(&CConfigServerLinks::new(&LINKS)).await;
|
||||
}
|
||||
|
||||
// TODO: Is this the right place to send them?
|
||||
// Send tags.
|
||||
// TODO: Is this the right place to send them?
|
||||
|
||||
self.send_packet_now(&CUpdateTags::new(&[
|
||||
pumpkin_data::tag::RegistryKey::Block,
|
||||
|
||||
@@ -1593,9 +1593,9 @@ impl Player {
|
||||
|
||||
let response = CCommandSuggestions::new(
|
||||
packet.id,
|
||||
(last_word_start + 2).into(),
|
||||
(cmd.len() - last_word_start - 1).into(),
|
||||
suggestions,
|
||||
(last_word_start + 2).try_into().unwrap(),
|
||||
(cmd.len() - last_word_start - 1).try_into().unwrap(),
|
||||
suggestions.into(),
|
||||
);
|
||||
|
||||
self.client.enqueue_packet(&response).await;
|
||||
|
||||
@@ -344,7 +344,7 @@ impl Server {
|
||||
&self,
|
||||
message: &TextComponent,
|
||||
sender_name: &TextComponent,
|
||||
chat_type: u32,
|
||||
chat_type: u8,
|
||||
target_name: Option<&TextComponent>,
|
||||
) {
|
||||
send_cancellable! {{
|
||||
|
||||
@@ -207,7 +207,7 @@ impl World {
|
||||
&self,
|
||||
message: &TextComponent,
|
||||
sender_name: &TextComponent,
|
||||
chat_type: u32,
|
||||
chat_type: u8,
|
||||
target_name: Option<&TextComponent>,
|
||||
) {
|
||||
self.broadcast_packet_all(&CDisguisedChatMessage::new(
|
||||
@@ -320,14 +320,7 @@ impl World {
|
||||
pitch: f32,
|
||||
) {
|
||||
let seed = thread_rng().r#gen::<f64>();
|
||||
let packet = CSoundEffect::new(
|
||||
IdOr::Id(u32::from(sound_id)),
|
||||
category,
|
||||
position,
|
||||
volume,
|
||||
pitch,
|
||||
seed,
|
||||
);
|
||||
let packet = CSoundEffect::new(IdOr::Id(sound_id), category, position, volume, pitch, seed);
|
||||
self.broadcast_packet_all(&packet).await;
|
||||
}
|
||||
|
||||
@@ -518,7 +511,7 @@ impl World {
|
||||
entity_id,
|
||||
base_config.hardcore,
|
||||
&dimensions,
|
||||
base_config.max_players.into(),
|
||||
base_config.max_players.try_into().unwrap(),
|
||||
base_config.view_distance.get().into(), // TODO: view distance
|
||||
base_config.simulation_distance.get().into(), // TODO: sim view dinstance
|
||||
false,
|
||||
@@ -811,7 +804,7 @@ impl World {
|
||||
} else {
|
||||
Particle::ExplosionEmitter
|
||||
};
|
||||
let sound = IdOr::<SoundEvent>::Id(Sound::EntityGenericExplode as u32);
|
||||
let sound = IdOr::<SoundEvent>::Id(Sound::EntityGenericExplode as u16);
|
||||
for (_, player) in self.players.read().await.iter() {
|
||||
if player.position().squared_distance_to_vec(position) > 4096.0 {
|
||||
continue;
|
||||
@@ -1200,11 +1193,8 @@ impl World {
|
||||
.remove(&player.gameprofile.id)
|
||||
.unwrap();
|
||||
let uuid = player.gameprofile.id;
|
||||
self.broadcast_packet_except(
|
||||
&[player.gameprofile.id],
|
||||
&CRemovePlayerInfo::new(1.into(), &[uuid]),
|
||||
)
|
||||
.await;
|
||||
self.broadcast_packet_except(&[player.gameprofile.id], &CRemovePlayerInfo::new(&[uuid]))
|
||||
.await;
|
||||
self.broadcast_packet_all(&CRemoveEntities::new(&[player.entity_id().into()]))
|
||||
.await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user