1.13.2 (404) multiprotocol support (#67)

Adds support for 1.13.2 protocol (404)
Expands https://github.com/iceiix/steven/issues/18 Enhance protocol support

Metadata:

* Support 1.13.2 slot data format, bool and varint item id, optional damage (moved to NBT)

https://wiki.vg/index.php?title=Slot_Data&type=revision&diff=14363&oldid=7835

Packets:

* Add 1.13.2 packets, and implement all the command data parsers

https://wiki.vg/Command_Data#Parsers

* Send new plugin channel minecraft:brand

https://wiki.vg/Plugin_channels#minecraft:brand

* Add 1.13.2 metadata format, with shifted IDs

https://wiki.vg/Entity_metadata#Entity_Metadata_Format

* Implement particle entity metadata

* Add structures for 16 new packets

Blocks: The Flattening:

* Assign flattened IDs in correct order using new 'offset' macro token

* Assign hierarchical (pre-flattening) block IDs sequentially by counting Some data

* Split VANILLA_ID_MAP into flat/hier struct, to support before and after the flattening

* Extend travis build time to 20 minutes because the blocks macro takes a long time

* Support both flat/hier blocks by passing protocol_version to by_vanilla_id

Add block states and offsets for all blocks, replacing metadata for 1.13+:

* Add stripped logs and what was Log2 to Log
* Add the Wood blocks, should be called bark, previously Axis::None Log
* Add leaves distance and offset
* Add jungle/acacia to Leaves moved from Leaves2
* Add dispenser offsets, direction
* Add note block states
* Add offset None to Missing253 and Missing254, no holes in block states of 1.13.2
* Add bed colors
* Add seagrass, tall seagrass, remove redundant deadgrass, and piston offset
* Add torch, TNT, fire offsets, remove slabs
* Add furnance offset, merges lit into a property
* Add pressure plate offsets, new pressure plates, redstone ore/lit merged
* Add lever offsets, new directions from ceiling/floor, rename LeverDirections
* Add redstone torch offsets, new blocks since lit/unlit is now merged, and standing/wall is split
* Change lever to split face/facing, rm LeverDirection, add AttachedFace
* Add stone button offsets, face/facing similar to lever
* Move face/facing data and variant to AttachedFace, reuse for lever/stonebutton
* Add data_with_facing_and_powered() to AttachedFace, for lever/stonebutton
* Add wooden button offsets each wood
* Add pumpkin without a face
* Add carved pumpkin, portal offsets
* Add lit pumpkin (as jack-o-lantern) offsets after carved pumpkin
* Add repeater offsets, merged into Repeater
* Change brown mushroom block to booleans instead of MushroomVariant
* Add mushroom block offsets, red/brown mushroom blocks, and a new mushroom stem block
* Add command block, cobblestone walls, and flower pot offsets
Empty flower pot, and potted plants including saplings. Rename
variant DarkOak to DarkOakSaplings because it is a sapling, and
remove the duplicate Dandelion variant which causes duplicate blocks.
* Increase recursion limit in steven_blocks
* Add colored banner offsets
* Add wooden slab including double slab, in a different position for pre-1.13 and 1.13
* StoneSlabVariant::Wood -> StoneSlabVariant::PetrifiedWood
* Add fence_gate_offset() for wooden fence gates
* Add frosted ice age, offset
* Add new blocks: kelp, turtle egg, coral, coral fans, sea pickle, blue ice, smooth stone
* Add new blocks: conduit, void air, cave aid, bubble column, last of the 1.13 blocks
This commit is contained in:
iceiix 2018-12-28 21:11:42 -08:00 committed by ice_iix
parent 4d127c55fe
commit 26568190d0
5 changed files with 616 additions and 7 deletions

View File

@ -37,7 +37,7 @@ use flate2::Compression;
use std::time::{Instant, Duration};
use crate::shared::Position;
pub const SUPPORTED_PROTOCOLS: [i32; 9] = [340, 316, 315, 210, 109, 107, 74, 47, 5];
pub const SUPPORTED_PROTOCOLS: [i32; 10] = [404, 340, 316, 315, 210, 109, 107, 74, 47, 5];
// TODO: switch to using thread_local storage?, see https://doc.rust-lang.org/std/macro.thread_local.html
pub static mut CURRENT_PROTOCOL_VERSION: i32 = SUPPORTED_PROTOCOLS[0];
@ -553,6 +553,17 @@ impl <L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
}
}
impl Lengthable for bool {
fn into(self) -> usize {
if self { 1 } else { 0 }
}
fn from(u: usize) -> bool {
u != 0
}
}
impl Lengthable for u8 {
fn into(self) -> usize {
self as usize

View File

@ -53,6 +53,10 @@ state_packets!(
packet TeleportConfirm {
field teleport_id: VarInt =,
}
packet QueryBlockNBT {
field transaction_id: VarInt =,
field location: Position =,
}
/// TabComplete is sent by the client when the client presses tab in
/// the chat box.
packet TabComplete {
@ -156,6 +160,15 @@ state_packets!(
field channel: String =,
field data: LenPrefixedBytes<i16> =,
}
packet EditBook {
field new_book: Option<item::Stack> =,
field is_signing: bool =,
field hand: VarInt =,
}
packet QueryEntityNBT {
field transaction_id: VarInt =,
field entity_id: VarInt =,
}
/// UseEntity is sent when the user interacts (right clicks) or attacks
/// (left clicks) an entity.
packet UseEntity {
@ -240,10 +253,13 @@ state_packets!(
field yaw: f32 =,
field pitch: f32 =,
}
/// TODO: Document
/// SteerBoat is used to visually update the boat paddles.
packet SteerBoat {
field unknown: bool =,
field unknown2: bool =,
field left_paddle_turning: bool =,
field right_paddle_turning: bool =,
}
packet PickItem {
field slot_to_use: VarInt =,
}
/// CraftRecipeRequest is sent when player clicks a recipe in the crafting book.
packet CraftRecipeRequest {
@ -308,6 +324,9 @@ state_packets!(
field crafting_book_open: bool = when(|p: &CraftingBookData| p.action.0 == 1),
field crafting_filter: bool = when(|p: &CraftingBookData| p.action.0 == 1),
}
packet NameItem {
field item_name: String =,
}
/// ResourcePackStatus informs the server of the client's current progress
/// in activating the requested resource pack
packet ResourcePackStatus {
@ -322,17 +341,53 @@ state_packets!(
field action: VarInt =,
field tab_id: String = when(|p: &AdvancementTab| p.action.0 == 0),
}
packet SelectTrade {
field selected_slot: VarInt =,
}
packet SetBeaconEffect {
field primary_effect: VarInt =,
field secondary_effect: VarInt =,
}
/// HeldItemChange is sent when the player changes the currently active
/// hotbar slot.
packet HeldItemChange {
field slot: i16 =,
}
packet UpdateCommandBlock {
field location: Position =,
field command: String =,
field mode: VarInt =,
field flags: u8 =,
}
packet UpdateCommandBlockMinecart {
field entity_id: VarInt =,
field command: String =,
field track_output: bool =,
}
/// CreativeInventoryAction is sent when the client clicks in the creative
/// inventory. This is used to spawn items in creative.
packet CreativeInventoryAction {
field slot: i16 =,
field clicked_item: Option<item::Stack> =,
}
packet UpdateStructureBlock {
field location: Position =,
field action: VarInt =,
field mode: VarInt =,
field name: String =,
field offset_x: i8 =,
field offset_y: i8 =,
field offset_z: i8 =,
field size_x: i8 =,
field size_y: i8 =,
field size_z: i8 =,
field mirror: VarInt =,
field rotation: VarInt =,
field metadata: String =,
field integrity: f32 =,
field seed: VarLong =,
field flags: i8 =,
}
/// SetSign sets the text on a sign after placing it.
packet SetSign {
field location: Position =,
@ -704,6 +759,10 @@ state_packets!(
packet TabCompleteReply {
field matches: LenPrefixed<VarInt, String> =,
}
packet DeclareCommands {
field nodes: LenPrefixed<VarInt, packet::CommandNode> =,
field root_index: VarInt =,
}
/// ServerMessage is a message sent by the server. It could be from a player
/// or just a system message. The Type field controls the location the
/// message is displayed at and when the message is displayed.
@ -1148,6 +1207,15 @@ state_packets!(
field online: bool =,
field ping: u16 =,
}
packet FacePlayer {
field feet_eyes: VarInt =,
field target_x: f64 =,
field target_y: f64 =,
field target_z: f64 =,
field is_entity: bool =,
field entity_id: Option<VarInt> = when(|p: &FacePlayer| p.is_entity),
field entity_feet_eyes: Option<VarInt> = when(|p: &FacePlayer| p.is_entity),
}
/// TeleportPlayer is sent to change the player's position. The client is expected
/// to reply to the server with the same positions as contained in this packet
/// otherwise will reject future packets.
@ -1179,12 +1247,21 @@ state_packets!(
field y: u8 =,
field z: i32 =,
}
packet UnlockRecipes {
packet UnlockRecipes_NoSmelting {
field action: VarInt =,
field crafting_book_open: bool =,
field filtering_craftable: bool =,
field recipe_ids: LenPrefixed<VarInt, VarInt> =,
field recipe_ids2: LenPrefixed<VarInt, VarInt> = when(|p: &UnlockRecipes| p.action.0 == 0),
field recipe_ids2: LenPrefixed<VarInt, VarInt> = when(|p: &UnlockRecipes_NoSmelting| p.action.0 == 0),
}
packet UnlockRecipes_WithSmelting {
field action: VarInt =,
field crafting_book_open: bool =,
field filtering_craftable: bool =,
field smelting_book_open: bool =,
field filtering_smeltable: bool =,
field recipe_ids: LenPrefixed<VarInt, String> =,
field recipe_ids2: LenPrefixed<VarInt, String> = when(|p: &UnlockRecipes_WithSmelting| p.action.0 == 0),
}
/// EntityDestroy destroys the entities with the ids in the provided slice.
packet EntityDestroy {
@ -1229,6 +1306,10 @@ state_packets!(
field entity_id: i32 =,
field entity_status: i8 =,
}
packet NBTQueryResponse {
field transaction_id: VarInt =,
field nbt: Option<nbt::NamedTag> =,
}
/// SelectAdvancementTab indicates the client should switch the advancement tab.
packet SelectAdvancementTab {
field has_id: bool =,
@ -1405,6 +1486,11 @@ state_packets!(
field world_age: i64 =,
field time_of_day: i64 =,
}
packet StopSound {
field flags: u8 =,
field source: Option<VarInt> = when(|p: &StopSound| p.flags & 0x01 != 0),
field sound: Option<String> = when(|p: &StopSound| p.flags & 0x02 != 0),
}
/// Title configures an on-screen title.
packet Title {
field action: VarInt =,
@ -1544,6 +1630,14 @@ state_packets!(
field amplifier: i8 =,
field duration: i16 =,
}
packet DeclareRecipes {
field recipes: LenPrefixed<VarInt, packet::Recipe> =,
}
packet Tags {
field block_tags: LenPrefixed<VarInt, packet::Tags> =,
field item_tags: LenPrefixed<VarInt, packet::Tags> =,
field fluid_tags: LenPrefixed<VarInt, packet::Tags> =,
}
}
}
login Login {
@ -1569,6 +1663,11 @@ state_packets!(
field shared_secret: LenPrefixedBytes<i16> =,
field verify_token: LenPrefixedBytes<i16> =,
}
packet LoginPluginResponse {
field message_id: VarInt =,
field successful: bool =,
field data: Vec<u8> =,
}
}
clientbound Clientbound {
/// LoginDisconnect is sent by the server if there was any issues
@ -1609,6 +1708,11 @@ state_packets!(
/// Threshold where a packet should be sent compressed
field threshold: VarInt =,
}
packet LoginPluginRequest {
field message_id: VarInt =,
field channel: String =,
field data: Vec<u8> =,
}
}
}
status Status {
@ -2165,3 +2269,324 @@ pub struct PlayerProperty {
pub value: String,
pub signature: Option<String>,
}
use crate::item;
type RecipeIngredient = LenPrefixed<VarInt, Option<item::Stack>>;
#[derive(Debug)]
pub enum RecipeData {
Shapeless {
group: String,
ingredients: LenPrefixed<VarInt, RecipeIngredient>,
result: Option<item::Stack>,
},
Shaped {
width: VarInt,
height: VarInt,
group: String,
ingredients: Vec<RecipeIngredient>,
result: Option<item::Stack>,
},
ArmorDye,
BookCloning,
MapCloning,
MapExtending,
FireworkRocket,
FireworkStar,
FireworkStarFade,
RepairItem,
TippedArrow,
BannerDuplicate,
BannerAddPattern,
ShieldDecoration,
ShulkerBoxColoring,
Smelting {
group: String,
ingredient: RecipeIngredient,
result: Option<item::Stack>,
experience: f32,
cooking_time: VarInt,
},
}
impl Default for RecipeData {
fn default() -> Self {
RecipeData::ArmorDye
}
}
#[derive(Debug, Default)]
pub struct Recipe {
pub id: String,
pub ty: String,
pub data: RecipeData,
}
impl Serializable for Recipe {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
let id = String::read_from(buf)?;
let ty = String::read_from(buf)?;
let data =
match ty.as_ref() {
"crafting_shapeless" => RecipeData::Shapeless {
group: Serializable::read_from(buf)?,
ingredients: Serializable::read_from(buf)?,
result: Serializable::read_from(buf)?,
},
"crafting_shaped" => {
let width: VarInt = Serializable::read_from(buf)?;
let height: VarInt = Serializable::read_from(buf)?;
let group: String = Serializable::read_from(buf)?;
let capacity = width.0 as usize * height.0 as usize;
let mut ingredients = Vec::with_capacity(capacity);
for _ in 0 .. capacity {
ingredients.push(Serializable::read_from(buf)?);
}
let result: Option<item::Stack> = Serializable::read_from(buf)?;
RecipeData::Shaped { width, height, group, ingredients, result }
}
"crafting_special_armordye" => RecipeData::ArmorDye,
"crafting_special_bookcloning" => RecipeData::BookCloning,
"crafting_special_mapcloning" => RecipeData::MapCloning,
"crafting_special_mapextending" => RecipeData::MapExtending,
"crafting_special_firework_rocket" => RecipeData::FireworkRocket,
"crafting_special_firework_star" => RecipeData::FireworkStar,
"crafting_special_firework_star_fade" => RecipeData::FireworkStarFade,
"crafting_special_repairitem" => RecipeData::RepairItem,
"crafting_special_tippedarrow" => RecipeData::TippedArrow,
"crafting_special_bannerduplicate" => RecipeData::BannerDuplicate,
"crafting_special_banneraddpattern" => RecipeData::BannerAddPattern,
"crafting_special_shielddecoration" => RecipeData::ShieldDecoration,
"crafting_special_shulkerboxcoloring" => RecipeData::ShulkerBoxColoring,
"smelting" => RecipeData::Smelting {
group: Serializable::read_from(buf)?,
ingredient: Serializable::read_from(buf)?,
result: Serializable::read_from(buf)?,
experience: Serializable::read_from(buf)?,
cooking_time: Serializable::read_from(buf)?,
},
_ => panic!("unrecognized recipe type: {}", ty)
};
Ok(Recipe { id, ty, data })
}
fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> {
unimplemented!()
}
}
#[derive(Debug, Default)]
pub struct Tags {
pub tag_name: String,
pub entries: LenPrefixed<VarInt, VarInt>,
}
impl Serializable for Tags {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
Ok(Tags {
tag_name: Serializable::read_from(buf)?,
entries: Serializable::read_from(buf)?,
})
}
fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> {
unimplemented!()
}
}
#[derive(Debug, Default)]
pub struct CommandNode {
pub flags: u8,
pub children: LenPrefixed<VarInt, VarInt>,
pub redirect_node: Option<VarInt>,
pub name: Option<String>,
pub parser: Option<String>,
pub properties: Option<CommandProperty>,
pub suggestions_type: Option<String>,
}
#[derive(Debug, Eq, PartialEq)]
enum CommandNodeType {
Root,
Literal,
Argument,
}
#[derive(Debug)]
pub enum CommandProperty {
Bool,
Double {
flags: u8,
min: Option<f64>,
max: Option<f64>,
},
Float {
flags: u8,
min: Option<f32>,
max: Option<f32>,
},
Integer {
flags: u8,
min: Option<i32>,
max: Option<i32>,
},
String {
token_type: VarInt,
},
Entity {
flags: u8,
},
GameProfile,
BlockPos,
Vec3,
Vec2,
BlockState,
BlockPredicate,
ItemStack,
ItemPredicate,
Color,
Component,
Message,
Nbt,
NbtPath,
Objective,
ObjectiveCriteria,
Operation,
Particle,
Rotation,
ScoreboardSlot,
ScoreHolder {
flags: u8,
},
Swizzle,
Team,
ItemSlot,
ResourceLocation,
MobEffect,
Function,
EntityAnchor,
Range {
decimals: bool,
},
ItemEnchantment,
}
impl Serializable for CommandNode {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
let flags: u8 = Serializable::read_from(buf)?;
let children: LenPrefixed<VarInt, VarInt> = Serializable::read_from(buf)?;
let node_type = match flags & 0x03 {
0 => CommandNodeType::Root,
1 => CommandNodeType::Literal,
2 => CommandNodeType::Argument,
_ => panic!("unrecognized command node type {}", flags & 0x03),
};
let _is_executable = flags & 0x04 != 0;
let has_redirect = flags & 0x08 != 0;
let has_suggestions_type = flags & 0x10 != 0;
let redirect_node: Option<VarInt> = if has_redirect {
Some(Serializable::read_from(buf)?)
} else {
None
};
let name: Option<String> = if node_type == CommandNodeType::Argument || node_type == CommandNodeType::Literal {
Serializable::read_from(buf)?
} else {
None
};
let parser: Option<String> = if node_type == CommandNodeType::Argument {
Serializable::read_from(buf)?
} else {
None
};
let properties: Option<CommandProperty> = if let Some(ref parse) = parser {
Some(match parse.as_ref() {
"brigadier:bool" => CommandProperty::Bool,
"brigadier:double" => {
let flags = Serializable::read_from(buf)?;
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None };
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None };
CommandProperty::Double { flags, min, max }
},
"brigadier:float" => {
let flags = Serializable::read_from(buf)?;
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None };
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None };
CommandProperty::Float { flags, min, max }
},
"brigadier:integer" => {
let flags = Serializable::read_from(buf)?;
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None };
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None };
CommandProperty::Integer { flags, min, max }
},
"brigadier:string" => {
CommandProperty::String { token_type: Serializable::read_from(buf)? }
},
"minecraft:entity" => {
CommandProperty::Entity { flags: Serializable::read_from(buf)? }
},
"minecraft:game_profile" => CommandProperty::GameProfile,
"minecraft:block_pos" => CommandProperty::BlockPos,
"minecraft:vec3" => CommandProperty::Vec3,
"minecraft:vec2" => CommandProperty::Vec2,
"minecraft:block_state" => CommandProperty::BlockState,
"minecraft:block_predicate" => CommandProperty::BlockPredicate,
"minecraft:item_stack" => CommandProperty::ItemStack,
"minecraft:item_predicate" => CommandProperty::ItemPredicate,
"minecraft:color" => CommandProperty::Color,
"minecraft:component" => CommandProperty::Component,
"minecraft:message" => CommandProperty::Message,
"minecraft:nbt" => CommandProperty::Nbt,
"minecraft:nbt_path" => CommandProperty::NbtPath,
"minecraft:objective" => CommandProperty::Objective,
"minecraft:objective_criteria" => CommandProperty::ObjectiveCriteria,
"minecraft:operation" => CommandProperty::Operation,
"minecraft:particle" => CommandProperty::Particle,
"minecraft:rotation" => CommandProperty::Rotation,
"minecraft:scoreboard_slot" => CommandProperty::ScoreboardSlot,
"minecraft:score_holder" => {
CommandProperty::ScoreHolder { flags: Serializable::read_from(buf)? }
},
"minecraft:swizzle" => CommandProperty::Swizzle,
"minecraft:team" => CommandProperty::Team,
"minecraft:item_slot" => CommandProperty::ItemSlot,
"minecraft:resource_location" => CommandProperty::ResourceLocation,
"minecraft:mob_effect" => CommandProperty::MobEffect,
"minecraft:function" => CommandProperty::Function,
"minecraft:entity_anchor" => CommandProperty::EntityAnchor,
"minecraft:range" => {
CommandProperty::Range { decimals: Serializable::read_from(buf)? }
},
"minecraft:item_enchantment" => CommandProperty::ItemEnchantment,
_ => panic!("unsupported command node parser {}", parse),
})
} else {
None
};
let suggestions_type: Option<String> = if has_suggestions_type {
Serializable::read_from(buf)?
} else {
None
};
Ok(CommandNode { flags, children, redirect_node, name, parser, properties, suggestions_type })
}
fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> {
unimplemented!()
}
}

View File

@ -1,5 +1,6 @@
use crate::protocol::*;
mod v1_13_2;
mod v1_12_2;
mod v1_11_2;
mod v1_10_2;
@ -13,6 +14,9 @@ pub fn translate_internal_packet_id_for_version(version: i32, state: State, dir:
match version {
// https://wiki.vg/Protocol_History
// https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite
// 1.13.2
404 => v1_13_2::translate_internal_packet_id(state, dir, id, to_internal),
// 1.12.2
340 => v1_12_2::translate_internal_packet_id(state, dir, id, to_internal),

View File

@ -92,7 +92,7 @@ protocol_packet_ids!(
0x2e => PlayerInfo
0x2f => TeleportPlayer_WithConfirm
0x30 => EntityUsedBed
0x31 => UnlockRecipes
0x31 => UnlockRecipes_NoSmelting
0x32 => EntityDestroy
0x33 => EntityRemoveEffect
0x34 => ResourcePackSend

View File

@ -0,0 +1,169 @@
protocol_packet_ids!(
handshake Handshaking {
serverbound Serverbound {
0x00 => Handshake
}
clientbound Clientbound {
}
}
play Play {
serverbound Serverbound {
0x00 => TeleportConfirm
0x01 => QueryBlockNBT
0x02 => ChatMessage
0x03 => ClientStatus
0x04 => ClientSettings
0x05 => TabComplete
0x06 => ConfirmTransactionServerbound
0x07 => EnchantItem
0x08 => ClickWindow
0x09 => CloseWindow
0x0a => PluginMessageServerbound
0x0b => EditBook
0x0c => QueryEntityNBT
0x0d => UseEntity
0x0e => KeepAliveServerbound_i64
0x0f => Player
0x10 => PlayerPosition
0x11 => PlayerPositionLook
0x12 => PlayerLook
0x13 => VehicleMove
0x14 => SteerBoat
0x15 => PickItem
0x16 => CraftRecipeRequest
0x17 => ClientAbilities
0x18 => PlayerDigging
0x19 => PlayerAction
0x1a => SteerVehicle
0x1b => CraftingBookData
0x1c => NameItem
0x1d => ResourcePackStatus
0x1e => AdvancementTab
0x1f => SelectTrade
0x20 => SetBeaconEffect
0x21 => HeldItemChange
0x22 => UpdateCommandBlock
0x23 => UpdateCommandBlockMinecart
0x24 => CreativeInventoryAction
0x25 => UpdateStructureBlock
0x26 => SetSign
0x27 => ArmSwing
0x28 => SpectateTeleport
0x29 => PlayerBlockPlacement_f32
0x2a => UseItem
}
clientbound Clientbound {
0x00 => SpawnObject
0x01 => SpawnExperienceOrb
0x02 => SpawnGlobalEntity
0x03 => SpawnMob
0x04 => SpawnPainting
0x05 => SpawnPlayer_f64
0x06 => Animation
0x07 => Statistics
0x08 => BlockBreakAnimation
0x09 => UpdateBlockEntity
0x0a => BlockAction
0x0b => BlockChange_VarInt
0x0c => BossBar
0x0d => ServerDifficulty
0x0e => ServerMessage
0x0f => MultiBlockChange_VarInt
0x10 => TabCompleteReply
0x11 => DeclareCommands
0x12 => ConfirmTransaction
0x13 => WindowClose
0x14 => WindowOpen
0x15 => WindowItems
0x16 => WindowProperty
0x17 => WindowSetSlot
0x18 => SetCooldown
0x19 => PluginMessageClientbound
0x1a => NamedSoundEffect
0x1b => Disconnect
0x1c => EntityAction
0x1d => NBTQueryResponse
0x1e => Explosion
0x1f => ChunkUnload
0x20 => ChangeGameState
0x21 => KeepAliveClientbound_i64
0x22 => ChunkData
0x23 => Effect
0x24 => Particle
0x25 => JoinGame_i32
0x26 => Maps
0x27 => Entity
0x28 => EntityMove_i16
0x29 => EntityLookAndMove_i16
0x2a => EntityLook_VarInt
0x2b => VehicleTeleport
0x2c => SignEditorOpen
0x2d => CraftRecipeResponse
0x2e => PlayerAbilities
0x2f => CombatEvent
0x30 => PlayerInfo
0x31 => FacePlayer
0x32 => TeleportPlayer_WithConfirm
0x33 => EntityUsedBed
0x34 => UnlockRecipes_WithSmelting
0x35 => EntityDestroy
0x36 => EntityRemoveEffect
0x37 => ResourcePackSend
0x38 => Respawn
0x39 => EntityHeadLook
0x3a => SelectAdvancementTab
0x3b => WorldBorder
0x3c => Camera
0x3d => SetCurrentHotbarSlot
0x3e => ScoreboardDisplay
0x3f => EntityMetadata
0x40 => EntityAttach
0x41 => EntityVelocity
0x42 => EntityEquipment
0x43 => SetExperience
0x44 => UpdateHealth
0x45 => ScoreboardObjective
0x46 => SetPassengers
0x47 => Teams
0x48 => UpdateScore
0x49 => SpawnPosition
0x4a => TimeUpdate
0x4c => StopSound
0x4d => SoundEffect
0x4e => PlayerListHeaderFooter
0x4f => CollectItem
0x50 => EntityTeleport_f64
0x51 => Advancements
0x52 => EntityProperties
0x53 => EntityEffect
0x54 => DeclareRecipes
0x55 => Tags
}
}
login Login {
serverbound Serverbound {
0x00 => LoginStart
0x01 => EncryptionResponse
0x02 => LoginPluginResponse
}
clientbound Clientbound {
0x00 => LoginDisconnect
0x01 => EncryptionRequest
0x02 => LoginSuccess
0x03 => SetInitialCompression
0x04 => LoginPluginRequest
}
}
status Status {
serverbound Serverbound {
0x00 => StatusRequest
0x01 => StatusPing
}
clientbound Clientbound {
0x00 => StatusResponse
0x01 => StatusPong
}
}
);