From f935afdeac143de9db3206cc57ab7e07d92ae570 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 4 May 2019 16:01:28 -0700 Subject: [PATCH] 1.14 protocol support (477) (#132). Closes #72 Adds 1.14 (477) protocol support, based on: https://wiki.vg/index.php?title=Pre-release_protocol&oldid=14723 * New packets: SetDifficulty, LockDifficulty, UpdateJigsawBlock, UpdateViewPosition, UpdateViewDistance * New metadata: Optional VarInt (17) and Pose (18) * Add new join game variant with view distance, without difficulty * Add new server difficulty variant, with locked boolean * Implement recipe parsing changes, add stonecutting recipe type --- protocol/src/protocol/mod.rs | 2 +- protocol/src/protocol/packet.rs | 85 ++++++++++- protocol/src/protocol/versions.rs | 3 + protocol/src/protocol/versions/v1_14.rs | 180 ++++++++++++++++++++++++ 4 files changed, 266 insertions(+), 4 deletions(-) create mode 100644 protocol/src/protocol/versions/v1_14.rs diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index bb91423..6ac2f39 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -38,7 +38,7 @@ use flate2::Compression; use std::time::{Instant, Duration}; use crate::shared::Position; -pub const SUPPORTED_PROTOCOLS: [i32; 12] = [404, 451, 452, 340, 316, 315, 210, 109, 107, 74, 47, 5]; +pub const SUPPORTED_PROTOCOLS: [i32; 13] = [477, 452, 451, 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]; diff --git a/protocol/src/protocol/packet.rs b/protocol/src/protocol/packet.rs index 41da4ef..6b75acb 100644 --- a/protocol/src/protocol/packet.rs +++ b/protocol/src/protocol/packet.rs @@ -57,6 +57,9 @@ state_packets!( field transaction_id: VarInt =, field location: Position =, } + packet SetDifficulty { + field new_difficulty: u8 =, + } /// TabComplete is sent by the client when the client presses tab in /// the chat box. packet TabComplete { @@ -202,6 +205,9 @@ state_packets!( packet KeepAliveServerbound_i32 { field id: i32 =, } + packet LockDifficulty { + field locked: bool =, + } /// PlayerPosition is used to update the player's position. packet PlayerPosition { field x: f64 =, @@ -370,6 +376,12 @@ state_packets!( field slot: i16 =, field clicked_item: Option =, } + packet UpdateJigsawBlock { + field location: Position =, + field attachment_type: String =, + field target_pool: String =, + field final_state: String =, + } packet UpdateStructureBlock { field location: Position =, field action: VarInt =, @@ -753,6 +765,10 @@ state_packets!( packet ServerDifficulty { field difficulty: u8 =, } + packet ServerDifficulty_Locked { + field difficulty: u8 =, + field locked: bool =, + } /// TabCompleteReply is sent as a reply to a tab completion request. /// The matches should be possible completions for the command/chat the /// player sent. @@ -1055,6 +1071,23 @@ state_packets!( } /// JoinGame is sent after completing the login process. This /// sets the initial state for the client. + packet JoinGame_i32_ViewDistance { + /// The entity id the client will be referenced by + field entity_id: i32 =, + /// The starting gamemode of the client + field gamemode: u8 =, + /// The dimension the client is starting in + field dimension: i32 =, + /// The max number of players on the server + field max_players: u8 =, + /// The level type of the server + field level_type: String =, + /// The render distance (2-32) + field view_distance: VarInt =, + /// Whether the client should reduce the amount of debug + /// information it displays in F3 mode + field reduced_debug_info: bool =, + } packet JoinGame_i32 { /// The entity id the client will be referenced by field entity_id: i32 =, @@ -1377,6 +1410,15 @@ state_packets!( packet SetCurrentHotbarSlot { field slot: u8 =, } + /// UpdateViewPosition is used to determine what chunks should be remain loaded. + packet UpdateViewPosition { + field chunk_x: VarInt =, + field chunk_z: VarInt =, + } + /// UpdateViewDistance is sent by the integrated server when changing render distance. + packet UpdateViewDistance { + field view_distance: VarInt =, + } /// ScoreboardDisplay is used to set the display position of a scoreboard. packet ScoreboardDisplay { field position: u8 =, @@ -2396,6 +2438,11 @@ pub enum RecipeData { experience: f32, cooking_time: VarInt, }, + Stonecutting { + group: String, + ingredient: RecipeIngredient, + result: Option, + }, } impl Default for RecipeData { @@ -2413,8 +2460,35 @@ pub struct Recipe { impl Serializable for Recipe { fn read_from(buf: &mut R) -> Result { - let id = String::read_from(buf)?; - let ty = String::read_from(buf)?; + let (id, ty, namespace) = { + let a = String::read_from(buf)?; + let b = String::read_from(buf)?; + + let protocol_version = unsafe { crate::protocol::CURRENT_PROTOCOL_VERSION }; + + // 1.14+ swaps recipe identifier and type, and adds namespace to type + if protocol_version >= 477 { + let ty = a; + let id = b; + + if let Some(at) = ty.find(':') { + let (namespace, ty) = ty.split_at(at + 1); + let ty: String = ty.into(); + let namespace: String = namespace.into(); + (id, ty, namespace) + } else { + (id, ty, "minecraft:".to_string()) + } + } else { + let ty = b; + let id = a; + (id, ty, "minecraft:".to_string()) + } + }; + + if namespace != "minecraft:" { + panic!("unrecognized recipe type namespace: {}", namespace); + } let data = match ty.as_ref() { @@ -2473,13 +2547,18 @@ impl Serializable for Recipe { experience: Serializable::read_from(buf)?, cooking_time: Serializable::read_from(buf)?, }, - "campfire" => RecipeData::Campfire { + "campfire" | "campfire_cooking" => RecipeData::Campfire { 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)?, }, + "stonecutting" => RecipeData::Stonecutting { + group: Serializable::read_from(buf)?, + ingredient: Serializable::read_from(buf)?, + result: Serializable::read_from(buf)?, + }, _ => panic!("unrecognized recipe type: {}", ty) }; diff --git a/protocol/src/protocol/versions.rs b/protocol/src/protocol/versions.rs index d80b2a6..dbc569a 100644 --- a/protocol/src/protocol/versions.rs +++ b/protocol/src/protocol/versions.rs @@ -1,5 +1,6 @@ use crate::protocol::*; +mod v1_14; mod v19w02a; mod v18w50a; mod v1_13_2; @@ -16,6 +17,8 @@ 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 + + 477 => v1_14::translate_internal_packet_id(state, dir, id, to_internal), // 19w02a 452 => v19w02a::translate_internal_packet_id(state, dir, id, to_internal), diff --git a/protocol/src/protocol/versions/v1_14.rs b/protocol/src/protocol/versions/v1_14.rs new file mode 100644 index 0000000..7949206 --- /dev/null +++ b/protocol/src/protocol/versions/v1_14.rs @@ -0,0 +1,180 @@ +protocol_packet_ids!( + handshake Handshaking { + serverbound Serverbound { + 0x00 => Handshake + } + clientbound Clientbound { + } + } + play Play { + serverbound Serverbound { + 0x00 => TeleportConfirm + 0x01 => QueryBlockNBT + 0x02 => SetDifficulty + 0x03 => ChatMessage + 0x04 => ClientStatus + 0x05 => ClientSettings + 0x06 => TabComplete + 0x07 => ConfirmTransactionServerbound + //0x08 => EnchantItem + //0x08 => ClickWindowButton + 0x09 => ClickWindow + 0x0a => CloseWindow + 0x0b => PluginMessageServerbound + 0x0c => EditBook + 0x0d => QueryEntityNBT + 0x0e => UseEntity + 0x0f => KeepAliveServerbound_i64 + 0x10 => LockDifficulty + 0x11 => PlayerPosition + 0x12 => PlayerPositionLook + 0x13 => PlayerLook + 0x14 => Player + 0x15 => VehicleMove + 0x16 => SteerBoat + 0x17 => PickItem + 0x18 => CraftRecipeRequest + 0x19 => ClientAbilities + 0x1a => PlayerDigging + 0x1b => PlayerAction + 0x1c => SteerVehicle + 0x1d => CraftingBookData + 0x1e => NameItem + 0x1f => ResourcePackStatus + 0x20 => AdvancementTab + 0x21 => SelectTrade + 0x22 => SetBeaconEffect + 0x23 => HeldItemChange + 0x24 => UpdateCommandBlock + 0x25 => UpdateCommandBlockMinecart + 0x26 => CreativeInventoryAction + 0x27 => UpdateJigsawBlock + 0x28 => UpdateStructureBlock + 0x29 => SetSign + 0x2a => ArmSwing + 0x2b => SpectateTeleport + 0x2c => PlayerBlockPlacement_f32 + 0x2d => 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_Locked + 0x0e => ServerMessage + 0x0f => MultiBlockChange_VarInt + 0x10 => TabCompleteReply + 0x11 => DeclareCommands + 0x12 => ConfirmTransaction + 0x13 => WindowClose + 0x14 => WindowItems + 0x15 => WindowProperty + 0x16 => WindowSetSlot + 0x17 => SetCooldown + 0x18 => PluginMessageClientbound + 0x19 => NamedSoundEffect + 0x1a => Disconnect + 0x1b => EntityAction + 0x1c => Explosion + 0x1d => ChunkUnload + 0x1e => ChangeGameState + 0x1f => WindowOpenHorse + 0x20 => KeepAliveClientbound_i64 + 0x21 => ChunkData_HeightMap + 0x22 => Effect + 0x23 => Particle_Data + 0x24 => UpdateLight + 0x25 => JoinGame_i32_ViewDistance + 0x26 => Maps + 0x27 => TradeList + 0x28 => EntityMove_i16 + 0x29 => EntityLookAndMove_i16 + 0x2a => EntityLook_VarInt + 0x2b => Entity + 0x2c => VehicleTeleport + 0x2d => OpenBook + 0x2e => WindowOpen_VarInt + 0x2f => SignEditorOpen + 0x30 => CraftRecipeResponse + 0x31 => PlayerAbilities + 0x32 => CombatEvent + 0x33 => PlayerInfo + 0x34 => FacePlayer + 0x35 => TeleportPlayer_WithConfirm + 0x36 => UnlockRecipes_WithSmelting + 0x37 => EntityDestroy + 0x38 => EntityRemoveEffect + 0x39 => ResourcePackSend + 0x3a => Respawn + 0x3b => EntityHeadLook + 0x3c => SelectAdvancementTab + 0x3d => WorldBorder + 0x3e => Camera + 0x3f => SetCurrentHotbarSlot + 0x40 => UpdateViewPosition + 0x41 => UpdateViewDistance + 0x42 => ScoreboardDisplay + 0x43 => EntityMetadata + 0x44 => EntityAttach + 0x45 => EntityVelocity + 0x46 => EntityEquipment + 0x47 => SetExperience + 0x48 => UpdateHealth + 0x49 => ScoreboardObjective + 0x4a => SetPassengers + 0x4b => Teams + 0x4c => UpdateScore + 0x4d => SpawnPosition + 0x4e => TimeUpdate + 0x4f => Title + 0x50 => EntitySoundEffect + 0x51 => SoundEffect + 0x52 => StopSound + 0x53 => PlayerListHeaderFooter + 0x54 => NBTQueryResponse + 0x55 => CollectItem + 0x56 => EntityTeleport_f64 + 0x57 => Advancements + 0x58 => EntityProperties + 0x59 => EntityEffect + 0x5a => DeclareRecipes + 0x5b => TagsWithEntities + } + } + 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 + } + } +); + +