aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBennovanDorst <bennovandorst@gmail.com>2022-07-12 02:41:55 +0200
committerBennovanDorst <bennovandorst@gmail.com>2022-07-12 02:41:55 +0200
commitd3c73ebe514e4754a3b6f2e1a927d357f435725a (patch)
treec2a67f53f1bd932f9ec610226321d9fc08951e60
parentc76a1c67c5fd91bbd78b9c46471160321ca12af0 (diff)
downloadmcproto-rs-d3c73ebe514e4754a3b6f2e1a927d357f435725a.tar.gz
mcproto-rs-d3c73ebe514e4754a3b6f2e1a927d357f435725a.tar.bz2
mcproto-rs-d3c73ebe514e4754a3b6f2e1a927d357f435725a.zip
[🎉] Added 1.19
-rw-r--r--src/lib.rs2
-rw-r--r--src/v1_19.rs5078
2 files changed, 5080 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index fba77bc..5cd124e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,6 +26,8 @@ pub mod v1_16_3;
pub mod v1_17_0;
#[cfg(feature = "v1_17_1")]
pub mod v1_17_1;
+#[cfg(feature = "v1_19")]
+pub mod v1_19;
pub use deserialize::*;
pub use serialize::*;
diff --git a/src/v1_19.rs b/src/v1_19.rs
new file mode 100644
index 0000000..ae5cb3a
--- /dev/null
+++ b/src/v1_19.rs
@@ -0,0 +1,5078 @@
+use crate::{types::*, uuid::*, *};
+use alloc::fmt;
+use alloc::{
+ borrow::ToOwned,
+ // boxed::Box,
+ string::{String, ToString},
+ vec::Vec,
+};
+use fmt::Debug;
+
+#[cfg(all(test, feature = "std"))]
+use crate::protocol::TestRandom;
+
+define_protocol!(759, Packet759, RawPacket759, RawPacket759Body, Packet759Kind => {
+ // handshaking
+ Handshake, 0x00, Handshaking, ServerBound => HandshakeSpec {
+ version: VarInt,
+ server_address: String,
+ server_port: u16,
+ next_state: HandshakeNextState
+ },
+
+ // status
+ StatusRequest, 0x00, Status, ServerBound => StatusRequestSpec {},
+ StatusPing, 0x01, Status, ServerBound => StatusPingSpec {
+ payload: i64
+ },
+ StatusResponse, 0x00, Status, ClientBound => StatusResponseSpec {
+ response: super::status::StatusSpec
+ },
+ StatusPong, 0x01, Status, ClientBound => StatusPongSpec {
+ payload: i64
+ },
+
+ // login
+ LoginDisconnect, 0x00, Login, ClientBound => LoginDisconnectSpec {
+ message: Chat
+ },
+ LoginEncryptionRequest, 0x01, Login, ClientBound => LoginEncryptionRequestSpec {
+ server_id: String,
+ public_key: CountedArray<u8, VarInt>,
+ verify_token: CountedArray<u8, VarInt>
+ },
+ LoginSuccess, 0x02, Login, ClientBound => LoginSuccessSpec {
+ uuid: UUID4,
+ username: String
+ },
+ LoginSetCompression, 0x03, Login, ClientBound => LoginSetCompressionSpec {
+ threshold: VarInt
+ },
+ LoginPluginRequest, 0x04, Login, ClientBound => LoginPluginRequestSpec {
+ message_id: VarInt,
+ channel: String,
+ data: RemainingBytes
+ },
+ LoginStart, 0x00, Login, ServerBound => LoginStartSpec {
+ name: String
+ },
+ LoginEncryptionResponse, 0x01, Login, ServerBound => LoginEncryptionResponseSpec {
+ shared_secret: CountedArray<u8, VarInt>,
+ verify_token: CountedArray<u8, VarInt>
+ },
+ LoginPluginResponse, 0x02, Login, ServerBound => LoginPluginResponseSpec {
+ message_id: VarInt,
+ successful: bool,
+ data: RemainingBytes
+ },
+
+ // play
+ // client bound
+ PlaySpawnEntity, 0x00, Play, ClientBound => PlaySpawnEntitySpec {
+ entity_id: VarInt,
+ object_uuid: UUID4,
+ entity_type: VarInt,
+ position: Vec3<f64>,
+ pitch: Angle,
+ yaw: Angle,
+ data: i32,
+ velocity: Vec3<i16>
+ },
+ PlaySpawnExperienceOrb, 0x01, Play, ClientBound => PlaySpawnExperienceOrbSpec {
+ entity_id: VarInt,
+ position: Vec3<f64>,
+ count: i16
+ },
+ PlaySpawnLivingEntity, 0x02, Play, ClientBound => PlaySpawnLivingEntitySpec {
+ entity_id: VarInt,
+ entity_uuid: UUID4,
+ entity_type: VarInt,
+ location: EntityLocation<f64, Angle>,
+ head_pitch: Angle,
+ velocity: Vec3<i16>
+ },
+ PlaySpawnPainting, 0x03, Play, ClientBound => PlaySpawnPaintingSpec {
+ entity_id: VarInt,
+ entity_uuid: UUID4,
+ motive: VarInt,
+ location: IntPosition,
+ direction: CardinalDirection
+ },
+ PlaySpawnPlayer, 0x04, Play, ClientBound => PlaySpawnPlayerSpec {
+ entity_id: VarInt,
+ uuid: UUID4,
+ location: EntityLocation<f64, Angle>
+ },
+ PlaySculkVibrationSignal, 0x05, Play, ClientBound => PlaySculkVibrationSignalSpec {
+ source_position: IntPosition,
+ destination: SculkDestinationIdentifier,
+ arrival_ticks: VarInt
+ },
+ PlayEntityAnimation, 0x06, Play, ClientBound => PlayEntityAnimationSpec {
+ entity_id: VarInt,
+ animation: EntityAnimationKind
+ },
+ PlayStatistics, 0x07, Play, ClientBound => PlayStatisticsSpec {
+ entries: CountedArray<Statistic, VarInt>
+ },
+ PlayAcknowledgePlayerDigging, 0x08, Play, ClientBound => PlayAcknowledgePlayerDiggingSpec {
+ location: IntPosition,
+ block: VarInt,
+ status: DiggingStatus,
+ successful: bool
+ },
+ PlayBlockBreakAnimation, 0x09, Play, ClientBound => PlayBlockBreakAnimationSpec {
+ entity_id: VarInt,
+ location: IntPosition,
+ destroy_stage: i8
+ },
+ PlayBlockEntityData, 0x0A, Play, ClientBound => PlayBlockEntityDataSpec {
+ location: IntPosition,
+ action: BlockEntityDataAction,
+ nbt_data: NamedNbtTag
+ },
+ PlayBlockAction, 0x0B, Play, ClientBound => PlayBlockActionSpec {
+ location: IntPosition,
+ action_id: u8,
+ action_payload: u8,
+ block_type: VarInt
+ },
+ PlayBlockChange, 0x0C, Play, ClientBound => PlayBlockChangeSpec {
+ location: IntPosition,
+ block_id: VarInt
+ },
+ PlayBossBar, 0x0D, Play, ClientBound => PlayBossBarSpec {
+ uuid: UUID4,
+ action: BossBarAction
+ },
+ PlayServerDifficulty, 0x0E, Play, ClientBound => PlayServerDifficultySpec {
+ difficulty: Difficulty,
+ locked: bool
+ },
+ PlayServerChatMessage, 0x0F, Play, ClientBound => PlayServerChatMessageSpec {
+ message: Chat,
+ position: ChatPosition,
+ sender: UUID4
+ },
+ PlayClearTitles, 0x10, Play, ClientBound => PlayClearTitlesSpec {
+ reset: bool
+ },
+ PlayTabComplete, 0x11, Play, ClientBound => PlayTabCompleteSpec {
+ id: VarInt,
+ start: VarInt,
+ length: VarInt,
+ matches: CountedArray<TabCompleteMatch, VarInt>
+ },
+ PlayDeclareCommands, 0x12, Play, ClientBound => PlayDeclareCommandsSpec {
+ nodes: CountedArray<CommandNodeSpec, VarInt>,
+ root_index: VarInt
+ },
+ PlayServerCloseWindow, 0x13, Play, ClientBound => PlayServerCloseWindowSpec {
+ window_id: u8
+ },
+ PlayWindowItems, 0x14, Play, ClientBound => PlayWindowItemsSpec {
+ window_id: u8,
+ state_id: VarInt,
+ slots: CountedArray<Slot, VarInt>,
+ carried_item: Slot
+ },
+ PlayWindowProperty, 0x15, Play, ClientBound => PlayWindowPropertySpec {
+ window_id: u8,
+ property: i16,
+ value: i16
+ },
+ PlaySetSlot, 0x16, Play, ClientBound => PlaySetSlotSpec {
+ window_id: u8,
+ slot: i16,
+ slot_data: Slot
+ },
+ PlaySetCooldown, 0x17, Play, ClientBound => PlaySetCooldownSpec {
+ item_id: VarInt,
+ cooldown_ticks: VarInt
+ },
+ PlayServerPluginMessage, 0x18, Play, ClientBound => PlayServerPluginMessageSpec {
+ channel: String,
+ data: RemainingBytes
+ },
+ PlayNamedSoundEffect, 0x19, Play, ClientBound => PlayNamedSoundEffectSpec {
+ sound_name: String,
+ sound_category: SoundCategory,
+ position: Vec3<FixedInt>,
+ volume: f32,
+ pitch: f32
+ },
+ PlayDisconnect, 0x1A, Play, ClientBound => PlayDisconnectSpec {
+ reason: Chat
+ },
+ PlayEntityStatus, 0x1B, Play, ClientBound => PlayEntityStatusSpec {
+ entity_id: i32,
+ raw_status: u8 // todo deal with the gigantic table
+ },
+ PlayExplosion, 0x1C, Play, ClientBound => PlayExplosionSpec {
+ position: Vec3<f32>,
+ strength: f32,
+ records: CountedArray<Vec3<i8>, VarInt>,
+ player_motion: Vec3<f32>
+ },
+ PlayUnloadChunk, 0x1D, Play, ClientBound => PlayUnloadChunkSpec {
+ position: ChunkPosition<i32>
+ },
+ PlayChangeGameState, 0x1E, Play, ClientBound => PlayChangeGameStateSpec {
+ reason: GameChangeReason
+ },
+ PlayOpenHorseWindow, 0x1F, Play, ClientBound => PlayOpenHorseWindowSpec {
+ window_id: u8,
+ number_of_slots: VarInt,
+ entity_id: i32
+ },
+ PlayInitializeWorldBorder, 0x20, Play, ClientBound => PlayInitializeWorldBorderSpec {
+ x: f64,
+ z: f64,
+ old_diameter: f64,
+ new_diameter: f64,
+ speed: VarLong,
+ portal_teleport_boundary: VarInt,
+ warning_blocks: VarInt,
+ warning_time: VarInt
+ },
+ PlayServerKeepAlive, 0x21, Play, ClientBound => PlayServerKeepAliveSpec {
+ id: i64
+ },
+ PlayChunkData, 0x22, Play, ClientBound => PlayChunkDataWrapper {
+ x: i32,
+ z: i32,
+ primary_bit_mask: CountedArray<i64, VarInt>,
+ heightmaps: NamedNbtTag,
+ biomes: CountedArray<VarInt, VarInt>,
+ data: CountedArray<u8, VarInt>,
+ block_entities: CountedArray<NamedNbtTag, VarInt>
+ },
+ PlayEffect, 0x23, Play, ClientBound => PlayEffectSpec {
+ effect_id: EffectKind,
+ location: IntPosition,
+ data: i32,
+ disable_relative_volume: bool
+ },
+ PlayParticle, 0x24, Play, ClientBound => PlayParticleSpec {
+ particle_id: i32,
+ long_distance: bool,
+ position: Vec3<f64>,
+ offset: Vec3<f32>,
+ particle_data: i32,
+ data: RemainingBytes // todo
+ },
+ PlayUpdateLight, 0x25, Play, ClientBound => PlayUpdateLightSpec {
+ chunk: ChunkPosition<VarInt>,
+ trust_edges: bool,
+ sky_light_mask: CountedArray<i64, VarInt>,
+ block_light_mask: CountedArray<i64, VarInt>,
+ empty_sky_light_mask: CountedArray<i64, VarInt>,
+ empty_block_light_mask: CountedArray<i64, VarInt>,
+ sky_lights: CountedArray<CountedArray<i8, VarInt>, VarInt>,
+ block_lights: CountedArray<CountedArray<i8, VarInt>, VarInt>
+ },
+ PlayJoinGame, 0x26, Play, ClientBound => PlayJoinGameSpec {
+ entity_id: i32,
+ is_hardcore: bool,
+ gamemode: GameMode,
+ previous_gamemode: PreviousGameMode,
+ worlds: CountedArray<String, VarInt>,
+ dimension_codec: NamedNbtTag,
+ dimension: NamedNbtTag,
+ world_name: String,
+ hashed_seed: i64,
+ max_players: VarInt,
+ view_distance: VarInt,
+ reduced_debug_info: bool,
+ enable_respawn_screen: bool,
+ is_debug: bool,
+ is_flat: bool
+ },
+ PlayMapData, 0x27, Play, ClientBound => PlayMapDataSpec {
+ map_id: VarInt,
+ scale: i8,
+ locked: bool,
+ tracking_position: bool,
+ icons: CountedArray<MapIconSpec, VarInt>,
+ columns: MapColumns
+ },
+ PlayTradeList, 0x28, Play, ClientBound => PlayTradeListSpec {
+ window_id: VarInt,
+ trades: CountedArray<TradeSpec, i8>,
+ villager_level: VarInt,
+ experience: VarInt,
+ regular_villager: bool,
+ can_restock: bool
+ },
+ PlayEntityPosition, 0x29, Play, ClientBound => PlayEntityPositionSpec {
+ entity_id: VarInt,
+ delta: Vec3<i16>,
+ on_ground: bool
+ },
+ PlayEntityPositionAndRotation, 0x2A, Play, ClientBound => PlayEntityPositionAndRotationSpec {
+ entity_id: VarInt,
+ delta: EntityLocation<i16, Angle>,
+ on_ground: bool
+ },
+ PlayEntityRotation, 0x2B, Play, ClientBound => PlayEntityRotationSpec {
+ entity_id: VarInt,
+ rotation: EntityRotation<Angle>,
+ on_ground: bool
+ },
+ PlayServerVehicleMove, 0x2C, Play, ClientBound => PlayEntityVehicleMoveSpec {
+ location: EntityLocation<f64, f32>
+ },
+ PlayOpenBook, 0x2D, Play, ClientBound => PlayOpenBookSpec {
+ hand: Hand
+ },
+ PlayOpenWindow, 0x2E, Play, ClientBound => PlayOpenWindowSpec {
+ id: VarInt,
+ kind: WindowType,
+ title: Chat
+ },
+ PlayOpenSignEditor, 0x2F, Play, ClientBound => PlayOpenSignEditorSpec {
+ location: IntPosition
+ },
+ PlayPing, 0x30, Play, ClientBound => PlayPingSpec {
+ id: i32
+ },
+ PlayCraftRecipeResponse, 0x31, Play, ClientBound => PlayCraftRecipeResponseSpec {
+ window_id: u8, // TODO: should be i8?
+ recipe: String
+ },
+ PlayServerPlayerAbilities, 0x32, Play, ClientBound => PlayServerPlayerAbilitiesSpec {
+ flags: PlayerAbilityFlags,
+ flying_speed: f32,
+ field_of_view_modifier: f32
+ },
+ PlayEndCombatEvent, 0x33, Play, ClientBound => PlayEndCombatEventSpec {
+ duration_ticks: VarInt,
+ entity_id: i32
+ },
+ PlayEnterCombatEvent, 0x34, Play, ClientBound => PlayEnterCombatEventSpec {},
+ PlayDeathCombatEvent, 0x35, Play, ClientBound => PlayDeathCombatEventSpec {
+ player_id: VarInt,
+ entity_id: i32,
+ message: Chat
+ },
+ PlayPlayerInfo, 0x36, Play, ClientBound => PlayPlayerInfoSpec {
+ actions: PlayerInfoActionList
+ },
+ PlayFacePlayer, 0x37, Play, ClientBound => PlayFacePlayerSpec {
+ face_kind: FacePlayerKind,
+ target: Vec3<f64>,
+ entity: Option<FacePlayerEntityTarget>
+ },
+ PlayServerPlayerPositionAndLook, 0x38, Play, ClientBound => PlayServerPlayerPositionAndLookSpec {
+ location: EntityLocation<f64, f32>,
+ flags: PositionAndLookFlags,
+ teleport_id: VarInt,
+ dismount_vehicle: bool
+ },
+ PlayUnlockRecipes, 0x39, Play, ClientBound => PlayUnlockRecipesSpec {
+ action: RecipeUnlockAction,
+ crafting_book_open: bool,
+ crafting_book_active: bool,
+ smelting_book_open: bool,
+ smelting_book_active: bool,
+ blast_furnace_recipe_book_open: bool,
+ blast_furnace_recipe_book_active: bool,
+ smoke_recipe_book_open: bool,
+ smoke_recipe_book_active: bool,
+ recipe_ids: CountedArray<String, VarInt>,
+ other_recipe_ids: RemainingBytes // todo
+ },
+ PlayDestroyEntities, 0x3A, Play, ClientBound => PlayDestroyEntitySpec {
+ entity_ids: CountedArray<VarInt, VarInt>
+ },
+ PlayRemoveEntityEffect, 0x3B, Play, ClientBound => PlayRemoveEntityEffectSpec {
+ entity_id: VarInt,
+ effect: EntityEffectKind
+ },
+ PlayResourcePackSend, 0x3C, Play, ClientBound => PlayResourcePackSendSpec {
+ url: String,
+ hash: String,
+ forced: bool,
+ forced_message: Chat
+ },
+ PlayRespawn, 0x3D, Play, ClientBound => PlayRespawnSpec {
+ dimension: NamedNbtTag,
+ world_name: String,
+ hashed_seed: i64,
+ gamemode: GameMode,
+ previous_gamemode: GameMode,
+ is_debug: bool,
+ is_flat: bool,
+ copy_metadata: bool
+ },
+ PlayEntityHeadLook, 0x3E, Play, ClientBound => PlayEntityHeadLookSpec {
+ entity_id: VarInt,
+ head_yaw: Angle
+ },
+ PlayMultiBlockChange, 0x3F, Play, ClientBound => PlayMultiBlockChangeSpec {
+ chunk: ChunkSectionPosition,
+ not_trust_edges: bool,
+ blocks: CountedArray<MultiBlockChangeRecord, VarInt>
+ },
+ PlaySelectAdvancementTab, 0x40, Play, ClientBound => PlaySelectAdvancementTabSpec {
+ identifier: Option<String>
+ },
+ PlayActionBar, 0x41, Play, ClientBound => PlayActionBarSpec {
+ text: Chat
+ },
+ PlayWorldBorderCenter, 0x42, Play, ClientBound => PlayWorldBorderCenterSpec {
+ x: f64,
+ z: f64
+ },
+ PlayWorldBorderLerpSize, 0x43, Play, ClientBound => PlayWorldBorderLerpSizeSpec {
+ old_diameter: f64,
+ new_diameter: f64,
+ speed: VarLong
+ },
+ PlayWorldBorderSize, 0x44, Play, ClientBound => PlayWorldBorderSizeSpec {
+ diameter: f64
+ },
+ PlayWorldBorderWarningDelay, 0x45, Play, ClientBound => PlayWorldBorderWarningDelaySpec {
+ warning_time: VarInt
+ },
+ PlayWorldBorderWarningReach, 0x46, Play, ClientBound => PlayWorldBorderWarningReachSpec {
+ warning_blocks: VarInt
+ },
+ PlayCamera, 0x47, Play, ClientBound => PlayCameraSpec {
+ camera_id: VarInt
+ },
+ PlayServerHeldItemChange, 0x48, Play, ClientBound => PlayServerHeldItemChangeSpec {
+ slot: i8
+ },
+ PlayUpdateViewPosition, 0x49, Play, ClientBound => PlayUpdateViewPositionSpec {
+ chunk: ChunkPosition<VarInt>
+ },
+ PlayUpdateViewDistance, 0x4A, Play, ClientBound => PlayUpdateViewDistanceSpec {
+ view_distance: VarInt
+ },
+ PlaySpawnPosition, 0x4B, Play, ClientBound => PlaySpawnPositionSpec {
+ location: IntPosition,
+ angle: f32
+ },
+ PlayDisplayScoreboard, 0x4C, Play, ClientBound => PlayDisplayScoreboardSpec {
+ position: ScoreboardPosition,
+ score_name: String
+ },
+ PlayEntityMetadata, 0x4D, Play, ClientBound => PlayEntityMetadataSpec {
+ entity_id: VarInt,
+ metadata: EntityMetadata
+ },
+ PlayAttachEntity, 0x4E, Play, ClientBound => PlayAttachEntitySpec {
+ attached_entity_id: i32,
+ holding_entity_id: i32
+ },
+ PlayEntityVelocity, 0x4F, Play, ClientBound => PlayEntityVelocitySpec {
+ entity_id: VarInt,
+ velocity: Vec3<i16>
+ },
+ PlayEntityEquipment, 0x50, Play, ClientBound => PlayEntityEquiptmentSpec {
+ entity_id: VarInt,
+ equipment: EntityEquipmentArray
+ },
+ PlaySetExperience, 0x51, Play, ClientBound => PlaySetExperienceSpec {
+ experience_bar: f32,
+ level: VarInt,
+ total_experience: VarInt
+ },
+ PlayUpdatehealth, 0x52, Play, ClientBound => PlayUpdateHealthSpec {
+ health: f32,
+ food: VarInt,
+ saturation: f32
+ },
+ PlayScoreboardObjective, 0x53, Play, ClientBound => PlayScoreboardObjectiveSpec {
+ objective_name: String,
+ action: ScoreboardObjectiveAction
+ },
+ PlaySetPassengers, 0x54, Play, ClientBound => PlaySetPassengersSpec {
+ entity_id: VarInt,
+ passenger_entitiy_ids: CountedArray<VarInt, VarInt>
+ },
+ PlayTeams, 0x55, Play, ClientBound => PlayTeamsSpec {
+ team_name: String,
+ action: TeamAction
+ },
+ PlayUpdateScore, 0x56, Play, ClientBound => PlayUpdateScoreSpec {
+ entity_name: TeamMember,
+ update: UpdateScoreSpec
+ },
+ PlaySetTitleSubTitle, 0x57, Play, ClientBound => PlaySetTitleSubTitleSpec {
+ text: Chat
+ },
+ PlayTimeUpdate, 0x58, Play, ClientBound => PlayTimeUpdateSpec {
+ world_age: i64,
+ time_of_day: i64
+ },
+ PlaySetTitleText, 0x59, Play, ClientBound => PlaySetTitleTextSpec {
+ text: Chat
+ },
+ PlaySetTitleTimes, 0x5A, Play, ClientBound => PlaySetTitleTimesSpec {
+ fade_in: i32,
+ stay: i32,
+ fade_out: i32
+ },
+ PlayEntitySoundEffect, 0x5B, Play, ClientBound => PlayEntitySoundEffectSpec {
+ sound_id: VarInt,
+ sound_category: SoundCategory,
+ entity_id: VarInt,
+ volume: f32,
+ pitch: f32
+ },
+ PlaySoundEffect, 0x5C, Play, ClientBound => PlaySoundEffectSpec {
+ sound_id: VarInt,
+ sound_category: SoundCategory,
+ position: Vec3<FixedInt>,
+ volume: f32,
+ pitch: f32
+ },
+ PlayStopSound, 0x5D, Play, ClientBound => PlayStopSoundSpec {
+ spec: StopSoundSpec
+ },
+ PlayerPlayerListHeaderAndFooter, 0x5E, Play, ClientBound => PlayPlayerListHeaderAndFooterSpec {
+ header: Chat,
+ footer: Chat
+ },
+ PlayNbtQueryResponse, 0x5F, Play, ClientBound => PlayNbtQueryResponseSpec {
+ transaction_id: VarInt,
+ nbt: NamedNbtTag
+ },
+ PlayCollectItem, 0x60, Play, ClientBound => PlayCollectItemSpec {
+ collected_entity_id: VarInt,
+ collector_entity_id: VarInt,
+ pickup_item_count: VarInt
+ },
+ PlayEntityTeleport, 0x61, Play, ClientBound => PlayEntityTeleportSpec {
+ entity_id: VarInt,
+ location: EntityLocation<f64, Angle>,
+ on_ground: bool
+ },
+ PlayAdvancements, 0x62, Play, ClientBound => PlayAdvancementsSpec {
+ reset: bool,
+ mappings: CountedArray<AdvancementMappingEntrySpec, VarInt>,
+ identifiers: CountedArray<String, VarInt>,
+ progress: CountedArray<AdvancementProgressEntrySpec, VarInt>
+ },
+ PlayEntityProperties, 0x63, Play, ClientBound => PlayEntityPropertiesSpec {
+ entity_id: VarInt,
+ properties: CountedArray<EntityPropertySpec, VarInt>
+ },
+ PlayEntityEffect, 0x64, Play, ClientBound => PlayEntityEffectSpec {
+ entity_id: VarInt,
+ effect_id: EntityEffectKind,
+ amplifier: i8,
+ duration_ticks: VarInt,
+ flags: EntityEffectFlags
+ },
+ PlayDeclareRecipes, 0x65, Play, ClientBound => PlayDeclareRecipesSpec {
+ recipes: CountedArray<RecipeSpec, VarInt>
+ },
+ PlayTags, 0x66, Play, ClientBound => PlayTagsSpec {
+ tags: CountedArray<TypedTagList, VarInt>
+ },
+
+ // play server bound
+ PlayTeleportConfirm, 0x00, Play, ServerBound => PlayTeleportConfirmSpec {
+ teleport_id: VarInt
+ },
+ PlayQueryBlockNbt, 0x01, Play, ServerBound => PlayQueryBlockNbtSpec {
+ transaction_id: VarInt,
+ location: IntPosition
+ },
+ PlaySetDifficulty, 0x02, Play, ServerBound => PlaySetDifficultySpec {
+ new_difficulty: Difficulty
+ },
+ PlayClientChatMessage, 0x03, Play, ServerBound => PlayClientChatMessageSpec {
+ message: String
+ },
+ PlayClientStatus, 0x04, Play, ServerBound => PlayClientStatusSpec {
+ action: ClientStatusAction
+ },
+ PlayClientSettings, 0x05, Play, ServerBound => PlayClientSettingsSpec {
+ locale: String,
+ view_distance: i8,
+ chat_mode: ClientChatMode,
+ chat_colors: bool,
+ displayed_skin_parts: ClientDisplayedSkinParts,
+ main_hand: ClientMainHand,
+ disable_text_filtering: bool
+ },
+ PlayClientTabComplete, 0x06, Play, ServerBound => PlayClientTabCompleteSpec {
+ transaction_id: VarInt,
+ text: String
+ },
+ PlayClickWindowButton, 0x07, Play, ServerBound => PlayClickWindowButtonSpec {
+ window_id: i8,
+ button_id: i8
+ },
+ PlayClickWindow, 0x08, Play, ServerBound => PlayClickWindowSpec {
+ window_id: u8, // TODO: should be u8?
+ state_id: VarInt,
+ slot: i16,
+ button: i8,
+ mode: InventoryOperationMode,
+ slots: CountedArray<SlotAtSpec, VarInt>,
+ clicked_item: Slot
+ },
+ PlayClientCloseWindow, 0x09, Play, ServerBound => PlayClientCloseWindowSpec {
+ window_id: u8
+ },
+ PlayClientPluginMessage, 0x0A, Play, ServerBound => PlayClientPluginMessageSpec {
+ channel: String,
+ data: RemainingBytes
+ },
+ PlayEditBook, 0x0B, Play, ServerBound => PlayEditBookSpec {
+ hand: Hand,
+ pages: CountedArray<String, VarInt>,
+ title: Option<String>
+ },
+ PlayQueryEntityNbt, 0x0C, Play, ServerBound => PlayQueryEntityNbtSpec {
+ transaction_id: VarInt,
+ entity_id: VarInt
+ },
+ PlayInteractEntity, 0x0D, Play, ServerBound => PlayInteractEntitySpec {
+ entity_id: VarInt,
+ kind: InteractKind,
+ sneaking: bool
+ },
+ PlayGenerateStructure, 0x0E, Play, ServerBound => PlayGenerateStructureSpec {
+ location: IntPosition,
+ levels: VarInt,
+ keep_jigsaws: bool
+ },
+ PlayClientKeepAlive, 0x0F, Play, ServerBound => PlayClientKeepAliveSpec {
+ id: i64
+ },
+ PlayLockDifficulty, 0x10, Play, ServerBound => PlayLockDifficultySpec {
+ locked: bool
+ },
+ PlayPlayerPosition, 0x11, Play, ServerBound => PlayPlayerPositionSpec {
+ feet_position: Vec3<f64>,
+ on_ground: bool
+ },
+ PlayClientPlayerPositionAndRotation, 0x12, Play, ServerBound => PlayClientPlayerPositionAndRotationSpec {
+ feet_location: EntityLocation<f64, f32>,
+ on_ground: bool
+ },
+ PlayPlayerRotation, 0x13, Play, ServerBound => PlayPlayerRotationSpec {
+ rotation: EntityRotation<f32>,
+ on_ground: bool
+ },
+ PlayPlayerMovement, 0x14, Play, ServerBound => PlayPlayerMovementSpec {
+ on_ground: bool
+ },
+ PlayClientVehicleMove, 0x15, Play, ServerBound => PlayClientVehicleMoveSpec {
+ location: EntityLocation<f64, f32>
+ },
+ PlaySteerBoat, 0x16, Play, ServerBound => PlaySteerBoatSpec {
+ left_paddle_turning: bool,
+ right_paddle_turning: bool
+ },
+ PlayPickItem, 0x17, Play, ServerBound => PlayPickItemSpec {
+ slot_idx: VarInt
+ },
+ PlayCraftRecipeRequest, 0x18, Play, ServerBound => PlayCraftRecipeRequestSpec {
+ window_id: i8,
+ recipe: String,
+ make_all: bool
+ },
+ PlayClientPlayerAbilities, 0x19, Play, ServerBound => PlayClientPlayerAbilitiesSpec {
+ flags: ClientPlayerAbilities
+ },
+ PlayPlayerDigging, 0x1A, Play, ServerBound => PlayPlayerDiggingSpec {
+ status: PlayerDiggingStatus,
+ location: IntPosition,
+ face: DiggingFace
+ },
+ PlayEntityAction, 0x1B, Play, ServerBound => PlayEntityActionSpec {
+ entity_id: VarInt,
+ action: EntityActionKind,
+ jump_boot: VarInt
+ },
+ PlaySteerVehicle, 0x1C, Play, ServerBound => PlaySteerVehicleSpec {
+ sideways: f32,
+ forward: f32,
+ flags: SteerVehicleFlags
+ },
+ PlayPong, 0x1D, Play, ServerBound => PlayPongSpec {
+ id: i32
+ },
+ PlaySetRecipeBookState, 0x1E, Play, ServerBound => PlaySetRecipeBookStateSpec {
+ book_id: RecipeBookType,
+ open: bool,
+ filtered: bool
+ },
+ PlaySetDisplayedRecipe, 0x1F, Play, ServerBound => PlaySetDisplayedRecipeSpec {
+ recipe_id: String
+ },
+ PlayNameItem, 0x20, Play, ServerBound => PlayNameItemSpec {
+ name: String
+ },
+ PlayResourcePackStatus, 0x21, Play, ServerBound => PlayResourcePackStatusSpec {
+ status: ResourcePackStatus
+ },
+ PlayAdvancementTab, 0x22, Play, ServerBound => PlayAdvancementTabSpec {
+ action: AdvancementTabAction
+ },
+ PlaySelectTrade, 0x23, Play, ServerBound => PlaySelectTradeSpec {
+ selected_slot: VarInt
+ },
+ PlaySetBeaconEffect, 0x24, Play, ServerBound => PlaySetBeaconEffectSpec {
+ primary_effect: VarInt,
+ secondary_effect: VarInt
+ },
+ PlayClientHeldItemChange, 0x25, Play, ServerBound => PlayClientHeldItemChangeSpec {
+ slot: i16
+ },
+ PlayUpdateCommandBlock, 0x26, Play, ServerBound => PlayUpdateCommandBlockSpec {
+ location: IntPosition,
+ command: String,
+ mode: CommandBlockMode,
+ flags: CommandBlockFlags
+ },
+ PlayUpdateCommandBlockMinecart, 0x27, Play, ServerBound => PlayUpdateCommandBlockMinecartSpec {
+ entity_id: VarInt,
+ command: String,
+ track_output: bool
+ },
+ PlayCreativeInventoryAction, 0x28, Play, ServerBound => PlayCreativeInventoryActionSpec {
+ slot: i16,
+ clicked_item: Slot
+ },
+ PlayUpdateJigsawBlock, 0x29, Play, ServerBound => PlayUpdateJigsawBlockSpec {
+ location: IntPosition,
+ attachment_type: String,
+ target_pool: String,
+ final_state: String
+ },
+ PlayUpdateStructureBlock, 0x2A, Play, ServerBound => PlayUpdateStructureBlockSpec {
+ location: IntPosition,
+ action: UpdateStructureBlockAction,
+ mode: UpdateStructureBlockMode,
+ name: String,
+ offset: Vec3<i8>,
+ size: Vec3<i8>,
+ mirror: UpdateStructureBlockMirror,
+ rotation: UpdateStructureBlockRotation,
+ metadata: String,
+ integrity: f32,
+ seed: VarLong,
+ flags: UpdateStructureBlockFlags
+ },
+ PlayUpdateSign, 0x2B, Play, ServerBound => PlayUpdateSignSpec {
+ location: IntPosition,
+ line1: String,
+ line2: String,
+ line3: String,
+ line4: String
+ },
+ PlayClientAnimation, 0x2C, Play, ServerBound => PlayClientAnimationSpec {
+ hand: Hand
+ },
+ PlaySpectate, 0x2D, Play, ServerBound => PlaySpectateSpec {
+ target: UUID4
+ },
+ PlayBlockPlacement, 0x2E, Play, ServerBound => PlayBlockPlacementSpec {
+ hand: Hand,
+ location: IntPosition,
+ face: DiggingFace,
+ cursor_position: Vec3<f32>,
+ inside_block: bool
+ },
+ PlayUseItem, 0x2F, Play, ServerBound => PlayUseItemSpec {
+ hand: Hand
+ }
+});
+
+// helper types
+
+// handshake enum
+proto_byte_enum!(HandshakeNextState,
+ 0x01 :: Status,
+ 0x02 :: Login
+);
+
+proto_byte_enum!(CardinalDirection,
+ 0x00 :: South,
+ 0x01 :: West,
+ 0x02 :: North,
+ 0x03:: East
+);
+
+proto_byte_enum!(EntityAnimationKind,
+ 0x00 :: SwingMainArm,
+ 0x01 :: TakeDamage,
+ 0x02 :: LeaveBed,
+ 0x03 :: SwingOffHand,
+ 0x04 :: CriticalEffect,
+ 0x05 :: MagicCriticalEffect
+);
+
+proto_varint_enum!(StatisticCategory,
+ 0x00 :: Mined(VarInt),
+ 0x01 :: Crafted(VarInt),
+ 0x02 :: Used(VarInt),
+ 0x03 :: Broken(VarInt),
+ 0x04 :: PickedUp(VarInt),
+ 0x05 :: Dropped(VarInt),
+ 0x06 :: Killed(VarInt),
+ 0x07 :: KilledBy(VarInt),
+ 0x08 :: Custom(StatisticKind)
+);
+
+proto_varint_enum!(StatisticKind,
+ 0x00 :: LeaveGame,
+ 0x01 :: PlayOneMinute,
+ 0x02 :: TimeSinceDeath,
+ 0x03 :: SneakTime,
+ 0x04 :: WealkOneCm,
+ 0x05 :: CrouchOneCm,
+ 0x06 :: SprintOneCm,
+ 0x07 :: SwimOneCm,
+ 0x08 :: FallOneCm,
+ 0x09 :: ClimbOneCm,
+ 0x0A :: FlyOneCm,
+ 0x0B :: DiveOneCm,
+ 0x0C :: MinecartOneCm,
+ 0x0D :: BoatOneCm,
+ 0x0E :: PigOneCm,
+ 0x0F :: HorseOneCm,
+ 0x10 :: AviateOneCm,
+ 0x11 :: Jumps,
+ 0x12 :: Drops,
+ 0x13 :: DamageDealt,
+ 0x14 :: DamageTaken,
+ 0x15 :: Deaths,
+ 0x16 :: MobKills,
+ 0x17 :: AnimalsBread,
+ 0x18 :: PlayerKills,
+ 0x19 :: FishCaught,
+ 0x1A :: TalkedToVillager,
+ 0x1B :: TradedWithVillager,
+ 0x1C :: EatCakeSlice,
+ 0x1D :: FillCauldron,
+ 0x1E :: UseCauldron,
+ 0x1F :: CleanArmor,
+ 0x20 :: CleanBanner,
+ 0x21 :: InteractWithBrewingStand,
+ 0x22 :: InteractWithBeaccon,
+ 0x23 :: InspectDropper,
+ 0x24 :: InspectHopper,
+ 0x25 :: InspectDispenser,
+ 0x26 :: PlayNoteBlock,
+ 0x27 :: TuneNoteBlock,
+ 0x28 :: PotFlower,
+ 0x29 :: TriggerTrappedChest,
+ 0x2A :: OpenEnderChest,
+ 0x2B :: EnchantItem,
+ 0x2C :: PlayRecord,
+ 0x2D :: InteractWithFurnace,
+ 0x2E :: InteractWithCraftingTable,
+ 0x2F :: OpenChest,
+ 0x30 :: SleepInBed,
+ 0x31 :: OpenShulkerBox
+);
+
+proto_struct!(Statistic {
+ kind: StatisticCategory,
+ value: VarInt
+});
+
+proto_byte_enum!(DiggingStatus,
+ 0x00 :: Started,
+ 0x01 :: Cancelled,
+ 0x02 :: Finished
+);
+
+proto_byte_enum!(BlockEntityDataAction,
+ 0x01 :: SetMobSpawnerData,
+ 0x02 :: SetCommandBlockText,
+ 0x03 :: SetBeaconLevelAndPower,
+ 0x04 :: SetMobHeadRotationAndSkin,
+ 0x05 :: DeclareConduit,
+ 0x06 :: SetBannerColorAndPatterns,
+ 0x07 :: SetStructureTileEntityData,
+ 0x08 :: SetEndGatewayDestination,
+ 0x09 :: SetSignText,
+ 0x0B :: DeclareBed,
+ 0x0C :: SetJigsawBlockData,
+ 0x0D :: SetCampfireItems,
+ 0x0E :: BeehiveInformation
+);
+
+proto_byte_enum!(Difficulty,
+ 0x00 :: Peaceful,
+ 0x01 :: Easy,
+ 0x02 :: Normal,
+ 0x03 :: Hard
+);
+
+proto_byte_enum!(ChatPosition,
+ 0x00 :: ChatBox,
+ 0x01 :: SystemMessage,
+ 0x02 :: Hotbar
+);
+
+proto_str_enum!(SculkDestinationIdentifier,
+ "block" :: Block(IntPosition),
+ "entity" :: Entity(VarInt)
+);
+
+proto_int_enum!(EffectKind,
+ 1000 :: DispenserDispenses,
+ 1001 :: DispenserFails,
+ 1002 :: DispenserShoots,
+ 1003 :: EnderEyeLaunched,
+ 1004 :: FireworkShot,
+ 1005 :: IronDoorOpened,
+ 1006 :: WoodenDoorOpened,
+ 1007 :: WoodenTrapdoorOpened,
+ 1008 :: FenceGateOpened,
+ 1009 :: FireExtinguished,
+ 1010 :: PlayRecord,
+ 1011 :: IronDoorClosed,
+ 1012 :: WoodenDoorClosed,
+ 1013 :: WoodenTrapdoorClosed,
+ 1014 :: FenceGateClosed,
+ 1015 :: GhastWarns,
+ 1016 :: GhastShoots,
+ 1017 :: EnderDragonShoots,
+ 1018 :: BlazeShoots,
+ 1019 :: ZombieAttacksWoodDoor,
+ 1020 :: ZombieAttacksIronDoor,
+ 1021 :: ZombieBreaksWoodDoor,
+ 1022 :: WitherBreaksBlock,
+ 1023 :: WitherSpawned,
+ 1024 :: WitherShoots,
+ 1025 :: BatTakesOff,
+ 1026 :: ZombieInfects,
+ 1027 :: ZombieVillagerConverted,
+ 1028 :: EnderDragonDeath,
+ 1029 :: AnvilDestroyed,
+ 1030 :: AnvilUsed,
+ 1031 :: AnvilLanded,
+ 1032 :: PortalTravel,
+ 1033 :: ChorusFlowerGrown,
+ 1034 :: ChorusFlowerDied,
+ 1035 :: BrewingStandBrewed,
+ 1036 :: IronTrapdoorOpened,
+ 1037 :: IronTrapdoorClosed,
+ 1038 :: EndPortalCreatedInOverworld,
+ 1039 :: PhantomBites,
+ 1040 :: ZombieConvertsToDrowned,
+ 1041 :: HuskConvertsToZombieByDrowning,
+ 1042 :: GrindstoneUsed,
+ 1043 :: BookPageTurned,
+ // particles:
+ 1500 :: ComposterComposts,
+ 1501 :: LavaConvertsBlock,
+ 1502 :: RedstoneTorchBurnsOut,
+ 1503 :: EnderEyePlaced,
+ 2000 :: Spawns10SmokeParticles,
+ 2001 :: BlockBreak,
+ 2002 :: SplashPotion,
+ 2003 :: EyeOfEnderBreak,
+ 2004 :: MobSpawn,
+ 2005 :: Bonemeal,
+ 2006 :: DragonBreath,
+ 2007 :: InstantSplashPotion,
+ 2008 :: EnderDragonDestroysBlock,
+ 2009 :: WetSpongeVaporizes,
+ 3000 :: EndGatewaySpawn,
+ 3001 :: EnderDragonGrowl,
+ 3002 :: ElectricSpark,
+ 3003 :: CopperApplyWax,
+ 3004 :: CopperRemoveWax,
+ 3005 :: CopperScrapeOxidation
+);
+
+proto_str_enum!(TagType,
+ "minecraft:block" :: Block,
+ "minecraft:item" :: Item,
+ "minecraft:fluid" :: Fluid,
+ "minecraft:entity_type" :: EntityType,
+ "minecraft:game_event" :: GameEvent
+);
+
+proto_struct!(TypedTagList {
+ tag_type: TagType,
+ tags: CountedArray<TagSpec, VarInt>
+});
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct BlockChangeHorizontalPosition {
+ pub rel_x: u8,
+ pub rel_z: u8,
+}
+
+impl Serialize for BlockChangeHorizontalPosition {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_byte((self.rel_x & 0xF) << 4 | (self.rel_z & 0xF))
+ }
+}
+
+impl Deserialize for BlockChangeHorizontalPosition {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ Ok(
+ u8::mc_deserialize(data)?.map(move |b| BlockChangeHorizontalPosition {
+ rel_x: (b >> 4) & 0xF,
+ rel_z: b & 0xF,
+ }),
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for BlockChangeHorizontalPosition {
+ fn test_gen_random() -> Self {
+ BlockChangeHorizontalPosition {
+ rel_x: rand::random::<u8>() % 16,
+ rel_z: rand::random::<u8>() % 16,
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct ChunkSectionPosition {
+ pub x: i32,
+ pub y: i32,
+ pub z: i32,
+}
+
+impl Serialize for ChunkSectionPosition {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let num = (((self.x as u64) & 0x3FFFFF) << 42)
+ | (((self.z as u64) & 0x3FFFFF) << 20)
+ | ((self.y as u64) & 0xFFFFF);
+
+ to.serialize_other(&num)
+ }
+}
+
+impl Deserialize for ChunkSectionPosition {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: raw, data } = u64::mc_deserialize(data)?;
+ let y = (raw & 0xFFFFF) as i32;
+ let z = ((raw >> 20) & 0x3FFFFF) as i32;
+ let x = ((raw >> 42) & 0x3FFFFF) as i32;
+ Deserialized::ok(Self { x, y, z }, data)
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for ChunkSectionPosition {
+ fn test_gen_random() -> Self {
+ Self {
+ x: (u32::test_gen_random() & 0x3FFFFF) as i32,
+ y: (u32::test_gen_random() & 0xFFFFF) as i32,
+ z: (u32::test_gen_random() & 0x3FFFFF) as i32,
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct MultiBlockChangeRecord {
+ pub block_id: u64,
+ pub rel_position: Vec3<i8>,
+}
+
+impl Serialize for MultiBlockChangeRecord {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let raw = (self.block_id << 12)
+ | (((self.rel_position.x as u64) & 0xF) << 8)
+ | (((self.rel_position.y as u64) & 0xF) << 4)
+ | ((self.rel_position.z as u64) & 0xF);
+ let raw = VarLong(raw as i64);
+ to.serialize_other(&raw)
+ }
+}
+
+impl Deserialize for MultiBlockChangeRecord {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: raw, data } = VarLong::mc_deserialize(data)?;
+ let raw = raw.0 as u64;
+ let block_id = raw >> 12;
+ let x = ((raw >> 8) & 0xF) as i8;
+ let y = ((raw >> 4) & 0xF) as i8;
+ let z = (raw & 0xF) as i8;
+ let rel_position = (x, y, z).into();
+ Deserialized::ok(
+ Self {
+ block_id,
+ rel_position,
+ },
+ data,
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for MultiBlockChangeRecord {
+ fn test_gen_random() -> Self {
+ let mut rel_position = <Vec3<i8>>::test_gen_random();
+ rel_position.x &= 0xF;
+ rel_position.y &= 0xF;
+ rel_position.z &= 0xF;
+ let block_id = u64::test_gen_random() & ((1 << 52) - 1);
+
+ Self {
+ block_id,
+ rel_position,
+ }
+ }
+}
+
+proto_varint_enum!(BossBarAction,
+ 0x00 :: Add(BossBarAddSpec),
+ 0x01 :: Remove,
+ 0x02 :: UpdateHealth(BossBarUpdateHealthSpec),
+ 0x03 :: UpdateTitle(BossBarUpdateTitleSpec),
+ 0x04 :: UpdateStyle(BossBarUpdateStyleSpec),
+ 0x05 :: UpdateFlags(BossBarUpdateFlagsSpec)
+);
+
+proto_varint_enum!(BossBarColor,
+ 0x00 :: Pink,
+ 0x01 :: Blue,
+ 0x02 :: Red,
+ 0x03 :: Green,
+ 0x04 :: Yellow,
+ 0x05 :: Purple,
+ 0x06 :: White
+);
+
+proto_varint_enum!(BossBarDivision,
+ 0x00 :: NoDivision,
+ 0x01 :: SixNotches,
+ 0x02 :: TenNotches,
+ 0x03 :: TwelveNotches,
+ 0x04 :: TwentyNotches
+);
+
+proto_byte_flag!(BossBarFlags,
+ 0x01 :: is_darken_sky set_darken_sky,
+ 0x02 :: is_dragon_bar set_dragon_bar,
+ 0x04 :: is_create_fog set_create_fog
+);
+
+proto_struct!(BossBarAddSpec {
+ title: Chat,
+ health: f32,
+ color: BossBarColor,
+ division: BossBarDivision,
+ flags: BossBarFlags
+});
+
+proto_struct!(BossBarUpdateHealthSpec { health: f32 });
+
+proto_struct!(BossBarUpdateTitleSpec { title: String });
+
+proto_struct!(BossBarUpdateStyleSpec {
+ color: BossBarColor,
+ dividers: BossBarDivision
+});
+
+proto_struct!(BossBarUpdateFlagsSpec {
+ flags: BossBarFlags
+});
+
+proto_struct!(TabCompleteMatch {
+ match_: String,
+ tooltip: Option<Chat>
+});
+
+#[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),
+}
+
+impl Serialize for CommandNodeSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let mut flags: u8 = 0;
+
+ use CommandNode::*;
+
+ flags |= match &self.node {
+ Root => 0x00,
+ Literal(_) => 0x01,
+ Argument(_) => 0x02,
+ };
+
+ if self.is_executable {
+ flags |= 0x04;
+ }
+
+ if self.redirect_node.is_some() {
+ flags |= 0x08;
+ }
+
+ if let Argument(body) = &self.node {
+ if body.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) => body.serialize(to),
+ 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 (redirect_node, data) = if flags & 0x08 != 0 {
+ let Deserialized {
+ value: redirect_node,
+ data,
+ } = VarInt::mc_deserialize(data)?;
+ (Some(redirect_node), data)
+ } else {
+ (None, data)
+ };
+ let is_executable = flags & 0x04 != 0;
+
+ 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::deserialize(flags & 0x10 != 0, data)?
+ .map(move |body| Argument(body)),
+ ),
+ other => panic!("impossible condition (bitmask) {}", other),
+ }?;
+
+ Deserialized::ok(
+ Self {
+ children_indices,
+ redirect_node,
+ is_executable,
+ node,
+ },
+ data,
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for CommandNodeSpec {
+ fn test_gen_random() -> Self {
+ let children_indices = <CountedArray<VarInt, VarInt>>::test_gen_random();
+ let redirect_node = <Option<VarInt>>::test_gen_random();
+ let is_executable = rand::random::<bool>();
+ let idx = rand::random::<usize>() % 3;
+ let node = match idx {
+ 0 => CommandNode::Root,
+ 1 => CommandNode::Argument(CommandArgumentNodeSpec::test_gen_random()),
+ 2 => CommandNode::Literal(CommandLiteralNodeSpec::test_gen_random()),
+ other => panic!("impossible state {}", other),
+ };
+
+ Self {
+ children_indices,
+ redirect_node,
+ is_executable,
+ node,
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct CommandArgumentNodeSpec {
+ pub name: String,
+ pub parser: CommandParserSpec,
+ pub suggestions_types: Option<SuggestionsTypeSpec>,
+}
+
+impl CommandArgumentNodeSpec {
+ fn serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_other(&self.name)?;
+ to.serialize_other(&self.parser)?;
+ if let Some(suggestions_types) = &self.suggestions_types {
+ to.serialize_other(suggestions_types)?;
+ }
+
+ Ok(())
+ }
+
+ fn deserialize(has_suggestion_types: bool, data: &[u8]) -> DeserializeResult<Self> {
+ let Deserialized { value: name, data } = String::mc_deserialize(data)?;
+ let Deserialized {
+ value: parser,
+ data,
+ } = CommandParserSpec::mc_deserialize(data)?;
+ let (suggestions_types, data) = if has_suggestion_types {
+ let Deserialized {
+ value: suggestions_types,
+ data,
+ } = SuggestionsTypeSpec::mc_deserialize(data)?;
+ (Some(suggestions_types), data)
+ } else {
+ (None, data)
+ };
+
+ Deserialized::ok(
+ Self {
+ name,
+ parser,
+ suggestions_types,
+ },
+ data,
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for CommandArgumentNodeSpec {
+ fn test_gen_random() -> Self {
+ let name = String::test_gen_random();
+ let suggestions_types = <Option<SuggestionsTypeSpec>>::test_gen_random();
+ let parser = CommandParserSpec::test_gen_random();
+
+ Self {
+ name,
+ parser,
+ suggestions_types,
+ }
+ }
+}
+
+proto_str_enum!(SuggestionsTypeSpec,
+ "minecraft:ask_server" :: AskServer,
+ "minecraft:all_recipes" :: AllRecipes,
+ "minecraft:available_sounds" :: AvailableSounds,
+ "minecraft:summonable_entities" :: SummonableEntities,
+ "minecraft:available_biomes" :: AvailableBiomes
+);
+
+proto_struct!(CommandLiteralNodeSpec { name: String });
+
+proto_str_enum!(CommandParserSpec,
+ "brigadier:bool" :: Bool,
+ "brigadier:double" :: Double(DoubleParserProps),
+ "brigadier:float" :: Float(FloatParserProps),
+ "brigadier:integer" :: Integer(IntegerParserProps),
+ "brigadier:string" :: StringParser(StringParserMode),
+ "minecraft:entity" :: Entity(EntityParserFlags),
+ "minecraft:game_profile" :: GameProfile,
+ "minecraft:block_pos" :: BlockPosition,
+ "minecraft:column_pos" :: ColumnPosition,
+ "minecraft:vec3" :: Vec3,
+ "minecraft:vec2" :: Vec2,
+ "minecraft:block_state" :: BlockState,
+ "minecraft:block_predicate" :: BlockPredicate,
+ "minecraft:item_stack" :: ItemStack,
+ "minecraft:item_predicate" :: ItemPredicate,
+ "minecraft:color" :: Color,
+ "minecraft:component" :: Component,
+ "minecraft:message" :: Message,
+ "minecraft:nbt" :: Nbt,
+ "minecraft:nbt_path" :: NbtPath,
+ "minecraft:objective" :: Objective,
+ "minecraft:objective_criteria" :: ObjectiveCriteria,
+ "minecraft:operation" :: Operation,
+ "minecraft:particle" :: Particle,
+ "minecraft:rotation" :: Rotation,
+ "minecraft:angle" :: Angle,
+ "minecraft:scoreboard_slot" :: ScoreboardSlot,
+ "minecraft:score_holder" :: ScoreHolder(ScoreHolderFlags),
+ "minecraft:swizzle" :: Swizzle,
+ "minecraft:team" :: Team,
+ "minecraft:item_slot" :: ItemSlot,
+ "minecraft:resource_location" :: ResourceLocation,
+ "minecraft:mob_effect" :: MobEffect,
+ "minecraft:function" :: Function,
+ "minecraft:entity_anchor" :: EntityAnchor,
+ "minecraft:range" :: Range(RangeParserProps),
+ "minecraft:int_range" :: IntRange,
+ "minecraft:float_range" :: FloatRange,
+ "minecraft:item_enchantment" :: ItemEnchantment,
+ "minecraft:entity_summon" :: EntitySummon,
+ "minecraft:dimension" :: Dimension,
+ "minecraft:uuid" :: UUID,
+ "minecraft:nbt_tag" :: NbtTag,
+ "minecraft:nbt_compound_tag" :: NbtCompoundTag,
+ "minecraft:time" :: Time
+);
+
+pub struct NumParserProps<T> {
+ pub min: Option<T>,
+ pub max: Option<T>,
+}
+
+pub type DoubleParserProps = NumParserProps<f64>;
+
+pub type FloatParserProps = NumParserProps<f32>;
+
+pub type IntegerParserProps = NumParserProps<i32>;
+
+impl<T> Copy for NumParserProps<T> where T: Copy {}
+
+impl<T> Clone for NumParserProps<T>
+where
+ T: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ min: self.min.clone(),
+ max: self.max.clone(),
+ }
+ }
+}
+
+impl<T> Debug for NumParserProps<T>
+where
+ T: Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "NumParserProps(min={:?}, max={:?})", self.min, self.max)
+ }
+}
+
+impl<T> PartialEq for NumParserProps<T>
+where
+ T: PartialEq,
+{
+ fn eq(&self, other: &Self) -> bool {
+ other.max.eq(&self.max) && other.min.eq(&self.min)
+ }
+}
+
+impl<T> Serialize for NumParserProps<T>
+where
+ T: Serialize,
+{
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let mut flags: u8 = 0;
+ if self.min.is_some() {
+ flags |= 0x01;
+ }
+
+ if self.max.is_some() {
+ flags |= 0x02;
+ }
+
+ to.serialize_other(&flags)?;
+ if let Some(min) = &self.min {
+ to.serialize_other(min)?;
+ }
+
+ if let Some(max) = &self.max {
+ to.serialize_other(max)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl<T> Deserialize for NumParserProps<T>
+where
+ T: Deserialize,
+{
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: flags, data } = u8::mc_deserialize(data)?;
+ let (min, data) = if flags & 0x01 != 0 {
+ let Deserialized { value: min, data } = T::mc_deserialize(data)?;
+ (Some(min), data)
+ } else {
+ (None, data)
+ };
+
+ let (max, data) = if flags & 0x02 != 0 {
+ let Deserialized { value: max, data } = T::mc_deserialize(data)?;
+ (Some(max), data)
+ } else {
+ (None, data)
+ };
+
+ let out = Self { min, max };
+ Deserialized::ok(out, data)
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl<T> TestRandom for NumParserProps<T>
+where
+ T: TestRandom + std::cmp::PartialOrd,
+ rand::distributions::Standard: rand::distributions::Distribution<T>,
+{
+ fn test_gen_random() -> Self {
+ let has_min = rand::random::<bool>();
+ let has_max = rand::random::<bool>();
+ let (min, max) = if has_min && has_max {
+ let a = rand::random::<T>();
+ let b = rand::random::<T>();
+ if a < b {
+ (Some(a), Some(b))
+ } else {
+ (Some(b), Some(a))
+ }
+ } else if !has_min && !has_max {
+ (None, None)
+ } else {
+ let v = rand::random::<T>();
+ if has_min {
+ (Some(v), None)
+ } else {
+ (None, Some(v))
+ }
+ };
+
+ Self { min, max }
+ }
+}
+
+proto_varint_enum!(StringParserMode,
+ 0x00 :: SingleWord,
+ 0x01 :: QuotablePharse,
+ 0x02 :: GreedyPhrase
+);
+
+proto_byte_flag!(EntityParserFlags,
+ 0x01 :: is_single_target set_single_target,
+ 0x02 :: is_players_only set_players_only
+);
+
+proto_byte_flag!(ScoreHolderFlags,
+ 0x01 :: is_multiple set_multiple
+);
+
+proto_struct!(RangeParserProps { decimal: bool });
+
+proto_byte_enum!(TeamAction,
+ 0x00 :: Create(TeamActionCreateSpec),
+ 0x01 :: Remove,
+ 0x02 :: UpdateInfo(TeamActionUpdateInfoSpec),
+ 0x03 :: AddPlayers(TeamActionPlayerList),
+ 0x04 :: RemovePlayers(TeamActionPlayerList)
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum TeamMember {
+ Player(String),
+ Entity(UUID4),
+}
+
+impl Serialize for TeamMember {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ use TeamMember::*;
+ match self {
+ Player(username) => username.mc_serialize(to),
+ Entity(entity_id) => entity_id.to_string().mc_serialize(to),
+ }
+ }
+}
+
+impl Deserialize for TeamMember {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ use TeamMember::*;
+
+ Ok(String::mc_deserialize(data)?.map(move |raw| {
+ if let Some(entity_id) = UUID4::parse(raw.as_str()) {
+ Entity(entity_id)
+ } else {
+ Player(raw)
+ }
+ }))
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for TeamMember {
+ fn test_gen_random() -> Self {
+ use TeamMember::*;
+
+ let rand_bool: bool = rand::random();
+ if rand_bool {
+ Player(String::test_gen_random())
+ } else {
+ Entity(UUID4::random())
+ }
+ }
+}
+
+proto_str_enum!(TeamTagNameVisibility,
+ "always" :: Always,
+ "hideForOtherTeams" :: HideForOtherTeams,
+ "hideForOwnTeam" :: HideForOwnTeam,
+ "never" :: Never
+);
+
+proto_str_enum!(TeamCollisionRule,
+ "always" :: Always,
+ "pushForOtherTeams" :: PushForOtherTeams,
+ "pushOwnTeam" :: PushOwnTeam,
+ "never" :: Never
+);
+
+proto_struct!(TeamActionPlayerList {
+ entities: CountedArray<TeamMember, VarInt>
+});
+
+proto_struct!(TeamActionCreateSpec {
+ display_name: Chat,
+ friendly_flags: TeamFriendlyFlags,
+ tag_name_visibility: TeamTagNameVisibility,
+ collision_rule: TeamCollisionRule,
+ color: VarInt,
+ prefix: Chat,
+ suffix: Chat,
+ entities: CountedArray<TeamMember, VarInt>
+});
+
+proto_struct!(TeamActionUpdateInfoSpec {
+ display_name: Chat,
+ friendly_flags: TeamFriendlyFlags,
+ tag_name_visibility: TeamTagNameVisibility,
+ collision_rule: TeamCollisionRule,
+ color: VarInt,
+ prefix: Chat,
+ suffix: Chat
+});
+
+proto_byte_flag!(TeamFriendlyFlags,
+ 0x01 :: allow_friendly_fire set_friendly_fire,
+ 0x02 :: show_invisible_teammates set_show_invisible_teammates
+);
+
+proto_byte_enum!(UpdateScoreAction,
+ 0x00 :: Upsert(VarInt),
+ 0x01 :: Remove
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct UpdateScoreSpec {
+ pub objective_name: String,
+ pub action: UpdateScoreAction,
+}
+
+impl Serialize for UpdateScoreSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_byte(self.action.id())?;
+ to.serialize_other(&self.objective_name)?;
+ self.action.serialize_body(to)?;
+
+ Ok(())
+ }
+}
+
+impl Deserialize for UpdateScoreSpec {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized {
+ value: action_id,
+ data,
+ } = u8::mc_deserialize(data)?;
+ let Deserialized {
+ value: objective_name,
+ data,
+ } = String::mc_deserialize(data)?;
+
+ Ok(
+ UpdateScoreAction::deserialize_with_id(action_id, data)?.map(move |action| Self {
+ objective_name,
+ action,
+ }),
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for UpdateScoreSpec {
+ fn test_gen_random() -> Self {
+ Self {
+ objective_name: String::test_gen_random(),
+ action: UpdateScoreAction::test_gen_random(),
+ }
+ }
+}
+
+// proto_varint_enum!(TitleActionSpec,
+// 0x00 :: SetTitle(Chat),
+// 0x01 :: SetSubtitle(Chat),
+// 0x02 :: SetActionBar(Chat),
+// 0x03 :: SetTimesAndDisplay(TitleTimesSpec),
+// 0x04 :: Hide,
+// 0x05 :: Reset
+// );
+
+// proto_struct!(TitleTimesSpec {
+// fade_in: i32,
+// stay: i32,
+// fade_out: i32
+// });
+
+proto_varint_enum!(SoundCategory,
+ 0x00 :: Master,
+ 0x01 :: Music,
+ 0x02 :: Records,
+ 0x03 :: Weather,
+ 0x04 :: Block,
+ 0x05 :: Hostile,
+ 0x06 :: Neutral,
+ 0x07 :: Player,
+ 0x08 :: Ambient,
+ 0x09 :: Voice
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct StopSoundSpec {
+ pub source: Option<SoundCategory>,
+ pub sound: Option<String>,
+}
+
+impl Serialize for StopSoundSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let has_sound = self.sound.is_some();
+ let has_source = self.source.is_some();
+ let mut flags = 0;
+ if has_sound {
+ flags |= 0x02;
+ }
+ if has_source {
+ flags |= 0x01;
+ }
+
+ to.serialize_byte(flags)?;
+ if let Some(source) = &self.source {
+ to.serialize_other(source)?;
+ }
+
+ if let Some(sound) = &self.sound {
+ to.serialize_other(sound)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl Deserialize for StopSoundSpec {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: flags, data } = u8::mc_deserialize(data)?;
+
+ let is_source_present = flags & 0x01 != 0;
+ let is_sound_present = flags & 0x02 != 0;
+
+ let (source, data) = if is_source_present {
+ let Deserialized {
+ value: source,
+ data,
+ } = SoundCategory::mc_deserialize(data)?;
+ (Some(source), data)
+ } else {
+ (None, data)
+ };
+
+ let (sound, data) = if is_sound_present {
+ let Deserialized { value: sound, data } = String::mc_deserialize(data)?;
+ (Some(sound), data)
+ } else {
+ (None, data)
+ };
+
+ Deserialized::ok(Self { source, sound }, data)
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for StopSoundSpec {
+ fn test_gen_random() -> Self {
+ let source = if rand::random::<bool>() {
+ Some(SoundCategory::test_gen_random())
+ } else {
+ None
+ };
+
+ let sound = if source.is_none() || rand::random::<bool>() {
+ Some(String::test_gen_random())
+ } else {
+ None
+ };
+
+ Self { source, sound }
+ }
+}
+
+proto_byte_enum!(GameMode,
+ 0x00 :: Survival,
+ 0x01 :: Creative,
+ 0x02 :: Adventure,
+ 0x03 :: 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)))
+ }
+ }
+ }
+}
+
+impl Into<Option<GameMode>> for PreviousGameMode {
+ fn into(self) -> Option<GameMode> {
+ use PreviousGameMode::*;
+ match self {
+ NoPrevious => None,
+ Previous(mode) => Some(mode),
+ }
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for PreviousGameMode {
+ fn test_gen_random() -> Self {
+ use PreviousGameMode::*;
+ match <Option<GameMode> as TestRandom>::test_gen_random() {
+ Some(gamemode) => Previous(gamemode),
+ None => NoPrevious,
+ }
+ }
+}
+
+proto_byte_enum!(WinGameAction,
+ 0x00 :: Respawn,
+ 0x01 :: RollCreditsAndRespawn
+);
+
+proto_byte_enum!(DemoEvent,
+ 0x00 :: ShowWelcomeScreen,
+ 0x65 :: TellMovementControls,
+ 0x66 :: TellJumpControl,
+ 0x67 :: TellInventoryControl,
+ 0x68 :: EndDemo
+);
+
+proto_byte_enum!(RespawnRequestType,
+ 0x00 :: Screen,
+ 0x01 :: Immediate
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum GameChangeReason {
+ NoRespawnAvailable,
+ EndRaining,
+ BeginRaining,
+ ChangeGameMode(GameMode),
+ WinGame(WinGameAction),
+ Demo(DemoEvent),
+ ArrowHitPlayer,
+ RainLevelChange(f32),
+ ThunderLevelChange(f32),
+ PufferfishSting,
+ ElderGuardianMobAppearance,
+ Respawn(RespawnRequestType),
+}
+
+impl Serialize for GameChangeReason {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ use GameChangeReason::*;
+ to.serialize_byte(match self {
+ NoRespawnAvailable => 0x00,
+ EndRaining => 0x01,
+ BeginRaining => 0x02,
+ ChangeGameMode(_) => 0x03,
+ WinGame(_) => 0x04,
+ Demo(_) => 0x05,
+ ArrowHitPlayer => 0x06,
+ RainLevelChange(_) => 0x07,
+ ThunderLevelChange(_) => 0x08,
+ PufferfishSting => 0x09,
+ ElderGuardianMobAppearance => 0x0A,
+ Respawn(_) => 0x0B,
+ })?;
+
+ let value = match self {
+ ChangeGameMode(body) => body.id() as f32,
+ WinGame(body) => body.id() as f32,
+ Demo(body) => body.id() as f32,
+ RainLevelChange(body) => *body,
+ ThunderLevelChange(body) => *body,
+ Respawn(body) => body.id() as f32,
+ _ => 0 as f32,
+ };
+ to.serialize_other(&value)
+ }
+}
+
+impl Deserialize for GameChangeReason {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized {
+ value: reason_id,
+ data,
+ } = u8::mc_deserialize(data)?;
+ let Deserialized { value, data } = f32::mc_deserialize(data)?;
+ use GameChangeReason::*;
+ match reason_id {
+ 0x00 => Deserialized::ok(NoRespawnAvailable, data),
+ 0x01 => Deserialized::ok(EndRaining, data),
+ 0x02 => Deserialized::ok(BeginRaining, data),
+ 0x03 => Ok(GameMode::deserialize_with_id(value as u8, data)?
+ .map(move |mode| ChangeGameMode(mode))),
+ 0x04 => Ok(WinGameAction::deserialize_with_id(value as u8, data)?
+ .map(move |mode| WinGame(mode))),
+ 0x05 => {
+ Ok(DemoEvent::deserialize_with_id(value as u8, data)?.map(move |mode| Demo(mode)))
+ }
+ 0x06 => Deserialized::ok(ArrowHitPlayer, data),
+ 0x07 => Deserialized::ok(RainLevelChange(value), data),
+ 0x08 => Deserialized::ok(ThunderLevelChange(value), data),
+ 0x09 => Deserialized::ok(PufferfishSting, data),
+ 0x0A => Deserialized::ok(ElderGuardianMobAppearance, data),
+ 0x0B => Ok(RespawnRequestType::deserialize_with_id(value as u8, data)?
+ .map(move |mode| Respawn(mode))),
+ other => Err(DeserializeErr::CannotUnderstandValue(alloc::format!(
+ "invalid game change reason id {}",
+ other
+ ))),
+ }
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for GameChangeReason {
+ fn test_gen_random() -> Self {
+ // todo
+ GameChangeReason::PufferfishSting
+ }
+}
+
+proto_varint_enum!(MapIconType,
+ 0x00 :: WhiteArrow,
+ 0x01 :: GreenArrow,
+ 0x02 :: RedArrow,
+ 0x03 :: BlueArrow,
+ 0x04 :: WhiteCross,
+ 0x05 :: RedPointer,
+ 0x06 :: WhiteCircle,
+ 0x07 :: SmallWhiteCircle,
+ 0x08 :: Mansion,
+ 0x09 :: Temple,
+ 0x0A :: WhiteBanner,
+ 0x0B :: OrangeBanner,
+ 0x0C :: MagentaBanner,
+ 0x0D :: LightBlueBanner,
+ 0x0E :: YellowBanner,
+ 0x0F :: LimeBanner,
+ 0x10 :: PinkBanner,
+ 0x11 :: GrayBanner,
+ 0x12 :: LightGrayBanner,
+ 0x13 :: CyanBanner,
+ 0x14 :: PurpleBanner,
+ 0x15 :: BlueBanner,
+ 0x16 :: BrownBanner,
+ 0x17 :: GreenBanner,
+ 0x18 :: RedBanner,
+ 0x19 :: BlackBanner,
+ 0x1A :: TreasureMarker
+);
+
+proto_struct!(MapIconSpec {
+ kind: MapIconType,
+ position: TopDownPosition<i8>,
+ direction: i8,
+ display_name: Option<Chat>
+});
+
+#[derive(Clone, PartialEq, Debug)]
+pub enum MapColumns {
+ NoUpdates,
+ Updated(MapColumnsSpec),
+}
+
+proto_struct!(MapColumnsSpec {
+ columns: u8,
+ rows: u8, // TODO: docs just say "Byte", should be i8?
+ position: TopDownPosition<u8>,
+ data: CountedArray<u8, VarInt>
+});
+
+impl Serialize for MapColumns {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ use MapColumns::*;
+ match self {
+ NoUpdates => to.serialize_other(&0u8),
+ Updated(body) => to.serialize_other(body),
+ }
+ }
+}
+
+impl Deserialize for MapColumns {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized {
+ value: columns,
+ data: rest,
+ } = u8::mc_deserialize(data)?;
+ use MapColumns::*;
+ match columns {
+ 0x00 => Deserialized::ok(NoUpdates, rest),
+ _ => Ok(MapColumnsSpec::mc_deserialize(data)?.map(move |v| Updated(v))),
+ }
+ }
+}
+
+impl Into<Option<MapColumnsSpec>> for MapColumns {
+ fn into(self) -> Option<MapColumnsSpec> {
+ use MapColumns::*;
+ match self {
+ NoUpdates => None,
+ Updated(body) => Some(body),
+ }
+ }
+}
+
+impl From<Option<MapColumnsSpec>> for MapColumns {
+ fn from(other: Option<MapColumnsSpec>) -> Self {
+ use MapColumns::*;
+ match other {
+ Some(body) => {
+ if body.columns == 0 {
+ NoUpdates
+ } else {
+ Updated(body)
+ }
+ }
+ None => NoUpdates,
+ }
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for MapColumns {
+ fn test_gen_random() -> Self {
+ <Option<MapColumnsSpec>>::test_gen_random().into()
+ }
+}
+
+proto_struct!(TradeSpec {
+ input_item_1: Slot,
+ output_item: Slot,
+ input_item_2: Slot,
+ trade_disabled: bool,
+ trade_uses: i32,
+ max_trade_uses: i32,
+ xp: i32,
+ special_price: i32,
+ price_multiplier: f32,
+ demand: i32
+});
+
+proto_varint_enum!(Hand,
+ 0x00 :: MainHand,
+ 0x01 :: OffHand
+);
+
+proto_varint_enum!(WindowType, // TODO: does 0x00 actually map to GenericOneRow?
+ 0x00 :: GenericOneRow,
+ 0x01 :: GenericTwoRow,
+ 0x02 :: GenericThreeRow,
+ 0x03 :: GenericFourRow,
+ 0x04 :: GenericFiveRow,
+ 0x05 :: GenericSixRow,
+ 0x06 :: GenericSquare,
+ 0x07 :: Anvil,
+ 0x08 :: Beacon,
+ 0x09 :: BlastFurnace,
+ 0x0A :: BrewingStand,
+ 0x0B :: CraftingTable,
+ 0x0C :: EnchantmentTable,
+ 0x0D :: Furnace,
+ 0x0E :: Grindstone,
+ 0x0F :: Hopper,
+ 0x10 :: Lectern,
+ 0x11 :: Loom,
+ 0x12 :: Merchant,
+ 0x13 :: ShulkerBox,
+ 0x14 :: Smoker,
+ 0x15 :: Cartography,
+ 0x16 :: StoneCutter
+);
+
+proto_byte_flag!(PlayerAbilityFlags,
+ 0x01 :: is_invulnerable set_invulnerable,
+ 0x02 :: is_flying set_flying,
+ 0x04 :: is_flight_allowed set_flight_allowed,
+ 0x08 :: is_instant_break set_instant_break
+);
+
+// proto_varint_enum!(CombatEvent,
+// 0x00 :: Enter,
+// 0x01 :: End(CombatEndSpec),
+// 0x02 :: EntityDead(CombatEntityDeadSpec)
+// );
+
+// proto_struct!(CombatEndSpec {
+// duration_ticks: VarInt,
+// entity_id: i32
+// });
+
+// proto_struct!(CombatEntityDeadSpec {
+// player_id: VarInt,
+// entity_id: i32,
+// message: Chat
+// });
+
+proto_struct!(PlayerInfoAction<A> {
+ uuid: UUID4,
+ action: A
+});
+
+proto_varint_enum!(PlayerInfoActionList,
+ 0x00 :: Add(CountedArray<PlayerInfoAction<PlayerAddActionSpec>, VarInt>),
+ 0x01 :: UpdateGameMode(CountedArray<PlayerInfoAction<GameMode>, VarInt>),
+ 0x02 :: UpdateLatency(CountedArray<PlayerInfoAction<VarInt>, VarInt>),
+ 0x03 :: UpdateDisplayName(CountedArray<PlayerInfoAction<Option<Chat>>, VarInt>),
+ 0x04 :: Remove(CountedArray<UUID4, VarInt>)
+);
+
+proto_struct!(PlayerAddActionSpec {
+ name: String,
+ properties: CountedArray<PlayerAddProperty, VarInt>,
+ game_mode: GameMode,
+ ping_ms: VarInt,
+ display_name: Option<Chat>
+});
+
+proto_struct!(PlayerAddProperty {
+ name: String,
+ value: String,
+ signature: Option<String>
+});
+
+proto_varint_enum!(FacePlayerKind,
+ 0x00 :: Feet,
+ 0x01 :: Eyes
+);
+
+proto_struct!(FacePlayerEntityTarget {
+ entity_id: VarInt,
+ kind: FacePlayerKind
+});
+
+proto_byte_flag!(PositionAndLookFlags,
+ 0x01 :: is_x_rel set_x_rel,
+ 0x02 :: is_y_rel set_y_rel,
+ 0x04 :: is_z_rel set_z_rel,
+ 0x08 :: is_y_rotation_rel set_y_rotation_rel,
+ 0x10 :: is_x_rotation_rel set_x_rotation_rel
+);
+
+proto_byte_enum!(EntityEffectKind,
+ 0x01 :: Speed,
+ 0x02 :: Slowness,
+ 0x03 :: Haste,
+ 0x04 :: MiningFatigue,
+ 0x05 :: Strength,
+ 0x06 :: InstantHealth,
+ 0x07 :: InstantDamage,
+ 0x08 :: JumpBoost,
+ 0x09 :: Nausea,
+ 0x0A :: Regeneration,
+ 0x0B :: Resistance,
+ 0x0C :: FireResistance,
+ 0x0D :: WaterBreathing,
+ 0x0E :: Invisibility,
+ 0x0F :: Blindness,
+ 0x10 :: NightVision,
+ 0x11 :: Hunger,
+ 0x12 :: Weakness,
+ 0x13 :: Poison,
+ 0x14 :: Wither,
+ 0x15 :: HealthBoost,
+ 0x16 :: Absorption,
+ 0x17 :: Saturation,
+ 0x18 :: Glowing,
+ 0x19 :: Levetation,
+ 0x1A :: Luck,
+ 0x1B :: Unluck,
+ 0x1C :: SlowFalling,
+ 0x1D :: ConduitPower,
+ 0x1E :: DolphinsGrace,
+ 0x1F :: BadOmen,
+ 0x20 :: HeroOfTheVillage
+);
+
+// proto_varint_enum!(WorldBorderAction,
+// 0x00 :: SetSize(WorldBorderSetSizeSpec),
+// 0x01 :: LerpSize(WorldBorderLerpSizeSpec),
+// 0x02 :: SetCenter(TopDownPosition<f64>),
+// 0x03 :: Initialize(WorldBorderInitiaializeSpec),
+// 0x04 :: SetWarningTime(WorldBorderWarningTimeSpec),
+// 0x05 :: SetWarningBlocks(WorldBorderWarningBlocksSpec)
+// );
+
+// proto_struct!(WorldBorderSetSizeSpec {
+// diameter: f64
+// });
+
+// proto_struct!(WorldBorderLerpSizeSpec {
+// old_diameter: f64,
+// new_diameter: f64,
+// speed: VarLong
+// });
+
+// proto_struct!(WorldBorderInitializeSpec {
+// position: TopDownPosition<f64>,
+// old_diameter: f64,
+// new_diameter: f64,
+// speed: VarLong,
+// portal_teleport_boundary: VarLong,
+// warning_time: VarInt,
+// warning_blocks: VarInt
+// });
+
+// proto_struct!(WorldBorderWarningTimeSpec {
+// warning_time: VarInt
+// });
+
+// proto_struct!(WorldBorderWarningBlocksSpec {
+// warning_blocks: VarInt
+// });
+
+proto_byte_enum!(ScoreboardPosition,
+ 0x00 :: List,
+ 0x01 :: Sidebar,
+ 0x02 :: BelowName,
+ 0x03 :: TeamSpecific(i8)
+);
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct EntityEquipmentEntry {
+ pub slot: EquipmentSlot,
+ pub item: Slot,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct EntityEquipmentArray {
+ data: Vec<EntityEquipmentEntry>,
+}
+
+impl Serialize for EntityEquipmentArray {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ if self.data.is_empty() {
+ return Err(SerializeErr::CannotSerialize(
+ "entity equipment must be non-empty to send!".to_owned(),
+ ));
+ }
+
+ let n = self.data.len();
+
+ for i in 0..n {
+ let is_last = i == n - 1;
+ let entry = self.data.get(i).expect("iter in bounds");
+ let mut slot_raw = entry.slot.id();
+ if !is_last {
+ slot_raw |= 0x80;
+ }
+ to.serialize_byte(slot_raw)?;
+ to.serialize_other(&entry.item)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl Deserialize for EntityEquipmentArray {
+ fn mc_deserialize(mut data: &[u8]) -> DeserializeResult<'_, Self> {
+ if data.is_empty() {
+ return DeserializeErr::Eof.into();
+ }
+
+ let mut out = Vec::new();
+ let mut has_next = true;
+ while has_next {
+ let Deserialized {
+ value: raw_slot_id,
+ data: rest,
+ } = u8::mc_deserialize(data)?;
+ has_next = raw_slot_id & 0x80 != 0;
+ let slot_id = raw_slot_id & 0x7F;
+ let Deserialized {
+ value: slot,
+ data: rest,
+ } = EquipmentSlot::deserialize_with_id(slot_id, rest)?;
+ let Deserialized {
+ value: item,
+ data: rest,
+ } = Slot::mc_deserialize(rest)?;
+ out.push(EntityEquipmentEntry { slot, item });
+ data = rest;
+ }
+
+ Deserialized::ok(Self { data: out }, data)
+ }
+}
+
+impl core::ops::Deref for EntityEquipmentArray {
+ type Target = Vec<EntityEquipmentEntry>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.data
+ }
+}
+
+impl core::ops::DerefMut for EntityEquipmentArray {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.data
+ }
+}
+
+impl From<Vec<EntityEquipmentEntry>> for EntityEquipmentArray {
+ fn from(data: Vec<EntityEquipmentEntry>) -> Self {
+ Self { data }
+ }
+}
+
+impl From<EntityEquipmentArray> for Vec<EntityEquipmentEntry> {
+ fn from(other: EntityEquipmentArray) -> Self {
+ other.data
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for EntityEquipmentArray {
+ fn test_gen_random() -> Self {
+ let mut out = Vec::new();
+
+ for slot in &[
+ EquipmentSlot::MainHand,
+ EquipmentSlot::OffHand,
+ EquipmentSlot::ArmorBoots,
+ EquipmentSlot::ArmorLeggings,
+ EquipmentSlot::ArmorChestplate,
+ EquipmentSlot::ArmorHelmet,
+ ] {
+ out.push(EntityEquipmentEntry {
+ slot: slot.clone(),
+ item: Slot::test_gen_random(),
+ });
+ }
+
+ out.into()
+ }
+}
+
+proto_byte_enum!(EquipmentSlot,
+ 0x00 :: MainHand,
+ 0x01 :: OffHand,
+ 0x02 :: ArmorBoots,
+ 0x03 :: ArmorLeggings,
+ 0x04 :: ArmorChestplate,
+ 0x05 :: ArmorHelmet
+);
+
+proto_byte_enum!(ScoreboardObjectiveAction,
+ 0x00 :: Create(ScoreboardObjectiveSpec),
+ 0x01 :: Remove,
+ 0x02 :: UpdateText(ScoreboardObjectiveSpec)
+);
+
+proto_varint_enum!(ScoreboardObjectiveKind,
+ 0x00 :: Integer,
+ 0x01 :: Hearts
+);
+
+proto_struct!(ScoreboardObjectiveSpec {
+ text: Chat,
+ kind: ScoreboardObjectiveKind
+});
+
+proto_struct!(AdvancementMappingEntrySpec {
+ key: String,
+ value: AdvancementSpec
+});
+
+proto_struct!(AdvancementSpec {
+ parent: Option<String>,
+ display: Option<AdvancementDisplaySpec>,
+ criteria: CountedArray<String, VarInt>,
+ requirements: CountedArray<CountedArray<String, VarInt>, VarInt>
+});
+
+proto_struct!(AdvancementDisplaySpec {
+ title: Chat,
+ description: Chat,
+ icon: Slot,
+ frame_type: AdvancementFrameType,
+ flags: AdvancementDisplayFlags,
+ position: Vec2<f32>
+});
+
+proto_struct!(SlotAtSpec {
+ number: i16,
+ data: Slot
+});
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct AdvancementDisplayFlags {
+ pub background_texture: Option<String>,
+ pub show_toast: bool,
+ pub hidden: bool,
+}
+
+impl Serialize for AdvancementDisplayFlags {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let mut raw_flags: i32 = 0;
+ if self.background_texture.is_some() {
+ raw_flags |= 0x01;
+ }
+ if self.show_toast {
+ raw_flags |= 0x02;
+ }
+ if self.hidden {
+ raw_flags |= 0x04;
+ }
+
+ to.serialize_other(&raw_flags)?;
+ if let Some(texture) = &self.background_texture {
+ to.serialize_other(texture)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl Deserialize for AdvancementDisplayFlags {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized {
+ value: raw_flags,
+ data,
+ } = i32::mc_deserialize(data)?;
+ let has_background_texture = raw_flags & 0x01 != 0;
+ let show_toast = raw_flags & 0x02 != 0;
+ let hidden = raw_flags & 0x04 != 0;
+
+ Ok(if has_background_texture {
+ String::mc_deserialize(data)?.map(move |id| Some(id))
+ } else {
+ Deserialized { value: None, data }
+ }
+ .map(move |background_texture| Self {
+ background_texture,
+ show_toast,
+ hidden,
+ }))
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for AdvancementDisplayFlags {
+ fn test_gen_random() -> Self {
+ let background_texture = if rand::random::<bool>() {
+ Some(String::test_gen_random())
+ } else {
+ None
+ };
+ let show_toast = rand::random::<bool>();
+ let hidden = rand::random::<bool>();
+
+ Self {
+ background_texture,
+ show_toast,
+ hidden,
+ }
+ }
+}
+
+proto_varint_enum!(AdvancementFrameType,
+ 0x00 :: Task,
+ 0x01 :: Challenge,
+ 0x02 :: Goal
+);
+
+proto_struct!(AdvancementProgressEntrySpec {
+ key: String,
+ value: AdvancementProgressSpec
+});
+
+proto_struct!(AdvancementProgressSpec {
+ criteria: CountedArray<AdvancementCriteriaSpec, VarInt>
+});
+
+proto_struct!(AdvancementCriteriaSpec {
+ identifier: String,
+ progress: AdvancementCriterionProgressSpec
+});
+
+proto_struct!(AdvancementCriterionProgressSpec {
+ achieved_at: Option<i64>
+});
+
+proto_struct!(EntityPropertySpec {
+ key: String,
+ value: f64,
+ modifiers: CountedArray<EntityPropertyModifierSpec, VarInt>
+});
+
+proto_struct!(EntityPropertyModifierSpec {
+ uuid: UUID4,
+ amount: f64,
+ operation: EntityPropertyModifierOperation
+});
+
+proto_byte_enum!(EntityPropertyModifierOperation,
+ 0x00 :: AddSubtractAmount,
+ 0x01 :: AddSubtractAmountPercentOfCurrent,
+ 0x02 :: MultiplyByAmountPercent
+);
+
+proto_byte_flag!(EntityEffectFlags,
+ 0x01 :: is_ambient set_ambient,
+ 0x02 :: is_show_particles set_show_particles,
+ 0x04 :: is_show_icon set_show_icon
+);
+
+proto_struct!(TagSpec {
+ name: String,
+ entries: CountedArray<VarInt, VarInt>
+});
+
+proto_varint_enum!(ClientStatusAction,
+ 0x00 :: PerformRespawn,
+ 0x01 :: RequestStats
+);
+
+proto_varint_enum!(ClientChatMode,
+ 0x00 :: Enabled,
+ 0x01 :: CommandsOnly,
+ 0x02 :: Hidden
+);
+
+proto_varint_enum!(ClientMainHand,
+ 0x00 :: Left,
+ 0x01 :: Right
+);
+
+proto_byte_flag!(ClientDisplayedSkinParts,
+ 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_pant_legs_enabled set_right_pant_legs_enabled,
+ 0x40 :: is_hat_enabled set_hat_enabled
+);
+
+proto_varint_enum!(InventoryOperationMode,
+ 0x00 :: MouseClick,
+ 0x01 :: ShiftClick,
+ 0x02 :: NumberClick,
+ 0x03 :: MiddleClick,
+ 0x04 :: DropClick,
+ 0x05 :: Drag,
+ 0x06 :: DoubleClick
+);
+
+proto_struct!(InteractAtSpec {
+ target_position: Vec3<f32>,
+ hand: Hand
+});
+
+proto_varint_enum!(InteractKind,
+ 0x00 :: Interact(Hand),
+ 0x01 :: Attack,
+ 0x02 :: InteractAt(InteractAtSpec)
+);
+
+proto_byte_flag!(ClientPlayerAbilities,
+ 0x01 :: is_creative set_creative,
+ 0x02 :: is_flying set_flying,
+ 0x04 :: is_fly_enabled set_fly_enabled,
+ 0x08 :: is_damaged_disabled set_damaged_disabled
+);
+
+proto_varint_enum!(PlayerDiggingStatus,
+ 0x00 :: Started,
+ 0x01 :: Cancelled,
+ 0x02 :: Finished,
+ 0x03 :: DropStack,
+ 0x04 :: DropItem,
+ 0x05 :: ShootArrowOrFishEating,
+ 0x06 :: SwapItemInHand
+);
+
+proto_byte_enum!(DiggingFace,
+ 0x00 :: Bottom,
+ 0x01 :: Top,
+ 0x02 :: North,
+ 0x03 :: South,
+ 0x04 :: West,
+ 0x05 :: East
+);
+
+proto_varint_enum!(EntityActionKind,
+ 0x00 :: StartSneaking,
+ 0x01 :: StopSneaking,
+ 0x02 :: LeaveBed,
+ 0x03 :: StartSprinting,
+ 0x04 :: StopSprinting,
+ 0x05 :: StartJumpWithHorse,
+ 0x06 :: StopJumpWithHorse,
+ 0x07 :: OpenHorseInventory,
+ 0x08 :: StartFlyingWithElytra
+);
+
+proto_byte_flag!(SteerVehicleFlags,
+ 0x01 :: is_jump set_jump,
+ 0x02 :: is_unmount set_unmount
+);
+
+proto_varint_enum!(RecipeBookType,
+ 0x00 :: Crafting,
+ 0x01 :: Furnace,
+ 0x02 :: BlastFurnace,
+ 0x03 :: Smoker
+);
+
+proto_varint_enum!(ResourcePackStatus,
+ 0x00 :: Loaded,
+ 0x01 :: Declined,
+ 0x02 :: FailedDownload,
+ 0x03 :: Accepted
+);
+
+proto_varint_enum!(AdvancementTabAction,
+ 0x00 :: Opened(String),
+ 0x01 :: Closed
+);
+
+proto_varint_enum!(CommandBlockMode,
+ 0x00 :: Sequence,
+ 0x01 :: Auto,
+ 0x02 :: Redstone
+);
+
+proto_byte_flag!(CommandBlockFlags,
+ 0x01 :: is_track_output set_track_output,
+ 0x02 :: is_conditional set_conditional,
+ 0x04 :: is_automatic set_automatic
+);
+
+proto_varint_enum!(UpdateStructureBlockAction,
+ 0x00 :: UpdateData,
+ 0x01 :: SaveStructure,
+ 0x02 :: LoadStructure,
+ 0x03 :: DetectSize
+);
+
+proto_varint_enum!(UpdateStructureBlockMode,
+ 0x00 :: Save,
+ 0x01 :: Load,
+ 0x02 :: Corner,
+ 0x03 :: Data
+);
+
+proto_varint_enum!(UpdateStructureBlockMirror,
+ 0x00 :: NoMirror,
+ 0x01 :: LeftRight,
+ 0x02 :: FrontBack
+);
+
+proto_varint_enum!(UpdateStructureBlockRotation,
+ 0x00 :: NoRotation,
+ 0x01 :: Clockwise90,
+ 0x02 :: Clockwise180,
+ 0x03 :: CounterClockwise90
+);
+
+proto_byte_flag!(UpdateStructureBlockFlags,
+ 0x01 :: is_ignore_entities set_ignore_entities,
+ 0x02 :: is_show_air set_show_air,
+ 0x04 :: is_show_bounding_box set_show_bounding_box
+);
+
+#[derive(Clone, PartialEq, Debug)]
+pub struct RecipeSpec {
+ pub recipe: Recipe,
+ pub id: String,
+}
+
+proto_str_enum!(Recipe,
+ "minecraft:crafting_shapeless" :: CraftingShapeless(RecipeCraftingShapelessSpec),
+ "minecraft:crafting_shaped" :: CraftingShaped(RecipeCraftingShapedSpec),
+ "minecraft:crafting_special_armordye" :: CraftingArmorDye,
+ "minecraft:crafting_special_bookcloning" :: CraftingBookCloning,
+ "minecraft:crafting_special_mapcloning" :: CraftingMapCloning,
+ "minecraft:crafting_special_mapextending" :: CraftingMapExtending,
+ "minecraft:crafting_special_firework_rocket" :: CraftingFireworkRocket,
+ "minecraft:crafting_special_firework_star" :: CraftingFireworkStar,
+ "minecraft:crafting_special_firework_star_fade" :: CraftingFireworkStarFade,
+ "minecraft:crafting_special_repairitem" :: CraftingRepairItem,
+ "minecraft:crafting_special_tippedarrow" :: CraftingTippedArrow,
+ "minecraft:crafting_special_bannerduplicate" :: CraftingBannerDuplicate,
+ "minecraft:crafting_special_banneraddpattern" :: CraftingBannerAddPattern,
+ "minecraft:crafting_special_shielddecoration" :: CraftingShieldDecoration,
+ "minecraft:crafting_special_shulkerboxcoloring" :: CraftingShulkerBoxColoring,
+ "minecraft:crafting_special_suspiciousstew" :: CraftingSuspiciousStew,
+ "minecraft:smelting" :: Smelting(RecipeSmeltingSpec),
+ "minecraft:blasting" :: Blasting(RecipeSmeltingSpec),
+ "minecraft:smoking" :: Smoking(RecipeSmeltingSpec),
+ "minecraft:campfire_cooking" :: CampfireCooking(RecipeSmeltingSpec),
+ "minecraft:stonecutting" :: StoneCutting(RecipeStonecuttingSpec),
+ "minecraft:smithing" :: Smithing(RecipeSmithingSpec)
+);
+
+impl Serialize for RecipeSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let _type = self.recipe.id();
+ to.serialize_other(&_type)?;
+ to.serialize_other(&self.id)?;
+ self.recipe.serialize_body(to)
+ }
+}
+
+impl Deserialize for RecipeSpec {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: _type, data } = String::mc_deserialize(data)?;
+ let Deserialized {
+ value: recipe_id,
+ data,
+ } = String::mc_deserialize(data)?;
+
+ Ok(
+ Recipe::deserialize_with_id(_type.as_str(), data)?.map(move |recipe| RecipeSpec {
+ id: recipe_id,
+ recipe,
+ }),
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for RecipeSpec {
+ fn test_gen_random() -> Self {
+ RecipeSpec {
+ recipe: Recipe::test_gen_random(),
+ id: String::test_gen_random(),
+ }
+ }
+}
+
+proto_struct!(RecipeIngredient {
+ items: CountedArray<Slot, VarInt>
+});
+
+proto_struct!(RecipeCraftingShapelessSpec {
+ group: String,
+ ingredients: CountedArray<RecipeIngredient, VarInt>,
+ result: Slot
+});
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct RecipeCraftingShapedSpec {
+ pub width: VarInt,
+ pub height: VarInt,
+ pub group: String,
+ pub ingredients: Vec<RecipeIngredient>,
+ pub result: Slot,
+}
+
+impl Serialize for RecipeCraftingShapedSpec {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ to.serialize_other(&self.width)?;
+ to.serialize_other(&self.height)?;
+ to.serialize_other(&self.group)?;
+ for elem in &self.ingredients {
+ to.serialize_other(elem)?;
+ }
+ to.serialize_other(&self.result)?;
+ Ok(())
+ }
+}
+
+impl Deserialize for RecipeCraftingShapedSpec {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized { value: width, data } = <VarInt>::mc_deserialize(data)?;
+ let Deserialized {
+ value: height,
+ data,
+ } = <VarInt>::mc_deserialize(data)?;
+ let Deserialized {
+ value: group,
+ mut data,
+ } = <String>::mc_deserialize(data)?;
+
+ let ingredients_count = width.0 as usize * height.0 as usize;
+ let mut ingredients: Vec<RecipeIngredient> = Vec::with_capacity(ingredients_count);
+ for _ in 0..ingredients_count {
+ let Deserialized {
+ value: elem,
+ data: rest,
+ } = RecipeIngredient::mc_deserialize(data)?;
+ data = rest;
+ ingredients.push(elem);
+ }
+
+ let Deserialized {
+ value: result,
+ data,
+ } = Slot::mc_deserialize(data)?;
+
+ Deserialized::ok(
+ Self {
+ width,
+ height,
+ group,
+ ingredients,
+ result,
+ },
+ data,
+ )
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for RecipeCraftingShapedSpec {
+ fn test_gen_random() -> Self {
+ use rand::distributions::Distribution;
+ let size_distr = rand::distributions::Uniform::new(1, 9);
+ let mut rng = rand::thread_rng();
+
+ let width: VarInt = size_distr.sample(&mut rng).into();
+ let height: VarInt = size_distr.sample(&mut rng).into();
+ let n_ingredients = (width.0 as usize) * (height.0 as usize);
+ let mut ingredients = Vec::with_capacity(n_ingredients);
+ for _ in 0..n_ingredients {
+ ingredients.push(RecipeIngredient::test_gen_random());
+ }
+
+ RecipeCraftingShapedSpec {
+ width,
+ height,
+ group: String::test_gen_random(),
+ ingredients,
+ result: Some(ItemStack::test_gen_random()),
+ }
+ }
+}
+
+proto_struct!(RecipeSmeltingSpec {
+ group: String,
+ ingredient: RecipeIngredient,
+ result: Slot,
+ experience: f32,
+ cooking_time: VarInt
+});
+
+proto_struct!(RecipeStonecuttingSpec {
+ group: String,
+ ingredient: RecipeIngredient,
+ result: Slot
+});
+
+proto_struct!(RecipeSmithingSpec {
+ base: RecipeIngredient,
+ addition: RecipeIngredient,
+ result: Slot
+});
+
+proto_varint_enum!(RecipeUnlockAction,
+ 0x00 :: Init,
+ 0x01 :: Add,
+ 0x02 :: Remove
+);
+
+// #[derive(Clone, PartialEq, Debug)]
+// pub struct ChunkData {
+// pub position: ChunkPosition<i32>,
+// pub primary_bit_mask: VarInt,
+// pub heightmaps: NamedNbtTag,
+// pub biomes: Option<CountedArray<VarInt, VarInt>>,
+// pub data: CountedArray<u8, VarInt>,
+// pub block_entities: Vec<NamedNbtTag>,
+// }
+
+// impl Serialize for ChunkData {
+// fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+// to.serialize_other(&self.position)?;
+// let full_chunk = self.biomes.is_some();
+// to.serialize_other(&full_chunk)?;
+// to.serialize_other(&self.primary_bit_mask)?;
+// to.serialize_other(&self.heightmaps)?;
+
+// if full_chunk {
+// to.serialize_other(self.biomes.as_ref().unwrap())?;
+// }
+
+// to.serialize_other(&self.data)?;
+// let num_block_entities = VarInt(self.block_entities.len() as i32);
+// to.serialize_other(&num_block_entities)?;
+// for entity in &self.block_entities {
+// to.serialize_other(entity)?;
+// }
+
+// Ok(())
+// }
+// }
+
+// impl Deserialize for ChunkData {
+// fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+// let Deserialized { value: position, data } = <ChunkPosition<i32>>::mc_deserialize(data)?;
+// let Deserialized { value: is_full_chunk, data } = bool::mc_deserialize(data)?;
+// let Deserialized { value: primary_bit_mask, data } = VarInt::mc_deserialize(data)?;
+// let Deserialized { value: heightmaps, mut data } = NamedNbtTag::mc_deserialize(data)?;
+// let biomes = if is_full_chunk {
+// let Deserialized { value: biomes, data: rest } = <CountedArray<VarInt, VarInt>>::mc_deserialize(data)?;
+// data = rest;
+// Some(biomes)
+// } else {
+// None
+// };
+// let Deserialized { value: chunk_data, data } = <CountedArray<u8, VarInt>>::mc_deserialize(data)?;
+// let Deserialized { value: n_block_entities_raw, mut data } = VarInt::mc_deserialize(data)?;
+// let n_block_entities = n_block_entities_raw.0 as usize;
+// let mut block_entities = Vec::with_capacity(n_block_entities);
+// for _ in 0..n_block_entities {
+// let Deserialized { value: entity, data: rest } = NamedNbtTag::mc_deserialize(data)?;
+// data = rest;
+// block_entities.push(entity);
+// }
+
+// Deserialized::ok(ChunkData {
+// position,
+// primary_bit_mask,
+// heightmaps,
+// biomes,
+// data: chunk_data,
+// block_entities,
+// }, data)
+// }
+// // }
+
+// #[cfg(all(test, feature = "std"))]
+// impl TestRandom for ChunkData {
+// fn test_gen_random() -> Self {
+// ChunkData {
+// position: <ChunkPosition<i32>>::test_gen_random(),
+// primary_bit_mask: VarInt::test_gen_random(),
+// heightmaps: NamedNbtTag::test_gen_random(),
+// biomes: None,
+// data: <CountedArray<u8, VarInt>>::test_gen_random(),
+// block_entities: vec![],
+// }
+// }
+// }
+
+// pub const LIGHT_DATA_LENGTH: usize = 2048;
+// pub const LIGHT_DATA_SECTIONS: usize = 18;
+
+// #[derive(Clone, PartialEq)]
+// pub struct LightingData {
+// pub data: Box<[Option<[u8; LIGHT_DATA_LENGTH]>; LIGHT_DATA_SECTIONS]>,
+// }
+
+// impl LightingData {
+// fn deserialize(update_mask: VarInt, mut data: &[u8]) -> DeserializeResult<Self> {
+// let mut out = Box::new([None; LIGHT_DATA_SECTIONS]);
+// for i in 0..LIGHT_DATA_SECTIONS {
+// // gotta read the var int
+// if update_mask.0 & (1 << i) != 0 {
+// let Deserialized { value: length, data: rest } = VarInt::mc_deserialize(data)?;
+// if (length.0 as usize) != LIGHT_DATA_LENGTH {
+// return Err(DeserializeErr::CannotUnderstandValue(alloc::format!("bad data length in light update {}", length)));
+// }
+
+// data = rest;
+// if data.len() < LIGHT_DATA_LENGTH {
+// return Err(DeserializeErr::Eof);
+// }
+
+// let (section, rest) = data.split_at(LIGHT_DATA_LENGTH);
+// let mut to_vec = [0u8; LIGHT_DATA_LENGTH];
+// to_vec.copy_from_slice(section);
+// out[i] = Some(to_vec);
+// data = rest;
+// }
+// }
+
+// let result = Self {
+// data: out,
+// };
+
+// Deserialized::ok(result, data)
+// }
+
+// fn update_mask(&self) -> VarInt {
+// self.compute_has_mask(true)
+// }
+
+// fn reset_mask(&self) -> VarInt {
+// self.compute_has_mask(false)
+// }
+
+// fn compute_has_mask(&self, has: bool) -> VarInt {
+// let mut out: u32 = 0;
+// for i in 0..LIGHT_DATA_SECTIONS {
+// if self.data[i].is_some() == has {
+// out |= 1 << i;
+// }
+// }
+
+// VarInt(out as i32)
+// }
+
+// fn serialize_data<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+// for item in self.data.iter() {
+// if let Some(contents) = item {
+// to.serialize_other(&VarInt(2048))?;
+// to.serialize_bytes(&contents[..])?;
+// }
+// }
+
+// Ok(())
+// }
+// }
+
+// impl fmt::Debug for LightingData {
+// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+// write!(
+// f,
+// "LightingData(update={:018b}, reset={:018b}, size={}, bytes={})",
+// self.update_mask().0,
+// self.reset_mask().0,
+// self.data.iter().filter(move |v| v.is_some()).count(),
+// self.data.iter()
+// .filter_map(move |v| v.
+// map(move |arr| arr.len()))
+// .sum::<usize>())
+// }
+// }
+
+// impl fmt::Display for LightingData {
+// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+// <dyn fmt::Debug>::fmt(self, f)
+// }
+// }
+
+// #[cfg(all(test, feature = "std"))]
+// impl LightingData {
+// fn gen_random_mask() -> i32 {
+// let rand: u32 = rand::random();
+// (rand & ((1 << 19) - 1)) as i32
+// }
+// }
+
+// #[cfg(all(test, feature = "std"))]
+// impl TestRandom for LightingData {
+// fn test_gen_random() -> Self {
+// let set_mask = Self::gen_random_mask();
+// let mut data = Box::new([None; LIGHT_DATA_SECTIONS]);
+// for i in 0..LIGHT_DATA_SECTIONS {
+// if (set_mask & (1 << i)) != 0 {
+// let mut data_arr = [0u8; LIGHT_DATA_LENGTH];
+// for k in 0..LIGHT_DATA_LENGTH {
+// data_arr[k] = rand::random();
+// }
+// data[i] = Some(data_arr);
+// }
+// }
+
+// Self {
+// data,
+// }
+// }
+// }
+
+// #[derive(Clone, PartialEq, Debug)]
+// pub struct LightingUpdateSpec {
+// pub skylight_data: LightingData,
+// pub blocklight_data: LightingData,
+// }
+
+// impl Serialize for LightingUpdateSpec {
+// fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+// self.skylight_data.update_mask().mc_serialize(to)?;
+// self.blocklight_data.update_mask().mc_serialize(to)?;
+// self.skylight_data.reset_mask().mc_serialize(to)?;
+// self.blocklight_data.reset_mask().mc_serialize(to)?;
+// self.skylight_data.serialize_data(to)?;
+// self.blocklight_data.serialize_data(to)
+// }
+// }
+
+// impl Deserialize for LightingUpdateSpec {
+// fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+// let Deserialized { value: skylight_update_mask, data } = VarInt::mc_deserialize(data)?;
+// let Deserialized { value: blocklight_update_mask, data } = VarInt::mc_deserialize(data)?;
+// let Deserialized { value: _, data } = VarInt::mc_deserialize(data)?;
+// let Deserialized { value: _, data } = VarInt::mc_deserialize(data)?;
+
+// let Deserialized { value: skylight_data, data } = LightingData::deserialize(skylight_update_mask, data)?;
+// let Deserialized { value: blocklight_data, data } = LightingData::deserialize(blocklight_update_mask, data)?;
+
+// Deserialized::ok(Self {
+// skylight_data,
+// blocklight_data,
+// }, data)
+// }
+// }
+
+// #[cfg(all(test, feature = "std"))]
+// impl TestRandom for LightingUpdateSpec {
+// fn test_gen_random() -> Self {
+// Self {
+// skylight_data: LightingData::test_gen_random(),
+// blocklight_data: LightingData::test_gen_random(),
+// }
+// }
+// }
+
+#[derive(Clone, Debug, PartialEq, Default)]
+pub struct EntityMetadata {
+ pub fields: Vec<EntityMetadataField>,
+}
+
+impl Serialize for EntityMetadata {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ for field in &self.fields {
+ to.serialize_byte(field.index)?;
+ to.serialize_other(&field.data)?;
+ }
+ to.serialize_byte(0xFF)
+ }
+}
+
+impl Deserialize for EntityMetadata {
+ fn mc_deserialize(mut data: &[u8]) -> DeserializeResult<'_, Self> {
+ let mut fields = Vec::new();
+ loop {
+ let Deserialized {
+ value: index,
+ data: rest,
+ } = u8::mc_deserialize(data)?;
+ data = rest;
+ if index == 0xFF {
+ break;
+ }
+
+ let Deserialized {
+ value: field,
+ data: rest,
+ } = EntityMetadataFieldData::mc_deserialize(data)?;
+ data = rest;
+ fields.push(EntityMetadataField { index, data: field });
+ }
+
+ Deserialized::ok(Self { fields }, data)
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
+impl TestRandom for EntityMetadata {
+ fn test_gen_random() -> Self {
+ let n_fields = rand::random::<usize>() % 10;
+ let mut fields = Vec::with_capacity(n_fields);
+ for i in 0..n_fields {
+ fields.push(EntityMetadataField {
+ index: i as u8,
+ data: EntityMetadataFieldData::test_gen_random(),
+ });
+ }
+
+ Self { fields }
+ }
+}
+
+impl EntityMetadata {
+ pub fn set(&mut self, index: u8, data: EntityMetadataFieldData) {
+ for field in &mut self.fields {
+ if field.index == index {
+ field.data = data;
+ return;
+ }
+ }
+
+ self.fields.push(EntityMetadataField { index, data })
+ }
+
+ pub fn remove(&mut self, index: u8) -> bool {
+ for i in 0..self.fields.len() {
+ let field = self
+ .fields
+ .get(i)
+ .expect("iterating through this vec, definitely have this index");
+ if field.index == index {
+ self.fields.remove(i);
+ return true;
+ }
+ }
+
+ false
+ }
+
+ pub fn get(&self, index: u8) -> Option<&EntityMetadataFieldData> {
+ for field in &self.fields {
+ if field.index == index {
+ return Some(&field.data);
+ }
+ }
+
+ None
+ }
+
+ pub fn get_mut(&mut self, index: u8) -> Option<&mut EntityMetadataFieldData> {
+ for field in &mut self.fields {
+ if field.index == index {
+ return Some(&mut field.data);
+ }
+ }
+
+ None
+ }
+}
+
+impl<'a> core::iter::IntoIterator for &'a EntityMetadata {
+ type Item = (u8, &'a EntityMetadataFieldData);
+ type IntoIter = FieldIter<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ FieldIter { data: self, at: 0 }
+ }
+}
+
+pub struct FieldIter<'a> {
+ data: &'a EntityMetadata,
+ at: usize,
+}
+
+impl<'a> core::iter::Iterator for FieldIter<'a> {
+ type Item = (u8, &'a EntityMetadataFieldData);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.data
+ .fields
+ .get(self.at)
+ .map(move |field| (field.index, &field.data))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.data.fields.len();
+ (len, Some(len))
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct EntityMetadataField {
+ pub index: u8,
+ pub data: EntityMetadataFieldData,
+}
+
+proto_varint_enum!(EntityMetadataFieldData,
+ 0x00 :: Byte(i8),
+ 0x01 :: VarInt(VarInt),
+ 0x02 :: Float(f32),
+ 0x03 :: String(String),
+ 0x04 :: Chat(Chat),
+ 0x05 :: OptChat(Option<Chat>),
+ 0x06 :: Slot(Slot),
+ 0x07 :: Boolean(bool),
+ 0x08 :: Rotation(Vec3<f32>),
+ 0x09 :: Position(IntPosition),
+ 0x0A :: OptPosition(Option<IntPosition>),
+ 0x0B :: Direction(EntityDirection),
+ 0x0C :: OptUUID(Option<UUID4>),
+ 0x0D :: OptBlockId(VarInt),
+ 0x0E :: NBT(NamedNbtTag),
+ 0x0F :: Particle(ParticleSpec),
+ 0x10 :: VillagerData(EntityVillagerData),
+ 0x11 :: OptVarInt(VarInt),
+ 0x12 :: Pose(EntityPose)
+);
+
+proto_varint_enum!(EntityDirection,
+ 0x00 :: Down,
+ 0x01 :: Up,
+ 0x02 :: North,
+ 0x03 :: South,
+ 0x04 :: West,
+ 0x05 :: East
+);
+
+proto_struct!(EntityVillagerData {
+ villager_type: VillagerType,
+ villager_profession: VillagerProfession,
+ level: VarInt
+});
+
+proto_varint_enum!(VillagerType,
+ 0x00 :: Desert,
+ 0x01 :: Jungle,
+ 0x02 :: Plains,
+ 0x03 :: Savanna,
+ 0x04 :: Snow,
+ 0x05 :: Swamp,
+ 0x06 :: Taiga
+);
+
+proto_varint_enum!(VillagerProfession,
+ 0x00 :: None,
+ 0x01 :: Armorer,
+ 0x02 :: Butcher,
+ 0x03 :: Cartographer,
+ 0x04 :: Cleric,
+ 0x05 :: Farmer,
+ 0x06 :: Fisherman,
+ 0x07 :: Fletcher,
+ 0x08 :: LeatherWorker,
+ 0x09 :: Librarian,
+ 0x0A :: Mason,
+ 0x0B :: Nitwit,
+ 0x0C :: Shepherd,
+ 0x0D :: Toolsmith,
+ 0x0E :: Weaponsmith
+);
+
+proto_varint_enum!(EntityPose,
+ 0x00 :: Standing,
+ 0x01 :: FallFlying,
+ 0x02 :: Sleeping,
+ 0x03 :: Swimming,
+ 0x04 :: SpinAttack,
+ 0x05 :: Sneaking,
+ 0x06 :: LongJumping,
+ 0x07 :: Dying
+);
+
+proto_varint_enum!(ParticleSpec,
+ 0x00 :: AmbientEntityEffect,
+ 0x01 :: AngryVillager,
+ 0x02 :: Barrier,
+ 0x03 :: Light,
+ 0x04 :: Block(BlockParticleData),
+ 0x05 :: Bubble,
+ 0x06 :: Cloud,
+ 0x07 :: Crit,
+ 0x08 :: DamageIndicator,
+ 0x09 :: DragonBreath,
+ 0x0A :: DrippingLava,
+ 0x0B :: FallingLava,
+ 0x0C :: LandingLava,
+ 0x0D :: DrippingWater,
+ 0x0E :: FallingWater,
+ 0x0F :: Dust(DustParticleData),
+ 0x10 :: DustColorTransition(DustColorTransitionData),
+ 0x11 :: Effect,
+ 0x12 :: ElderGuardian,
+ 0x13 :: EnchantedHit,
+ 0x14 :: Enchant,
+ 0x15 :: EndRod,
+ 0x16 :: EntityEffect,
+ 0x17 :: ExplosionEmitter,
+ 0x18 :: Explosion,
+ 0x19 :: FallingDust(DustParticleData),
+ 0x1A :: Firework,
+ 0x1B :: Fishing,
+ 0x1C :: Flame,
+ 0x1D :: SoulFireFlame,
+ 0x1E :: Soul,
+ 0x1F :: Flash,
+ 0x20 :: HappyVillager,
+ 0x21 :: Composter,
+ 0x22 :: Heart,
+ 0x23 :: InstantEffect,
+ 0x24 :: Item(Slot),
+ 0x25 :: Vibration(VibrationData),
+ 0x26 :: ItemSlime,
+ 0x27 :: ItemSnowball,
+ 0x28 :: LargeSmoke,
+ 0x29 :: Lava,
+ 0x2A :: Mycelium,
+ 0x2B :: Note,
+ 0x2C :: Poof,
+ 0x2D :: Portal,
+ 0x2E :: Rain,
+ 0x2F :: Smoke,
+ 0x30 :: Sneeze,
+ 0x31 :: Spit,
+ 0x32 :: SquidInk,
+ 0x33 :: SweepAttack,
+ 0x34 :: TotemOfUndying,
+ 0x35 :: Underwater,
+ 0x36 :: Splash,
+ 0x37 :: Witch,
+ 0x38 :: BubblePop,
+ 0x39 :: CurrentDown,
+ 0x3A :: BubbleColumnUp,
+ 0x3B :: Nautilus,
+ 0x3C :: Dolphin,
+ 0x3D :: CampfireCosySmoke,
+ 0x3E :: CampfireSignalSmoke,
+ 0x3F :: DrippingHoney,
+ 0x40 :: FallingHoney,
+ 0x41 :: LandingHoney,
+ 0x42 :: FallingNectar,
+ 0x43 :: FallingSporeBlossom,
+ 0x44 :: Ash,
+ 0x45 :: CrimsonSpore,
+ 0x46 :: WarpedSpore,
+ 0x47 :: SporeBlossomAir,
+ 0x48 :: DrippingObsidianTear,
+ 0x49 :: FallingObsidianTear,
+ 0x4A :: LandingObsidianTear,
+ 0x4B :: ReversePortal,
+ 0x4C :: WhiteAsh,
+ 0x4D :: SmallFlame,
+ 0x4E :: Snowflake,
+ 0x4F :: DrippingDripstoneLava,
+ 0x50 :: FallingDripstoneLava,
+ 0x51 :: DrippingDripstoneWater,
+ 0x52 :: FallingDripstoneWater,
+ 0x53 :: GlowSquidInk,
+ 0x54 :: Glow,
+ 0x55 :: WaxOn,
+ 0x56 :: WaxOff,
+ 0x57 :: ElectricSpark,
+ 0x58 :: Scrape
+);
+
+proto_struct!(BlockParticleData {
+ block_state: VarInt
+});
+
+proto_struct!(DustParticleData {
+ red: f32,
+ green: f32,
+ blue: f32,
+ scale: f32
+});
+
+proto_struct!(DustColorTransitionData {
+ from_red: f32,
+ from_green: f32,
+ from_blue: f32,
+ scale: f32,
+ to_red: f32,
+ to_green: f32,
+ to_blue: f32
+});
+
+proto_struct!(VibrationData {
+ origin_x: f64,
+ origin_y: f64,
+ origin_z: f64,
+ dest_x: f64,
+ dest_y: f64,
+ dest_z: f64
+});
+
+#[cfg(all(test, feature = "std"))]
+pub mod tests {
+ use super::*;
+ use crate::packet_test_cases;
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ Handshake,
+ HandshakeSpec,
+ test_handshake,
+ bench_write_handshake,
+ bench_read_handshake
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ StatusRequest,
+ StatusRequestSpec,
+ test_status_request,
+ bench_write_status_request,
+ bench_read_status_request
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ StatusPing,
+ StatusPingSpec,
+ test_status_ping,
+ bench_write_status_ping,
+ bench_read_status_ping
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ StatusResponse,
+ StatusResponseSpec,
+ test_status_response,
+ bench_write_status_response,
+ bench_read_status_response
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ StatusPong,
+ StatusPongSpec,
+ test_status_pong,
+ bench_write_status_pong,
+ bench_read_status_pong
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginDisconnect,
+ LoginDisconnectSpec,
+ test_login_disconnect,
+ bench_write_login_disconnect,
+ bench_read_login_disconnect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginEncryptionRequest,
+ LoginEncryptionRequestSpec,
+ test_login_encryption_request,
+ bench_write_login_encryption_request,
+ bench_read_login_encryption_request
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginSuccess,
+ LoginSuccessSpec,
+ test_login_success,
+ bench_write_login_success,
+ bench_read_login_success
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginSetCompression,
+ LoginSetCompressionSpec,
+ test_login_set_compression,
+ bench_write_login_set_compression,
+ bench_read_login_set_compression
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginPluginRequest,
+ LoginPluginRequestSpec,
+ test_login_plugin_request,
+ bench_write_login_plugin_request,
+ bench_read_login_plugin_request
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginStart,
+ LoginStartSpec,
+ test_login_start,
+ bench_write_login_start,
+ bench_read_login_start
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginEncryptionResponse,
+ LoginEncryptionResponseSpec,
+ test_login_encryption_response,
+ bench_write_login_encryption_response,
+ bench_read_login_encryption_response
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ LoginPluginResponse,
+ LoginPluginResponseSpec,
+ test_login_plugin_response,
+ bench_write_login_plugin_response,
+ bench_read_login_plugin_response
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpawnEntity,
+ PlaySpawnEntitySpec,
+ test_play_spawn_entity,
+ bench_write_play_spawn_entity,
+ bench_read_play_spawn_entity
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpawnExperienceOrb,
+ PlaySpawnExperienceOrbSpec,
+ test_play_spawn_experience_orb,
+ bench_write_play_spawn_experience_orb,
+ bench_read_play_spawn_experience_orb
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpawnLivingEntity,
+ PlaySpawnLivingEntitySpec,
+ test_play_spawn_living_entity,
+ bench_write_play_spawn_living_entity,
+ bench_read_play_spawn_living_entity
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpawnPainting,
+ PlaySpawnPaintingSpec,
+ test_play_spawn_painting,
+ bench_write_play_spawn_painting,
+ bench_read_play_spawn_painting
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpawnPlayer,
+ PlaySpawnPlayerSpec,
+ test_play_spawn_player,
+ bench_write_play_spawn_player,
+ bench_read_play_spawn_player
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityAnimation,
+ PlayEntityAnimationSpec,
+ test_play_entity_animation,
+ bench_write_play_entity_animation,
+ bench_read_play_entity_animation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayStatistics,
+ PlayStatisticsSpec,
+ test_play_statistics,
+ bench_write_play_statistics,
+ bench_read_play_statistics
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayAcknowledgePlayerDigging,
+ PlayAcknowledgePlayerDiggingSpec,
+ test_play_acknowledge_player_digging,
+ bench_write_play_acknowledge_player_digging,
+ bench_read_play_acknowledge_player_digging
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayBlockBreakAnimation,
+ PlayBlockBreakAnimationSpec,
+ test_play_block_break_animation,
+ bench_write_play_block_break_animation,
+ bench_read_play_block_break_animation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayBlockEntityData,
+ PlayBlockEntityDataSpec,
+ test_play_block_entity_data,
+ bench_write_play_block_entity_data,
+ bench_read_play_block_entity_data
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayBlockAction,
+ PlayBlockActionSpec,
+ test_play_block_action,
+ bench_write_play_block_action,
+ bench_read_play_block_action
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayBlockChange,
+ PlayBlockChangeSpec,
+ test_play_block_change,
+ bench_write_play_block_change,
+ bench_read_play_block_change
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayBossBar,
+ PlayBossBarSpec,
+ test_play_boss_bar,
+ bench_write_play_boss_bar,
+ bench_read_play_boss_bar
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerDifficulty,
+ PlayServerDifficultySpec,
+ test_play_server_difficulty,
+ bench_write_play_server_difficulty,
+ bench_read_play_server_difficulty
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerChatMessage,
+ PlayServerChatMessageSpec,
+ test_play_server_chat_message,
+ bench_write_play_server_chat_message,
+ bench_read_play_server_chat_message
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTabComplete,
+ PlayTabCompleteSpec,
+ test_play_tab_complete,
+ bench_write_play_tab_complete,
+ bench_read_play_tab_complete
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayDeclareCommands,
+ PlayDeclareCommandsSpec,
+ test_play_declare_commands,
+ bench_write_play_declare_commands,
+ bench_read_play_declare_commands
+ );
+
+ // packet_test_cases!(
+ // RawPacket755,
+ // Packet755,
+ // PlayServerWindowConfirmation,
+ // PlayServerWindowConfirmationSpec,
+ // test_play_server_window_confirmation,
+ // bench_write_play_server_window_confirmation,
+ // bench_read_play_server_window_confirmation
+ // );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerCloseWindow,
+ PlayServerCloseWindowSpec,
+ test_play_server_close_window,
+ bench_write_play_server_close_window,
+ bench_read_play_server_close_window
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayWindowItems,
+ PlayWindowItemsSpec,
+ test_play_window_items,
+ bench_write_play_window_items,
+ bench_read_play_window_items
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayWindowProperty,
+ PlayWindowPropertySpec,
+ test_play_window_property,
+ bench_write_play_window_property,
+ bench_read_play_window_property
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetSlot,
+ PlaySetSlotSpec,
+ test_play_set_slot,
+ bench_write_play_set_slot,
+ bench_read_play_set_slot
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetCooldown,
+ PlaySetCooldownSpec,
+ test_play_set_cooldown,
+ bench_write_play_set_cooldown,
+ bench_read_play_set_cooldown
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerPluginMessage,
+ PlayServerPluginMessageSpec,
+ test_play_server_plugin_message,
+ bench_write_play_server_plugin_message,
+ bench_read_play_server_plugin_message
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayNamedSoundEffect,
+ PlayNamedSoundEffectSpec,
+ test_play_named_sound_effect,
+ bench_write_play_named_sound_effect,
+ bench_read_play_named_sound_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayDisconnect,
+ PlayDisconnectSpec,
+ test_play_disconnect,
+ bench_write_play_disconnect,
+ bench_read_play_disconnect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityStatus,
+ PlayEntityStatusSpec,
+ test_play_entity_status,
+ bench_write_play_entity_status,
+ bench_read_play_entity_status
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayExplosion,
+ PlayExplosionSpec,
+ test_play_explosion,
+ bench_write_play_explosion,
+ bench_read_play_explosion
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUnloadChunk,
+ PlayUnloadChunkSpec,
+ test_play_unload_chunk,
+ bench_write_play_unload_chunk,
+ bench_read_play_unload_chunk
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayChangeGameState,
+ PlayChangeGameStateSpec,
+ test_play_change_game_state,
+ bench_write_play_change_game_state,
+ bench_read_play_change_game_state
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayOpenHorseWindow,
+ PlayOpenHorseWindowSpec,
+ test_play_open_horse_window,
+ bench_write_play_open_horse_window,
+ bench_read_play_open_horse_window
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerKeepAlive,
+ PlayServerKeepAliveSpec,
+ test_play_server_keep_alive,
+ bench_write_play_server_keep_alive,
+ bench_read_play_server_keep_alive
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayChunkData,
+ PlayChunkDataWrapper,
+ test_play_chunk_data,
+ bench_write_play_chunk_data,
+ bench_read_play_chunk_data
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEffect,
+ PlayEffectSpec,
+ test_play_effect,
+ bench_write_play_effect,
+ bench_read_play_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayParticle,
+ PlayParticleSpec,
+ test_play_particle,
+ bench_write_play_particle,
+ bench_read_play_particle
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateLight,
+ PlayUpdateLightSpec,
+ test_play_update_light,
+ bench_write_play_update_light,
+ bench_read_play_update_light
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayJoinGame,
+ PlayJoinGameSpec,
+ test_play_join_game,
+ bench_write_play_join_game,
+ bench_read_play_join_game
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayMapData,
+ PlayMapDataSpec,
+ test_play_map_data,
+ bench_write_play_map_data,
+ bench_read_play_map_data
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTradeList,
+ PlayTradeListSpec,
+ test_play_trade_list,
+ bench_write_play_trade_list,
+ bench_read_play_trade_list
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityPosition,
+ PlayEntityPositionSpec,
+ test_play_entity_position,
+ bench_write_play_entity_position,
+ bench_read_play_entity_position
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityPositionAndRotation,
+ PlayEntityPositionAndRotationSpec,
+ test_play_entity_position_and_rotation,
+ bench_write_play_entity_position_and_rotation,
+ bench_read_play_entity_position_and_rotation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityRotation,
+ PlayEntityRotationSpec,
+ test_play_entity_rotation,
+ bench_write_play_entity_rotation,
+ bench_read_play_entity_rotation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityMovement,
+ PlayEntityMovementSpec,
+ test_play_entity_movement,
+ bench_write_play_entity_movement,
+ bench_read_play_entity_movement
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerVehicleMove,
+ PlayEntityVehicleMoveSpec,
+ test_play_server_vehicle_move,
+ bench_write_play_server_vehicle_move,
+ bench_read_play_server_vehicle_move
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayOpenBook,
+ PlayOpenBookSpec,
+ test_play_open_book,
+ bench_write_play_open_book,
+ bench_read_play_open_book
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayOpenWindow,
+ PlayOpenWindowSpec,
+ test_play_open_window,
+ bench_write_play_open_window,
+ bench_read_play_open_window
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayOpenSignEditor,
+ PlayOpenSignEditorSpec,
+ test_play_open_sign_editor,
+ bench_write_play_open_sign_editor,
+ bench_read_play_open_sign_editor
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayCraftRecipeResponse,
+ PlayCraftRecipeResponseSpec,
+ test_play_craft_recipe_response,
+ bench_write_play_craft_recipe_response,
+ bench_read_play_craft_recipe_response
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerPlayerAbilities,
+ PlayServerPlayerAbilitiesSpec,
+ test_play_server_player_abilities,
+ bench_write_play_server_player_abilities,
+ bench_read_play_server_player_abilities
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayCombatEvent,
+ PlayCombatEventSpec,
+ test_play_combat_event,
+ bench_write_play_combat_event,
+ bench_read_play_combat_event
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayPlayerInfo,
+ PlayPlayerInfoSpec,
+ test_play_player_info,
+ bench_write_play_player_info,
+ bench_read_play_player_info
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayFacePlayer,
+ PlayFacePlayerSpec,
+ test_play_face_player,
+ bench_write_play_face_player,
+ bench_read_play_face_player
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerPlayerPositionAndLook,
+ PlayServerPlayerPositionAndLookSpec,
+ test_play_server_player_position_and_look,
+ bench_write_play_server_player_position_and_look,
+ bench_read_play_server_player_position_and_look
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUnlockRecipes,
+ PlayUnlockRecipesSpec,
+ test_play_unlock_recipes,
+ bench_write_play_unlock_recipes,
+ bench_read_play_unlock_recipes
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayDestroyEntities,
+ PlayDestroyEntitiesSpec,
+ test_play_destroy_entities,
+ bench_write_play_destroy_entities,
+ bench_read_play_destroy_entities
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayRemoveEntityEffect,
+ PlayRemoveEntityEffectSpec,
+ test_play_remove_entity_effect,
+ bench_write_play_remove_entity_effect,
+ bench_read_play_remove_entity_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayResourcePackSend,
+ PlayResourcePackSendSpec,
+ test_play_resource_pack_send,
+ bench_write_play_resource_pack_send,
+ bench_read_play_resource_pack_send
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayRespawn,
+ PlayRespawnSpec,
+ test_play_respawn,
+ bench_write_play_respawn,
+ bench_read_play_respawn
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityHeadLook,
+ PlayEntityHeadLookSpec,
+ test_play_entity_head_look,
+ bench_write_play_entity_head_look,
+ bench_read_play_entity_head_look
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayMultiBlockChange,
+ PlayMultiBlockChangeSpec,
+ test_play_multi_block_change,
+ bench_write_play_multi_block_change,
+ bench_read_play_multi_block_change
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySelectAdvancementTab,
+ PlaySelectAdvancementTabSpec,
+ test_play_select_advancement_tab,
+ bench_write_play_select_advancement_tab,
+ bench_read_play_select_advancement_tab
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayWorldBorder,
+ PlayWorldBorderSpec,
+ test_play_world_border,
+ bench_write_play_world_border,
+ bench_read_play_world_border
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayCamera,
+ PlayCameraSpec,
+ test_play_camera,
+ bench_write_play_camera,
+ bench_read_play_camera
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayServerHeldItemChange,
+ PlayServerHeldItemChangeSpec,
+ test_play_server_held_item_change,
+ bench_write_play_server_held_item_change,
+ bench_read_play_server_held_item_change
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateViewPosition,
+ PlayUpdateViewPositionSpec,
+ test_play_update_view_position,
+ bench_write_play_update_view_position,
+ bench_read_play_update_view_position
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateViewDistance,
+ PlayUpdateViewDistanceSpec,
+ test_play_update_view_distance,
+ bench_write_play_update_view_distance,
+ bench_read_play_update_view_distance
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpawnPosition,
+ PlaySpawnPositionSpec,
+ test_play_spawn_position,
+ bench_write_play_spawn_position,
+ bench_read_play_spawn_position
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayDisplayScoreboard,
+ PlayDisplayScoreboardSpec,
+ test_play_display_scoreboard,
+ bench_write_play_display_scoreboard,
+ bench_read_play_display_scoreboard
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityMetadata,
+ PlayEntityMetadataSpec,
+ test_play_entity_metadata,
+ bench_write_play_entity_metadata,
+ bench_read_play_entity_metadata
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayAttachEntity,
+ PlayAttachEntitySpec,
+ test_play_attach_entity,
+ bench_write_play_attach_entity,
+ bench_read_play_attach_entity
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityVelocity,
+ PlayEntityVelocitySpec,
+ test_play_entity_velocity,
+ bench_write_play_entity_velocity,
+ bench_read_play_entity_velocity
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityEquipment,
+ PlayEntityEquiptmentSpec,
+ test_play_entity_equipment,
+ bench_write_play_entity_equipment,
+ bench_read_play_entity_equipment
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetExperience,
+ PlaySetExperienceSpec,
+ test_play_set_experience,
+ bench_write_play_set_experience,
+ bench_read_play_set_experience
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdatehealth,
+ PlayUpdateHealthSpec,
+ test_play_updatehealth,
+ bench_write_play_updatehealth,
+ bench_read_play_updatehealth
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayScoreboardObjective,
+ PlayScoreboardObjectiveSpec,
+ test_play_scoreboard_objective,
+ bench_write_play_scoreboard_objective,
+ bench_read_play_scoreboard_objective
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetPassengers,
+ PlaySetPassengersSpec,
+ test_play_set_passengers,
+ bench_write_play_set_passengers,
+ bench_read_play_set_passengers
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTeams,
+ PlayTeamsSpec,
+ test_play_teams,
+ bench_write_play_teams,
+ bench_read_play_teams
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateScore,
+ PlayUpdateScoreSpec,
+ test_play_update_score,
+ bench_write_play_update_score,
+ bench_read_play_update_score
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTimeUpdate,
+ PlayTimeUpdateSpec,
+ test_play_time_update,
+ bench_write_play_time_update,
+ bench_read_play_time_update
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTitle,
+ PlayTitleSpec,
+ test_play_title,
+ bench_write_play_title,
+ bench_read_play_title
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntitySoundEffect,
+ PlayEntitySoundEffectSpec,
+ test_play_entity_sound_effect,
+ bench_write_play_entity_sound_effect,
+ bench_read_play_entity_sound_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySoundEffect,
+ PlaySoundEffectSpec,
+ test_play_sound_effect,
+ bench_write_play_sound_effect,
+ bench_read_play_sound_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayStopSound,
+ PlayStopSoundSpec,
+ test_play_stop_sound,
+ bench_write_play_stop_sound,
+ bench_read_play_stop_sound
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayerPlayerListHeaderAndFooter,
+ PlayPlayerListHeaderAndFooterSpec,
+ test_player_player_list_header_and_footer,
+ bench_write_player_player_list_header_and_footer,
+ bench_read_player_player_list_header_and_footer
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayNbtQueryResponse,
+ PlayNbtQueryResponseSpec,
+ test_play_nbt_query_response,
+ bench_write_play_nbt_query_response,
+ bench_read_play_nbt_query_response
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayCollectItem,
+ PlayCollectItemSpec,
+ test_play_collect_item,
+ bench_write_play_collect_item,
+ bench_read_play_collect_item
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityTeleport,
+ PlayEntityTeleportSpec,
+ test_play_entity_teleport,
+ bench_write_play_entity_teleport,
+ bench_read_play_entity_teleport
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayAdvancements,
+ PlayAdvancementsSpec,
+ test_play_advancements,
+ bench_write_play_advancements,
+ bench_read_play_advancements
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityProperties,
+ PlayEntityPropertiesSpec,
+ test_play_entity_properties,
+ bench_write_play_entity_properties,
+ bench_read_play_entity_properties
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityEffect,
+ PlayEntityEffectSpec,
+ test_play_entity_effect,
+ bench_write_play_entity_effect,
+ bench_read_play_entity_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayDeclareRecipes,
+ PlayDeclareRecipesSpec,
+ test_play_declare_recipes,
+ bench_write_play_declare_recipes,
+ bench_read_play_declare_recipes
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTags,
+ PlayTagsSpec,
+ test_play_tags,
+ bench_write_play_tags,
+ bench_read_play_tags
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayTeleportConfirm,
+ PlayTeleportConfirmSpec,
+ test_play_teleport_confirm,
+ bench_write_play_teleport_confirm,
+ bench_read_play_teleport_confirm
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayQueryBlockNbt,
+ PlayQueryBlockNbtSpec,
+ test_play_query_block_nbt,
+ bench_write_play_query_block_nbt,
+ bench_read_play_query_block_nbt
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayQueryEntityNbt,
+ PlayQueryEntityNbtSpec,
+ test_play_query_entity_nbt,
+ bench_write_play_query_entity_nbt,
+ bench_read_play_query_entity_nbt
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetDifficulty,
+ PlaySetDifficultySpec,
+ test_play_set_difficulty,
+ bench_write_play_set_difficulty,
+ bench_read_play_set_difficulty
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientChatMessage,
+ PlayClientChatMessageSpec,
+ test_play_client_chat_message,
+ bench_write_play_client_chat_message,
+ bench_read_play_client_chat_message
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientStatus,
+ PlayClientStatusSpec,
+ test_play_client_status,
+ bench_write_play_client_status,
+ bench_read_play_client_status
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientSettings,
+ PlayClientSettingsSpec,
+ test_play_client_settings,
+ bench_write_play_client_settings,
+ bench_read_play_client_settings
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientTabComplete,
+ PlayClientTabCompleteSpec,
+ test_play_client_tab_complete,
+ bench_write_play_client_tab_complete,
+ bench_read_play_client_tab_complete
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientWindowConfirmation,
+ PlayClientWindowConfirmationSpec,
+ test_play_client_window_confirmation,
+ bench_write_play_client_window_confirmation,
+ bench_read_play_client_window_confirmation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClickWindowButton,
+ PlayClickWindowButtonSpec,
+ test_play_click_window_button,
+ bench_write_play_click_window_button,
+ bench_read_play_click_window_button
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClickWindow,
+ PlayClickWindowSpec,
+ test_play_click_window,
+ bench_write_play_click_window,
+ bench_read_play_click_window
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientCloseWindow,
+ PlayClientCloseWindowSpec,
+ test_play_client_close_window,
+ bench_write_play_client_close_window,
+ bench_read_play_client_close_window
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientPluginMessage,
+ PlayClientPluginMessageSpec,
+ test_play_client_plugin_message,
+ bench_write_play_client_plugin_message,
+ bench_read_play_client_plugin_message
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEditBook,
+ PlayEditBookSpec,
+ test_play_edit_book,
+ bench_write_play_edit_book,
+ bench_read_play_edit_book
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayInteractEntity,
+ PlayInteractEntitySpec,
+ test_play_interact_entity,
+ bench_write_play_interact_entity,
+ bench_read_play_interact_entity
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayGenerateStructure,
+ PlayGenerateStructureSpec,
+ test_play_generate_structure,
+ bench_write_play_generate_structure,
+ bench_read_play_generate_structure
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientKeepAlive,
+ PlayClientKeepAliveSpec,
+ test_play_client_keep_alive,
+ bench_write_play_client_keep_alive,
+ bench_read_play_client_keep_alive
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayLockDifficulty,
+ PlayLockDifficultySpec,
+ test_play_lock_difficulty,
+ bench_write_play_lock_difficulty,
+ bench_read_play_lock_difficulty
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayPlayerPosition,
+ PlayPlayerPositionSpec,
+ test_play_player_position,
+ bench_write_play_player_position,
+ bench_read_play_player_position
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientPlayerPositionAndRotation,
+ PlayClientPlayerPositionAndRotationSpec,
+ test_play_client_player_position_and_rotation,
+ bench_write_play_client_player_position_and_rotation,
+ bench_read_play_client_player_position_and_rotation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayPlayerRotation,
+ PlayPlayerRotationSpec,
+ test_play_player_rotation,
+ bench_write_play_player_rotation,
+ bench_read_play_player_rotation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayPlayerMovement,
+ PlayPlayerMovementSpec,
+ test_play_player_movement,
+ bench_write_play_player_movement,
+ bench_read_play_player_movement
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientVehicleMove,
+ PlayClientVehicleMoveSpec,
+ test_play_client_vehicle_move,
+ bench_write_play_client_vehicle_move,
+ bench_read_play_client_vehicle_move
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySteerBoat,
+ PlaySteerBoatSpec,
+ test_play_steer_boat,
+ bench_write_play_steer_boat,
+ bench_read_play_steer_boat
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayPickItem,
+ PlayPickItemSpec,
+ test_play_pick_item,
+ bench_write_play_pick_item,
+ bench_read_play_pick_item
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayCraftRecipeRequest,
+ PlayCraftRecipeRequestSpec,
+ test_play_craft_recipe_request,
+ bench_write_play_craft_recipe_request,
+ bench_read_play_craft_recipe_request
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientPlayerAbilities,
+ PlayClientPlayerAbilitiesSpec,
+ test_play_client_player_abilities,
+ bench_write_play_client_player_abilities,
+ bench_read_play_client_player_abilities
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayPlayerDigging,
+ PlayPlayerDiggingSpec,
+ test_play_player_digging,
+ bench_write_play_player_digging,
+ bench_read_play_player_digging
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayEntityAction,
+ PlayEntityActionSpec,
+ test_play_entity_action,
+ bench_write_play_entity_action,
+ bench_read_play_entity_action
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySteerVehicle,
+ PlaySteerVehicleSpec,
+ test_play_steer_vehicle,
+ bench_write_play_steer_vehicle,
+ bench_read_play_steer_vehicle
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetDisplayedRecipe,
+ PlaySetDisplayedRecipeSpec,
+ test_play_set_displayed_recipe,
+ bench_write_play_set_displayed_recipe,
+ bench_read_play_set_displayed_recipe
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetRecipeBookState,
+ PlaySetRecipeBookStateSpec,
+ test_play_set_recipe_book_state,
+ bench_write_play_set_recipe_book_state,
+ bench_read_play_set_recipe_book_state
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayNameItem,
+ PlayNameItemSpec,
+ test_play_name_item,
+ bench_write_play_name_item,
+ bench_read_play_name_item
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayResourcePackStatus,
+ PlayResourcePackStatusSpec,
+ test_play_resource_pack_status,
+ bench_write_play_resource_pack_status,
+ bench_read_play_resource_pack_status
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayAdvancementTab,
+ PlayAdvancementTabSpec,
+ test_play_advancement_tab,
+ bench_write_play_advancement_tab,
+ bench_read_play_advancement_tab
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySelectTrade,
+ PlaySelectTradeSpec,
+ test_play_select_trade,
+ bench_write_play_select_trade,
+ bench_read_play_select_trade
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySetBeaconEffect,
+ PlaySetBeaconEffectSpec,
+ test_play_set_beacon_effect,
+ bench_write_play_set_beacon_effect,
+ bench_read_play_set_beacon_effect
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientHeldItemChange,
+ PlayClientHeldItemChangeSpec,
+ test_play_client_held_item_change,
+ bench_write_play_client_held_item_change,
+ bench_read_play_client_held_item_change
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateCommandBlock,
+ PlayUpdateCommandBlockSpec,
+ test_play_update_command_block,
+ bench_write_play_update_command_block,
+ bench_read_play_update_command_block
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateCommandBlockMinecart,
+ PlayUpdateCommandBlockMinecartSpec,
+ test_play_update_command_block_minecart,
+ bench_write_play_update_command_block_minecart,
+ bench_read_play_update_command_block_minecart
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateJigsawBlock,
+ PlayUpdateJigsawBlockSpec,
+ test_play_update_jigsaw_block,
+ bench_write_play_update_jigsaw_block,
+ bench_read_play_update_jigsaw_block
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayCreativeInventoryAction,
+ PlayCreativeInventoryActionSpec,
+ test_play_creative_inventory_action,
+ bench_write_play_creative_inventory_action,
+ bench_read_play_creative_inventory_action
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateStructureBlock,
+ PlayUpdateStructureBlockSpec,
+ test_play_update_structure_block,
+ bench_write_play_update_structure_block,
+ bench_read_play_update_structure_block
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUpdateSign,
+ PlayUpdateSignSpec,
+ test_play_update_sign,
+ bench_write_play_update_sign,
+ bench_read_play_update_sign
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayClientAnimation,
+ PlayClientAnimationSpec,
+ test_play_client_animation,
+ bench_write_play_client_animation,
+ bench_read_play_client_animation
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlaySpectate,
+ PlaySpectateSpec,
+ test_play_spectate,
+ bench_write_play_spectate,
+ bench_read_play_spectate
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayBlockPlacement,
+ PlayBlockPlacementSpec,
+ test_play_block_placement,
+ bench_write_play_block_placement,
+ bench_read_play_block_placement
+ );
+
+ packet_test_cases!(
+ RawPacket755,
+ Packet755,
+ PlayUseItem,
+ PlayUseItemSpec,
+ test_play_use_item,
+ bench_write_play_use_item,
+ bench_read_play_use_item
+ );
+
+ // trust me, this is some cutting edge shit
+ // I'm definitely not generating code using a unit test
+ #[test]
+ fn test_generate_test_cases() {
+ Packet755::describe().packets.iter().map(move |packet| {
+ let snake_case = to_snake_case(packet.name.clone());
+ alloc::format!("packet_test_cases!(RawPacket755, Packet755, {}, {},\n test_{}, bench_write_{}, bench_read_{});\n",
+ packet.name, packet.body_struct, snake_case, snake_case, snake_case).to_owned()
+ }).for_each(move |line| {
+ println!("{}", line)
+ })
+ }
+
+ fn to_snake_case(camel: String) -> String {
+ let mut parts = Vec::new();
+ let mut buf = String::new();
+ for c in camel.chars() {
+ if !buf.is_empty() && char::is_uppercase(c) {
+ parts.push(buf);
+ buf = String::new();
+ }
+
+ buf.push(c.to_ascii_lowercase());
+ }
+
+ if !buf.is_empty() {
+ parts.push(buf);
+ }
+
+ parts.join("_")
+ }
+}