aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs7
-rw-r--r--src/protocol.rs16
-rw-r--r--src/v1_19_3.rs529
3 files changed, 524 insertions, 28 deletions
diff --git a/src/lib.rs b/src/lib.rs
index ffba7ce..445a370 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,6 @@
-// #![cfg_attr(feature = "bench", feature(test))]
-#![feature(test)]
-// #![cfg_attr(feature = "gat", feature(generic_associated_types))]
-// #![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(feature = "bench", feature(test))]
+#![cfg_attr(feature = "gat", feature(generic_associated_types))]
+#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
diff --git a/src/protocol.rs b/src/protocol.rs
index 0b3e4c1..c9d81c2 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -203,7 +203,7 @@ macro_rules! proto_struct {
}
};
($bodyt: ident $(<$($g: ident),*>)? {
- $($fname: ident: $ftyp: ty ),+
+ $($fname: ident: $ftyp: ty ),+ $(,)?
}) => {
$crate::as_item! {
#[derive(Debug, Clone, PartialEq)]
@@ -257,7 +257,7 @@ macro_rules! proto_struct {
macro_rules! define_protocol {
($version: literal, $packett: ident, $rawpackett: ident, $rawdt: ident, $kindt: ident => {
$($nam: ident, $id: literal, $state: ident, $direction: ident => $body: ident {
- $($fnam: ident: $ftyp: ty),* }),*
+ $($fnam: ident: $ftyp: ty),* $(,)?}),* $(,)?
}
) => {
$crate::as_item! {
@@ -494,7 +494,7 @@ macro_rules! instead_of_ident {
#[macro_export]
macro_rules! proto_enum_with_type {
- ($typ: ty, $typname: ident, $(($bval: literal, $nam: ident $(($bod: ty))?)),*) => {
+ ($typ: ty, $typname: ident, $(($bval: literal, $nam: ident $(($bod: ty))?)),* $(,)?) => {
$crate::as_item! {
#[derive(PartialEq, Clone, Debug)]
pub enum $typname {
@@ -578,28 +578,28 @@ macro_rules! proto_enum_with_type {
#[macro_export]
macro_rules! proto_byte_enum {
- ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => {
+ ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),* $(,)?) => {
proto_enum_with_type!(u8, $typname, $(($bval, $nam $(($bod))?)),*);
}
}
#[macro_export]
macro_rules! proto_varint_enum {
- ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => {
+ ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),* $(,)?) => {
proto_enum_with_type!(VarInt, $typname, $(($bval, $nam $(($bod))?)),*);
}
}
#[macro_export]
macro_rules! proto_int_enum {
- ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => {
+ ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),* $(,)?) => {
proto_enum_with_type!(i32, $typname, $(($bval, $nam $(($bod))?)),*);
}
}
#[macro_export]
macro_rules! proto_str_enum {
- ($typname: ident, $($sval: literal :: $nam: ident $(($bod: ident))?),*) => {
+ ($typname: ident, $($sval: literal :: $nam: ident $(($bod: ident))?),* $(,)?) => {
crate::as_item! {
#[derive(PartialEq, Clone, Debug)]
pub enum $typname {
@@ -689,7 +689,7 @@ macro_rules! proto_str_enum {
#[macro_export]
macro_rules! proto_byte_flag {
- ($typname: ident, $($bval: literal :: $isnam: ident $setnam: ident),*) => {
+ ($typname: ident, $($bval: literal :: $isnam: ident $setnam: ident),* $(,)?) => {
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct $typname(pub u8);
diff --git a/src/v1_19_3.rs b/src/v1_19_3.rs
index ee51d04..5495c3d 100644
--- a/src/v1_19_3.rs
+++ b/src/v1_19_3.rs
@@ -1,17 +1,15 @@
use alloc::{
borrow::ToOwned,
- string::{String, ToString},
- vec::Vec,
+ string::String,
};
use alloc::fmt;
use fmt::Debug;
use crate::{*, types::*, uuid::*};
-pub use crate::v1_19::CommandNode;
#[cfg(all(test, feature = "std"))]
use crate::protocol::TestRandom;
-define_protocol!(760, Packet760, RawPacket760, RawPacket760Body, Packet760Kind => {
+define_protocol!(761, Packet761, RawPacket761, RawPacket761Body, Packet761Kind => {
// Handshaking
Handshake, 0x00, Handshaking, ServerBound => HandshakeSpec {
version: VarInt,
@@ -137,14 +135,16 @@ define_protocol!(760, Packet760, RawPacket760, RawPacket760Body, Packet760Kind =
ClearTitles, 0x0C, Play, ClientBound => ClearTitlesSpec {
reset: bool
},
+ /*
CommandSuggestionResponse, 0x0D, Play, ClientBound => CommandSuggestionResponseSpec {
transaction_id: VarInt,
start: VarInt,
length: VarInt,
suggestions: CountedArray<CommandSuggestion, VarInt>
},
+ */
Commands, 0x0E, Play, ClientBound => CommandsSpec {
- nodes: CountedArray<CommandNode, VarInt>,
+ nodes: CountedArray<CommandNodeSpec, VarInt>,
root_index: VarInt
},
CloseContainer, 0x0F, Play, ClientBound => CloseContainerSpec {
@@ -215,31 +215,528 @@ define_protocol!(760, Packet760, RawPacket760, RawPacket760Body, Packet760Kind =
entity_id: i32
},
InitializeWorldBorder, 0x1E, Play, ClientBound => InitializeWorldBorderSpec {
- x: f32,
- z: f32,
- old_diameter: f32,
- new_diameter: f32,
+ x: f64,
+ z: f64,
+ old_diameter: f64,
+ new_diameter: f64,
speed: VarLong,
portal_teleport_boundary: VarInt,
warning_blocks: VarInt,
warning_time: VarInt
},
- KeepAlive, 0x1f, Play, ClientBound => KeepAliveSpec {
+ KeepAliveClientBound, 0x1f, Play, ClientBound => KeepAliveClientBoundSpec {
keep_alive_id: i64
},
ChunkDataAndUpdateLight, 0x20, Play, ClientBound => ChunkDataAndUpdateLightSpec {
chunk_x: i32,
chunk_z: i32,
- heightmaps: NamedNbtTag,
- chunk_data: CountedArray<u8, VarInt>,
- block_entities: CountedArray<BlockEntity, VarInt>,
- trust_edges: bool // TODO: HEEELP
- }
+ chunk_data: ChunkDataSpec,
+ light_data: LightDataSpec,
+ },
+ // TODO 0x21 - 0x23
+ LoginPlay, 0x24, Play, ClientBound => LoginPlaySpec {
+ entity_id: i32,
+ is_hardcore: bool,
+ gamemode: GameMode,
+ previous_gamemode: PreviousGameMode,
+ dimension_names: CountedArray<String, VarInt>,
+ registry_codex: NamedNbtTag,
+ dimension_type: String,
+ dimension_name: String,
+ hashed_seed: u64,
+ max_players: VarInt,
+ view_distance: VarInt,
+ simulation_distance: VarInt,
+ reduced_debug_info: bool,
+ enable_respawn_screen: bool,
+ is_debug: bool,
+ is_flat: bool,
+ death_location: Option<DeathLocation>,
+ },
+ // TODO 0x25 - 0x48
+ SynchronizePlayerPosition, 0x38, Play, ClientBound => SynchronizePlayerPositionSpec {
+ position: Vec3<f64>,
+ yaw: f32,
+ pitch: f32,
+ flags: SynchronizePlayerPositionFlags,
+ teleport_id: VarInt,
+ dismount_vehicle: bool
+ },
+ UpdateRecipeBook, 0x39, Play, ClientBound => UpdateRecipeBookSpec {
+ action: RecipeBookAction,
+ },
+ // TODO missing recipe
+
+
+ SetCenterChunk, 0x4A, Play, ClientBound => SetCenterChunkSpec {
+ chunk_x: VarInt,
+ chunk_z: VarInt,
+ },
+ SetDefaultSpawnPosition, 0x4C, Play, ClientBound => SetDefaultSpawnPositionSpec {
+ location: IntPosition,
+ angle: f32,
+ },
+
+ // TODO missing recipe
+
+ SetHeldItemClient, 0x49, Play, ClientBound => SetHeldItemClientSpec {
+ selected_slot: u8,
+ },
+ // TODO missing recipe
+ UpdateRecipes, 0x69, Play, ClientBound => UpdateRecipesSpec {
+ recipes: CountedArray<Recipe, VarInt>
+ },
+
+ UpdateTags, 0x6A, Play, ClientBound => UpdateTagsSpec {
+ tags: CountedArray<TypedTagList, VarInt>
+ },
+
+ // Play - ServerBound
+
+ // TODO 0x00 - 0x06
+
+ ClientInformation, 0x07, Play, ServerBound => ClientInformationSpec {
+ locale: String,
+ view_distance: u8,
+ chat_mode: ChatMode,
+ chat_colors: bool,
+ displayed_skin_parts: DisplayedSkinParts,
+ main_hand: MainHand,
+ enable_text_filtering: bool,
+ allow_server_listings: bool,
+ },
+ // TODO Missing packets
+ SetHeldItemServer, 0x28, Play, ServerBound => SetHeldItemServerSpec {
+ selected_slot: u8,
+ },
});
// Helper types
+proto_struct!(ChunkSection {
+ block_count: u16,
+ block_state: PalettedContainer,
+ biomes: PalettedContainer,
+});
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct PalettedContainer {
+ // TODO: global, linear and hashed palettes
+ pub singular_value: VarInt,
+}
+
+impl Serialize for PalettedContainer {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_byte(0)?;
+ to.serialize_other(&self.singular_value)?;
+ // Serialize 0 bit bitstorage
+ to.serialize_other(&BitSet::empty())?;
+ Ok(())
+ }
+}
+
+impl Deserialize for PalettedContainer {
+ fn mc_deserialize(_data: &[u8]) -> DeserializeResult<Self> {
+ Err(DeserializeErr::CannotUnderstandValue("Not implemented".into()))
+ }
+}
+
+
+pub struct BlobArray {
+ // TODO make this work same as bit storage with a const generic entry size
+ pub data: Vec<u64>,
+ entry_size: usize,
+}
+
+impl BlobArray {
+ pub fn new(entry_size: u8) -> Self {
+ BlobArray { entry_size: entry_size as usize, data: vec![] }
+ }
+
+ pub fn ensure_capacity(&mut self, index: usize) {
+ let entries_per_long = 64usize / self.entry_size;
+ let needed_length = index / entries_per_long + 1;
+ if self.data.len() < needed_length {
+ self.data.extend(vec![0u64; needed_length - self.data.len()]);
+ }
+ }
+
+ pub fn set_entry(&mut self, index: usize, value: u64) {
+ let entries_per_long = 64usize / self.entry_size;
+ let array_index = index / entries_per_long;
+ let position = index % entries_per_long;
+ let array_shift = 64 - (entries_per_long - position) * self.entry_size;
+ let mask = (1u64 << self.entry_size) - 1;
+ self.ensure_capacity(index);
+ self.data[array_index] |= (value & mask) << array_shift;
+ }
+
+ pub fn get_entry(&mut self, index: usize) -> u64 {
+ let entries_per_long = 64 / self.entry_size;
+ let array_index = index / entries_per_long;
+ let position = index % entries_per_long;
+ let array_shift = 64 - (entries_per_long - position) * self.entry_size;
+ let mask = (1u64 << self.entry_size) - 1;
+ self.ensure_capacity(index);
+ (self.data[array_index] >> array_shift) & mask
+ }
+}
+
+proto_struct!(BitSet {
+ data: CountedArray<u64, VarInt>,
+});
+
+impl BitSet {
+ pub fn empty() -> BitSet {
+ BitSet { data: vec![].into() }
+ }
+
+ pub fn is_bit_set(&self, index: usize) -> bool {
+ if index * 64 >= self.data.len() {
+ return false;
+ }
+ self.is_bit_set_unsafe(index)
+ }
+ pub fn ensure_capacity(&mut self, index: usize) {
+ let needed_length = index / 64 + 1;
+ let length_increase = needed_length - self.data.len();
+ if length_increase > 0 {
+ self.data.extend(vec![0u64; length_increase]);
+ }
+ }
+
+ pub fn is_bit_set_unsafe(&self, index: usize) -> bool {
+ self.data[index / 64] & (1u64 << (index % 64)) != 0
+ }
+
+ pub fn set_bit(&mut self, index: usize, value: bool) {
+ self.ensure_capacity(index);
+ self.set_bit_unsafe(index, value)
+ }
+
+ pub fn set_bit_unsafe(&mut self, index: usize, value: bool) {
+ if value {
+ self.data[index / 64] |= 1u64 << (index % 64);
+ } else {
+ self.data[index / 64] &= !(1u64 << (index % 64));
+ }
+ }
+}
+
+
+proto_struct!(LightDataSpec {
+ trust_edges: bool,
+ sky_y_mask: BitSet,
+ block_y_mask: BitSet,
+ empty_sky_y_mask: BitSet,
+ empty_block_y_mask: BitSet,
+ sky_updates: CountedArray<CountedArray<u8, VarInt>, VarInt>,
+ block_updates: CountedArray<CountedArray<u8, VarInt>, VarInt>,
+});
+proto_struct!(ChunkDataSpec {
+ heightmaps: NamedNbtTag,
+ buffer: CountedArray<u8, VarInt>,
+ block_entities: CountedArray<BlockEntity, VarInt>,
+});
+
+proto_byte_flag!(SynchronizePlayerPositionFlags,
+ 0x01 :: is_x_relative set_x_relative,
+ 0x02 :: is_y_relative set_y_relative,
+ 0x04 :: is_z_relative set_z_relative,
+ 0x08 :: is_y_rot_relative set_y_rot_relative,
+ 0x10 :: is_x_rot_relative set_x_rot_relative,
+);
+
+proto_varint_enum!(RecipeBookAction,
+ 0 :: Init(RecipeBookInitSpec),
+ 1 :: Add(RecipeBookDiffSpec),
+ 2 :: Remove(RecipeBookDiffSpec),
+);
+
+proto_struct!(RecipeBookInitSpec {
+ book_settings: BookSettings,
+ known_recipes: CountedArray<String, VarInt>,
+ highlighted_recipes: CountedArray<String, VarInt>,
+});
+proto_struct!(RecipeBookDiffSpec {
+ book_settings: BookSettings,
+ to_add_or_remove: CountedArray<String, VarInt>,
+});
+proto_struct!(BookSettings {
+ crafting: BookSetting,
+ smelting: BookSetting,
+ blast_furnace: BookSetting,
+ smoker: BookSetting,
+});
+impl Default for BookSettings {
+ fn default() -> Self {
+ return BookSettings {
+ crafting: BookSetting::default(),
+ smelting: BookSetting::default(),
+ blast_furnace: BookSetting::default(),
+ smoker: BookSetting::default(),
+ };
+ }
+}
+
+proto_struct!(BookSetting {
+ open: bool,
+ filter_active: bool,
+});
+
+impl Default for BookSetting {
+ fn default() -> Self {
+ return BookSetting { open: false, filter_active: false };
+ }
+}
+
+proto_str_enum!(TagType,
+ "minecraft:block" :: Block,
+ "minecraft:item" :: Item,
+ "minecraft:fluid" :: Fluid,
+ "minecraft:entity_type" :: EntityType,
+ "minecraft:game_event" :: GameEvent,
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct CommandNodeSpec {
+ pub children_indices: CountedArray<VarInt, VarInt>,
+ pub redirect_node: Option<VarInt>,
+ pub is_executable: bool,
+ pub node: CommandNode,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum CommandNode {
+ Root,
+ Argument(CommandArgumentNodeSpec),
+ Literal(CommandLiteralNodeSpec),
+}
+
+proto_struct!(CommandLiteralNodeSpec {
+ name: String
+});
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct CommandArgumentNodeSpec {
+ name: String,
+ parser_id: VarInt,
+ properties: CommandNodeProperties,
+ suggestions_types: Option<SuggestionsTypeSpec>,
+}
+
+impl Serialize for CommandArgumentNodeSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_other(&self.name)?;
+ to.serialize_other(&self.parser_id)?;
+ to.serialize_other(&self.properties)?;
+ if let Some(body) = &self.suggestions_types {
+ to.serialize_other(body)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl CommandArgumentNodeSpec {
+ fn mc_deserialize(has_suggestions: bool, data: &[u8]) -> DeserializeResult<Self> {
+ let Deserialized { value: name, data } = String::mc_deserialize(data)?;
+ let Deserialized { value: parser_id, data } = VarInt::mc_deserialize(data)?;
+ let Deserialized { value: properties, data } = CommandNodeProperties::mc_deserialize(data)?;
+ let (suggestions_types, data) = if has_suggestions {
+ let Deserialized { value: suggestions_types, data } = SuggestionsTypeSpec::mc_deserialize(data)?;
+ (Some(suggestions_types), data)
+ } else {
+ (None, data)
+ };
+ Deserialized::ok(
+ Self {
+ name,
+ parser_id,
+ properties,
+ suggestions_types,
+ },
+ data,
+ )
+ }
+}
+proto_str_enum!(SuggestionsTypeSpec,
+ "minecraft:ask_server" :: AskServer,
+ "minecraft:all_recipes" :: AllRecipes,
+ "minecraft:available_sounds" :: AvailableSounds,
+ "minecraft:available_bioms" :: AvailableBiomes,
+ "minecraft:summonable_entities" :: SummonableEntities,
+);
+
+proto_varint_enum!(CommandNodeProperties,
+ 0 :: Bool,
+);
+
+
+impl Serialize for CommandNodeSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let mut flags = 0u8;
+ use CommandNode::*;
+ flags |= match &self.node {
+ Root => 0x00,
+ Argument(_) => 0x1,
+ Literal(_) => 0x2,
+ };
+
+ if self.is_executable {
+ flags |= 0x04;
+ }
+ if self.redirect_node.is_some() {
+ flags |= 0x08;
+ }
+
+ if let Argument(argument_data) = &self.node {
+ if argument_data.suggestions_types.is_some() {
+ flags |= 0x10;
+ }
+ }
+
+ to.serialize_byte(flags)?;
+ to.serialize_other(&self.children_indices)?;
+ if let Some(redirect_node) = &self.redirect_node {
+ to.serialize_other(redirect_node)?;
+ }
+ match &self.node {
+ Root => Ok(()),
+ Argument(body) => to.serialize_other(body),
+ Literal(body) => to.serialize_other(body)
+ }
+ }
+}
+
+impl Deserialize for CommandNodeSpec {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<Self> {
+ let Deserialized { value: flags, data } = u8::mc_deserialize(data)?;
+ let Deserialized {
+ value: children_indices,
+ data,
+ } = <CountedArray<VarInt, VarInt>>::mc_deserialize(data)?;
+ let is_executable = flags & 0x04 != 0;
+ let has_redirect = flags & 0x08 != 0;
+ let (redirect_node, data) = if has_redirect {
+ let Deserialized {
+ value: redirect_node,
+ data,
+ } = VarInt::mc_deserialize(data)?;
+ (Some(redirect_node), data)
+ } else {
+ (None, data)
+ };
+ use CommandNode::*;
+
+ let Deserialized { value: node, data } = match flags & 0x03 {
+ 0x00 => Deserialized::ok(Root, data),
+ 0x01 => {
+ Ok(CommandLiteralNodeSpec::mc_deserialize(data)?.map(move |body| Literal(body)))
+ }
+ 0x02 => Ok(
+ CommandArgumentNodeSpec::mc_deserialize(flags & 0x10 != 0, data)?
+ .map(move |body| Argument(body)),
+ ),
+ _ => Err(DeserializeErr::CannotUnderstandValue(
+ format!("Cannot understand {} as command node type", flags))),
+ }?;
+
+ Deserialized::ok(
+ Self {
+ children_indices,
+ redirect_node,
+ is_executable,
+ node,
+ },
+ data,
+ )
+ }
+}
+
+
+proto_struct!(TypedTagList {
+ tag_type: TagType,
+ tags: CountedArray<TagSpec, VarInt>
+});
+
+proto_struct!(TagSpec {
+ name: String,
+ entries: CountedArray<VarInt, VarInt>
+});
+
+proto_str_enum!(Recipe,
+ "TODO" :: Todo
+);
+
+proto_varint_enum!(MainHand,
+ 0 :: Left,
+ 1 :: Right,
+);
+
+proto_byte_flag!(DisplayedSkinParts,
+ 0x01 :: is_cape_enabled set_cape_enabled,
+ 0x02 :: is_jacket_enabled set_jacket_enabled,
+ 0x04 :: is_left_sleeve_enabled set_left_sleeve_enabled,
+ 0x08 :: is_right_sleeve_enabled set_right_sleeve_enabled,
+ 0x10 :: is_left_pants_leg_enabled set_left_pants_leg_enabled,
+ 0x20 :: is_right_pants_leg_enabled set_right_pants_leg_enabled,
+ 0x40 :: is_hat_enabled set_hat_enabled,
+);
+
+proto_varint_enum!(ChatMode,
+ 0 :: Enabled,
+ 1 :: CommandsOnly,
+ 2 :: Hidden,
+);
+proto_struct!(DeathLocation {
+ death_dimension_name: String,
+ death_location: IntPosition
+});
+
+proto_byte_enum!(GameMode,
+ 0 :: Survival,
+ 1 :: Creative,
+ 2 :: Adventure,
+ 3 :: Spectator,
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum PreviousGameMode {
+ NoPrevious,
+ Previous(GameMode),
+}
+
+impl PreviousGameMode {
+ pub fn id(&self) -> i8 {
+ use PreviousGameMode::*;
+ match self {
+ NoPrevious => -1,
+ Previous(mode) => mode.id() as i8,
+ }
+ }
+}
+
+impl Serialize for PreviousGameMode {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_byte(self.id() as u8)
+ }
+}
+
+impl Deserialize for PreviousGameMode {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: id, data } = i8::mc_deserialize(data)?;
+
+ use PreviousGameMode::*;
+ match id {
+ -1 => Deserialized::ok(NoPrevious, data),
+ other => {
+ Ok(GameMode::deserialize_with_id(other as u8, data)?.map(move |gm| Previous(gm)))
+ }
+ }
+ }
+}
proto_struct!(BlockEntity {
packed_xz: u8,
y: i16,
@@ -333,7 +830,7 @@ proto_varint_enum!(BossBarColor,
5 :: Purple,
6 :: White
);
-proto_varint_enum!(BossBarDivison,
+proto_varint_enum!(BossBarDivision,
0 :: NoDivision,
1 :: SixNotches,
2 :: TenNotches,