From d03f102bb8cb771b1a8159ba34a255c9d5fd90f4 Mon Sep 17 00:00:00 2001 From: iceiix <43691553+iceiix@users.noreply.github.com> Date: Mon, 3 Dec 2018 14:22:47 -0800 Subject: [PATCH] Multiprotocol support: 1.12.2 and 1.11.2 (#54) Adds support for connecting to both 1.12.2 and 1.11.2 (protocols 340 and 316) servers https://github.com/iceiix/steven/issues/18 Enhance protocol support Closes https://github.com/iceiix/steven/pull/48 1.11.2 protocol support (316) * Restore create_ids!() macro in packet identifiers * Add translate_packet_id() function to map external 1.12.2 packet ids to internal sequential ids * Implement translate_internal_packet_id() from a new protocol_packet_ids! macro * Move packet IDs to separate file, v1_12_2.rs * Change supported protocols constant to an array * Add v1_11_2 protocol packet IDs (from https://github.com/iceiix/steven/pull/48) * Add keep alive packet variants: _i64 (>=1.12.2) and _VarInt (<=1.11.2) * Abstract protocol versions, can now connect to both 1.12.2 and 1.11.2 * Send protocol version in handshake packet * Restore 1.11 (315) protocol support as in original (https://github.com/thinkofname/steven) Steven --- src/main.rs | 6 +- src/protocol/mod.rs | 196 ++++++++++--------------------- src/protocol/packet.rs | 10 +- src/protocol/versions.rs | 21 ++++ src/protocol/versions/v1_11_2.rs | 145 +++++++++++++++++++++++ src/protocol/versions/v1_12_2.rs | 152 ++++++++++++++++++++++++ src/screen/server_list.rs | 4 +- src/server/mod.rs | 15 ++- 8 files changed, 404 insertions(+), 145 deletions(-) create mode 100644 src/protocol/versions.rs create mode 100644 src/protocol/versions/v1_11_2.rs create mode 100644 src/protocol/versions/v1_12_2.rs diff --git a/src/main.rs b/src/main.rs index 81ff24a..22ba351 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,8 +96,8 @@ impl Game { if let Some(v) = server_versions_info.get(address) { v.as_i64().unwrap() as i32 } else { - warn!("Server protocol version not known for {} (no ping response?), defaulting to {}", address, protocol::SUPPORTED_PROTOCOL); - protocol::SUPPORTED_PROTOCOL + warn!("Server protocol version not known for {} (no ping response?), defaulting to {}", address, protocol::SUPPORTED_PROTOCOLS[0]); + protocol::SUPPORTED_PROTOCOLS[0] } }; @@ -230,7 +230,7 @@ fn main() { should_close: false, chunk_builder: chunk_builder::ChunkBuilder::new(resource_manager, textures), connect_reply: None, - protocol_version: protocol::SUPPORTED_PROTOCOL, + protocol_version: protocol::SUPPORTED_PROTOCOLS[0], dpi_factor, last_mouse_x: 0.0, last_mouse_y: 0.0, diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index c0f7a6c..4a31c74 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -13,6 +13,7 @@ // limitations under the License. #![allow(dead_code)] +#![allow(non_camel_case_types)] use aes::Aes128; use cfb8::Cfb8; @@ -36,7 +37,7 @@ use flate2::Compression; use std::time::{Instant, Duration}; use crate::shared::Position; -pub const SUPPORTED_PROTOCOL: i32 = 340; +pub const SUPPORTED_PROTOCOLS: [i32; 3] = [340, 316, 315]; /// Helper macro for defining packets @@ -83,130 +84,7 @@ macro_rules! state_packets { #[allow(non_upper_case_globals)] pub mod internal_ids { -pub const Handshake: i32 = 0x00; -pub const TeleportConfirm: i32 = 0x00; -pub const TabComplete: i32 = 0x01; -pub const ChatMessage: i32 = 0x02; -pub const ClientStatus: i32 = 0x03; -pub const ClientSettings: i32 = 0x04; -pub const ConfirmTransactionServerbound: i32 = 0x05; -pub const EnchantItem: i32 = 0x06; -pub const ClickWindow: i32 = 0x07; -pub const CloseWindow: i32 = 0x08; -pub const PluginMessageServerbound: i32 = 0x09; -pub const UseEntity: i32 = 0x0a; -pub const KeepAliveServerbound: i32 = 0x0b; -pub const Player: i32 = 0x0c; -pub const PlayerPosition: i32 = 0x0d; -pub const PlayerPositionLook: i32 = 0x0e; -pub const PlayerLook: i32 = 0x0f; -pub const VehicleMove: i32 = 0x10; -pub const SteerBoat: i32 = 0x11; -pub const CraftRecipeRequest: i32 = 0x12; -pub const ClientAbilities: i32 = 0x13; -pub const PlayerDigging: i32 = 0x14; -pub const PlayerAction: i32 = 0x15; -pub const SteerVehicle: i32 = 0x16; -pub const CraftingBookData: i32 = 0x17; -pub const ResourcePackStatus: i32 = 0x18; -pub const AdvancementTab: i32 = 0x19; -pub const HeldItemChange: i32 = 0x1a; -pub const CreativeInventoryAction: i32 = 0x1b; -pub const SetSign: i32 = 0x1c; -pub const ArmSwing: i32 = 0x1d; -pub const SpectateTeleport: i32 = 0x1e; -pub const PlayerBlockPlacement: i32 = 0x1f; -pub const UseItem: i32 = 0x20; -pub const SpawnObject: i32 = 0x00; -pub const SpawnExperienceOrb: i32 = 0x01; -pub const SpawnGlobalEntity: i32 = 0x02; -pub const SpawnMob: i32 = 0x03; -pub const SpawnPainting: i32 = 0x04; -pub const SpawnPlayer: i32 = 0x05; -pub const Animation: i32 = 0x06; -pub const Statistics: i32 = 0x07; -pub const BlockBreakAnimation: i32 = 0x08; -pub const UpdateBlockEntity: i32 = 0x09; -pub const BlockAction: i32 = 0x0a; -pub const BlockChange: i32 = 0x0b; -pub const BossBar: i32 = 0x0c; -pub const ServerDifficulty: i32 = 0x0d; -pub const TabCompleteReply: i32 = 0x0e; -pub const ServerMessage: i32 = 0x0f; -pub const MultiBlockChange: i32 = 0x10; -pub const ConfirmTransaction: i32 = 0x11; -pub const WindowClose: i32 = 0x12; -pub const WindowOpen: i32 = 0x13; -pub const WindowItems: i32 = 0x14; -pub const WindowProperty: i32 = 0x15; -pub const WindowSetSlot: i32 = 0x16; -pub const SetCooldown: i32 = 0x17; -pub const PluginMessageClientbound: i32 = 0x18; -pub const NamedSoundEffect: i32 = 0x19; -pub const Disconnect: i32 = 0x1a; -pub const EntityAction: i32 = 0x1b; -pub const Explosion: i32 = 0x1c; -pub const ChunkUnload: i32 = 0x1d; -pub const ChangeGameState: i32 = 0x1e; -pub const KeepAliveClientbound: i32 = 0x1f; -pub const ChunkData: i32 = 0x20; -pub const Effect: i32 = 0x21; -pub const Particle: i32 = 0x22; -pub const JoinGame: i32 = 0x23; -pub const Maps: i32 = 0x24; -pub const Entity: i32 = 0x25; -pub const EntityMove: i32 = 0x26; -pub const EntityLookAndMove: i32 = 0x27; -pub const EntityLook: i32 = 0x28; -pub const VehicleTeleport: i32 = 0x29; -pub const SignEditorOpen: i32 = 0x2a; -pub const CraftRecipeResponse: i32 = 0x2b; -pub const PlayerAbilities: i32 = 0x2c; -pub const CombatEvent: i32 = 0x2d; -pub const PlayerInfo: i32 = 0x2e; -pub const TeleportPlayer: i32 = 0x2f; -pub const EntityUsedBed: i32 = 0x30; -pub const UnlockRecipes: i32 = 0x31; -pub const EntityDestroy: i32 = 0x32; -pub const EntityRemoveEffect: i32 = 0x33; -pub const ResourcePackSend: i32 = 0x34; -pub const Respawn: i32 = 0x35; -pub const EntityHeadLook: i32 = 0x36; -pub const SelectAdvancementTab: i32 = 0x37; -pub const WorldBorder: i32 = 0x38; -pub const Camera: i32 = 0x39; -pub const SetCurrentHotbarSlot: i32 = 0x3a; -pub const ScoreboardDisplay: i32 = 0x3b; -pub const EntityMetadata: i32 = 0x3c; -pub const EntityAttach: i32 = 0x3d; -pub const EntityVelocity: i32 = 0x3e; -pub const EntityEquipment: i32 = 0x3f; -pub const SetExperience: i32 = 0x40; -pub const UpdateHealth: i32 = 0x41; -pub const ScoreboardObjective: i32 = 0x42; -pub const SetPassengers: i32 = 0x43; -pub const Teams: i32 = 0x44; -pub const UpdateScore: i32 = 0x45; -pub const SpawnPosition: i32 = 0x46; -pub const TimeUpdate: i32 = 0x47; -pub const Title: i32 = 0x48; -pub const SoundEffect: i32 = 0x49; -pub const PlayerListHeaderFooter: i32 = 0x4a; -pub const CollectItem: i32 = 0x4b; -pub const EntityTeleport: i32 = 0x4c; -pub const Advancements: i32 = 0x4d; -pub const EntityProperties: i32 = 0x4e; -pub const EntityEffect: i32 = 0x4f; -pub const LoginStart: i32 = 0x00; -pub const EncryptionResponse: i32 = 0x01; -pub const LoginDisconnect: i32 = 0x00; -pub const EncryptionRequest: i32 = 0x01; -pub const LoginSuccess: i32 = 0x02; -pub const SetInitialCompression: i32 = 0x03; -pub const StatusRequest: i32 = 0x00; -pub const StatusPing: i32 = 0x01; -pub const StatusResponse: i32 = 0x00; -pub const StatusPong: i32 = 0x01; + create_ids!(i32, $($name),*); } $( @@ -217,7 +95,9 @@ pub const StatusPong: i32 = 0x01; impl PacketType for $name { - fn packet_id(&self) -> i32 { internal_ids::$name } + fn packet_id(&self, version: i32) -> i32 { + packet::versions::translate_internal_packet_id_for_version(version, State::$stateName, Direction::$dirName, internal_ids::$name, false) + } fn write(self, buf: &mut W) -> Result<(), Error> { $( @@ -237,14 +117,15 @@ pub const StatusPong: i32 = 0x01; /// Returns the packet for the given state, direction and id after parsing the fields /// from the buffer. - pub fn packet_by_id(state: State, dir: Direction, id: i32, mut buf: &mut R) -> Result, Error> { + pub fn packet_by_id(version: i32, state: State, dir: Direction, id: i32, mut buf: &mut R) -> Result, Error> { match state { $( State::$stateName => { match dir { $( Direction::$dirName => { - match id { + let internal_id = packet::versions::translate_internal_packet_id_for_version(version, state, dir, id, true); + match internal_id { $( self::$state::$dir::internal_ids::$name => { use self::$state::$dir::$name; @@ -269,8 +150,52 @@ pub const StatusPong: i32 = 0x01; } } -pub mod packet; +#[macro_export] +macro_rules! protocol_packet_ids { + ($($state:ident $stateName:ident { + $($dir:ident $dirName:ident { + $( + $(#[$attr:meta])* + $id:expr => $name:ident + )* + })+ + })+) => { + use crate::protocol::*; + pub fn translate_internal_packet_id(state: State, dir: Direction, id: i32, to_internal: bool) -> i32 { + match state { + $( + State::$stateName => { + match dir { + $( + Direction::$dirName => { + if to_internal { + match id { + $( + $id => crate::protocol::packet::$state::$dir::internal_ids::$name, + )* + _ => panic!("bad packet id $id in $dir $state"), + } + } else { + match id { + $( + crate::protocol::packet::$state::$dir::internal_ids::$name => $id, + )* + _ => panic!("bad packet internal id $id in $dir $state"), + } + } + } + )* + } + } + )* + } + } + } +} + +pub mod packet; +pub mod versions; pub trait Serializable: Sized { fn read_from(buf: &mut R) -> Result; fn write_to(&self, buf: &mut W) -> Result<(), Error>; @@ -868,6 +793,7 @@ pub struct Conn { pub host: String, pub port: u16, direction: Direction, + pub protocol_version: i32, pub state: State, cipher: Option, @@ -878,7 +804,7 @@ pub struct Conn { } impl Conn { - pub fn new(target: &str) -> Result { + pub fn new(target: &str, protocol_version: i32) -> Result { // TODO SRV record support let mut parts = target.split(':').collect::>(); let address = if parts.len() == 1 { @@ -894,6 +820,7 @@ impl Conn { port: parts[1].parse().unwrap(), direction: Direction::Serverbound, state: State::Handshaking, + protocol_version, cipher: Option::None, compression_threshold: -1, compression_read: Option::None, @@ -903,7 +830,7 @@ impl Conn { pub fn write_packet(&mut self, packet: T) -> Result<(), Error> { let mut buf = Vec::new(); - VarInt(packet.packet_id()).write_to(&mut buf)?; + VarInt(packet.packet_id(self.protocol_version)).write_to(&mut buf)?; packet.write(&mut buf)?; let mut extra = if self.compression_threshold >= 0 { @@ -963,7 +890,7 @@ impl Conn { Direction::Serverbound => Direction::Clientbound, }; - let packet = packet::packet_by_id(self.state, dir, id, &mut buf)?; + let packet = packet::packet_by_id(self.protocol_version, self.state, dir, id, &mut buf)?; match packet { Some(val) => { @@ -998,7 +925,7 @@ impl Conn { let host = self.host.clone(); let port = self.port; self.write_packet(Handshake { - protocol_version: VarInt(SUPPORTED_PROTOCOL), + protocol_version: VarInt(self.protocol_version), host, port, next: VarInt(1), @@ -1131,6 +1058,7 @@ impl Clone for Conn { port: self.port, direction: self.direction, state: self.state, + protocol_version: self.protocol_version, cipher: Option::None, compression_threshold: self.compression_threshold, compression_read: Option::None, @@ -1140,7 +1068,7 @@ impl Clone for Conn { } pub trait PacketType { - fn packet_id(&self) -> i32; + fn packet_id(&self, protocol_version: i32) -> i32; fn write(self, buf: &mut W) -> Result<(), Error>; } diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs index f23e353..94a60e2 100644 --- a/src/protocol/packet.rs +++ b/src/protocol/packet.rs @@ -123,9 +123,12 @@ state_packets!( /// KeepAliveServerbound is sent by a client as a response to a /// KeepAliveClientbound. If the client doesn't reply the server /// may disconnect the client. - packet KeepAliveServerbound { + packet KeepAliveServerbound_i64 { field id: i64 =, } + packet KeepAliveServerbound_VarInt { + field id: VarInt =, + } /// PlayerPosition is used to update the player's position. packet PlayerPosition { field x: f64 =, @@ -505,9 +508,12 @@ state_packets!( /// client is still responding and keep the connection open. /// The client should reply with the KeepAliveServerbound /// packet setting ID to the same as this one. - packet KeepAliveClientbound { + packet KeepAliveClientbound_i64 { field id: i64 =, } + packet KeepAliveClientbound_VarInt { + field id: VarInt =, + } /// ChunkData sends or updates a single chunk on the client. If New is set /// then biome data should be sent too. packet ChunkData { diff --git a/src/protocol/versions.rs b/src/protocol/versions.rs new file mode 100644 index 0000000..ce355d6 --- /dev/null +++ b/src/protocol/versions.rs @@ -0,0 +1,21 @@ +use crate::protocol::*; + +mod v1_12_2; +mod v1_11_2; + +pub fn translate_internal_packet_id_for_version(version: i32, state: State, dir: Direction, id: i32, to_internal: bool) -> i32 { + match version { + // https://wiki.vg/Protocol_History + // https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite + // 1.12.2 + 340 => v1_12_2::translate_internal_packet_id(state, dir, id, to_internal), + + // 1.11.2 + 316 => v1_11_2::translate_internal_packet_id(state, dir, id, to_internal), + + // 1.11 + 315 => v1_11_2::translate_internal_packet_id(state, dir, id, to_internal), + + _ => panic!("unsupported protocol version"), + } +} diff --git a/src/protocol/versions/v1_11_2.rs b/src/protocol/versions/v1_11_2.rs new file mode 100644 index 0000000..02dc201 --- /dev/null +++ b/src/protocol/versions/v1_11_2.rs @@ -0,0 +1,145 @@ +protocol_packet_ids!( + handshake Handshaking { + serverbound Serverbound { + 0x00 => Handshake + } + clientbound Clientbound { + } + } + play Play { + serverbound Serverbound { + 0x00 => TeleportConfirm + 0x01 => TabComplete + 0x02 => ChatMessage + 0x03 => ClientStatus + 0x04 => ClientSettings + 0x05 => ConfirmTransactionServerbound + 0x06 => EnchantItem + 0x07 => ClickWindow + 0x08 => CloseWindow + 0x09 => PluginMessageServerbound + 0x0a => UseEntity + 0x0b => KeepAliveServerbound_VarInt + 0x0c => PlayerPosition + 0x0d => PlayerPositionLook + 0x0e => PlayerLook + 0x0f => Player + 0x10 => VehicleMove + 0x11 => SteerBoat + 0x12 => ClientAbilities + 0x13 => PlayerDigging + 0x14 => PlayerAction + 0x15 => SteerVehicle + 0x16 => ResourcePackStatus + 0x17 => HeldItemChange + 0x18 => CreativeInventoryAction + 0x19 => SetSign + 0x1a => ArmSwing + 0x1b => SpectateTeleport + 0x1c => PlayerBlockPlacement + 0x1d => UseItem + } + clientbound Clientbound { + 0x00 => SpawnObject + 0x01 => SpawnExperienceOrb + 0x02 => SpawnGlobalEntity + 0x03 => SpawnMob + 0x04 => SpawnPainting + 0x05 => SpawnPlayer + 0x06 => Animation + 0x07 => Statistics + 0x08 => BlockBreakAnimation + 0x09 => UpdateBlockEntity + 0x0a => BlockAction + 0x0b => BlockChange + 0x0c => BossBar + 0x0d => ServerDifficulty + 0x0e => TabCompleteReply + 0x0f => ServerMessage + 0x10 => MultiBlockChange + 0x11 => ConfirmTransaction + 0x12 => WindowClose + 0x13 => WindowOpen + 0x14 => WindowItems + 0x15 => WindowProperty + 0x16 => WindowSetSlot + 0x17 => SetCooldown + 0x18 => PluginMessageClientbound + 0x19 => NamedSoundEffect + 0x1a => Disconnect + 0x1b => EntityAction + 0x1c => Explosion + 0x1d => ChunkUnload + 0x1e => ChangeGameState + 0x1f => KeepAliveClientbound_VarInt + 0x20 => ChunkData + 0x21 => Effect + 0x22 => Particle + 0x23 => JoinGame + 0x24 => Maps + 0x25 => EntityMove + 0x26 => EntityLookAndMove + 0x27 => EntityLook + 0x28 => Entity + 0x29 => VehicleTeleport + 0x2a => SignEditorOpen + 0x2b => PlayerAbilities + 0x2c => CombatEvent + 0x2d => PlayerInfo + 0x2e => TeleportPlayer + 0x2f => EntityUsedBed + 0x30 => EntityDestroy + 0x31 => EntityRemoveEffect + 0x32 => ResourcePackSend + 0x33 => Respawn + 0x34 => EntityHeadLook + 0x35 => WorldBorder + 0x36 => Camera + 0x37 => SetCurrentHotbarSlot + 0x38 => ScoreboardDisplay + 0x39 => EntityMetadata + 0x3a => EntityAttach + 0x3b => EntityVelocity + 0x3c => EntityEquipment + 0x3d => SetExperience + 0x3e => UpdateHealth + 0x3f => ScoreboardObjective + 0x40 => SetPassengers + 0x41 => Teams + 0x42 => UpdateScore + 0x43 => SpawnPosition + 0x44 => TimeUpdate + 0x45 => Title + 0x46 => SoundEffect + 0x47 => PlayerListHeaderFooter + 0x48 => CollectItem + 0x49 => EntityTeleport + 0x4a => EntityProperties + 0x4b => EntityEffect + } + } + login Login { + serverbound Serverbound { + 0x00 => LoginStart + 0x01 => EncryptionResponse + } + clientbound Clientbound { + 0x00 => LoginDisconnect + 0x01 => EncryptionRequest + 0x02 => LoginSuccess + 0x03 => SetInitialCompression + } + } + status Status { + serverbound Serverbound { + 0x00 => StatusRequest + 0x01 => StatusPing + } + clientbound Clientbound { + 0x00 => StatusResponse + 0x01 => StatusPong + } + } +); + + diff --git a/src/protocol/versions/v1_12_2.rs b/src/protocol/versions/v1_12_2.rs new file mode 100644 index 0000000..d4ceb8d --- /dev/null +++ b/src/protocol/versions/v1_12_2.rs @@ -0,0 +1,152 @@ +protocol_packet_ids!( + handshake Handshaking { + serverbound Serverbound { + 0x00 => Handshake + } + clientbound Clientbound { + } + } + play Play { + serverbound Serverbound { + 0x00 => TeleportConfirm + 0x01 => TabComplete + 0x02 => ChatMessage + 0x03 => ClientStatus + 0x04 => ClientSettings + 0x05 => ConfirmTransactionServerbound + 0x06 => EnchantItem + 0x07 => ClickWindow + 0x08 => CloseWindow + 0x09 => PluginMessageServerbound + 0x0a => UseEntity + 0x0b => KeepAliveServerbound_i64 + 0x0c => Player + 0x0d => PlayerPosition + 0x0e => PlayerPositionLook + 0x0f => PlayerLook + 0x10 => VehicleMove + 0x11 => SteerBoat + 0x12 => CraftRecipeRequest + 0x13 => ClientAbilities + 0x14 => PlayerDigging + 0x15 => PlayerAction + 0x16 => SteerVehicle + 0x17 => CraftingBookData + 0x18 => ResourcePackStatus + 0x19 => AdvancementTab + 0x1a => HeldItemChange + 0x1b => CreativeInventoryAction + 0x1c => SetSign + 0x1d => ArmSwing + 0x1e => SpectateTeleport + 0x1f => PlayerBlockPlacement + 0x20 => UseItem + } + clientbound Clientbound { + 0x00 => SpawnObject + 0x01 => SpawnExperienceOrb + 0x02 => SpawnGlobalEntity + 0x03 => SpawnMob + 0x04 => SpawnPainting + 0x05 => SpawnPlayer + 0x06 => Animation + 0x07 => Statistics + 0x08 => BlockBreakAnimation + 0x09 => UpdateBlockEntity + 0x0a => BlockAction + 0x0b => BlockChange + 0x0c => BossBar + 0x0d => ServerDifficulty + 0x0e => TabCompleteReply + 0x0f => ServerMessage + 0x10 => MultiBlockChange + 0x11 => ConfirmTransaction + 0x12 => WindowClose + 0x13 => WindowOpen + 0x14 => WindowItems + 0x15 => WindowProperty + 0x16 => WindowSetSlot + 0x17 => SetCooldown + 0x18 => PluginMessageClientbound + 0x19 => NamedSoundEffect + 0x1a => Disconnect + 0x1b => EntityAction + 0x1c => Explosion + 0x1d => ChunkUnload + 0x1e => ChangeGameState + 0x1f => KeepAliveClientbound_i64 + 0x20 => ChunkData + 0x21 => Effect + 0x22 => Particle + 0x23 => JoinGame + 0x24 => Maps + 0x25 => Entity + 0x26 => EntityMove + 0x27 => EntityLookAndMove + 0x28 => EntityLook + 0x29 => VehicleTeleport + 0x2a => SignEditorOpen + 0x2b => CraftRecipeResponse + 0x2c => PlayerAbilities + 0x2d => CombatEvent + 0x2e => PlayerInfo + 0x2f => TeleportPlayer + 0x30 => EntityUsedBed + 0x31 => UnlockRecipes + 0x32 => EntityDestroy + 0x33 => EntityRemoveEffect + 0x34 => ResourcePackSend + 0x35 => Respawn + 0x36 => EntityHeadLook + 0x37 => SelectAdvancementTab + 0x38 => WorldBorder + 0x39 => Camera + 0x3a => SetCurrentHotbarSlot + 0x3b => ScoreboardDisplay + 0x3c => EntityMetadata + 0x3d => EntityAttach + 0x3e => EntityVelocity + 0x3f => EntityEquipment + 0x40 => SetExperience + 0x41 => UpdateHealth + 0x42 => ScoreboardObjective + 0x43 => SetPassengers + 0x44 => Teams + 0x45 => UpdateScore + 0x46 => SpawnPosition + 0x47 => TimeUpdate + 0x48 => Title + 0x49 => SoundEffect + 0x4a => PlayerListHeaderFooter + 0x4b => CollectItem + 0x4c => EntityTeleport + 0x4d => Advancements + 0x4e => EntityProperties + 0x4f => EntityEffect + } + } + login Login { + serverbound Serverbound { + 0x00 => LoginStart + 0x01 => EncryptionResponse + } + clientbound Clientbound { + 0x00 => LoginDisconnect + 0x01 => EncryptionRequest + 0x02 => LoginSuccess + 0x03 => SetInitialCompression + } + } + status Status { + serverbound Serverbound { + 0x00 => StatusRequest + 0x01 => StatusPing + } + clientbound Clientbound { + 0x00 => StatusResponse + 0x01 => StatusPong + } + } +); + + diff --git a/src/screen/server_list.rs b/src/screen/server_list.rs index 3051091..1c1f639 100644 --- a/src/screen/server_list.rs +++ b/src/screen/server_list.rs @@ -263,7 +263,7 @@ impl ServerList { // Don't block the main thread whilst pinging the server thread::spawn(move || { - match protocol::Conn::new(&address).and_then(|conn| conn.do_status()) { + match protocol::Conn::new(&address, protocol::SUPPORTED_PROTOCOLS[0]).and_then(|conn| conn.do_status()) { Ok(res) => { let mut desc = res.0.description; format::convert_legacy(&mut desc); @@ -484,7 +484,7 @@ impl super::Screen for ServerList { if res.exists { { let mut players = s.players.borrow_mut(); - let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL { + let txt = if protocol::SUPPORTED_PROTOCOLS.contains(&res.protocol_version) { players.colour.1 = 255; players.colour.2 = 255; format!("{}/{}", res.online, res.max) diff --git a/src/server/mod.rs b/src/server/mod.rs index f737cba..0230c92 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -104,7 +104,7 @@ macro_rules! handle_packet { impl Server { pub fn connect(resources: Arc>, profile: mojang::Profile, address: &str, protocol_version: i32) -> Result { - let mut conn = protocol::Conn::new(address)?; + let mut conn = protocol::Conn::new(address, protocol_version)?; let host = conn.host.clone(); let port = conn.port; @@ -374,7 +374,8 @@ impl Server { self pck { JoinGame => on_game_join, Respawn => on_respawn, - KeepAliveClientbound => on_keep_alive, + KeepAliveClientbound_i64 => on_keep_alive_i64, + KeepAliveClientbound_VarInt => on_keep_alive_varint, ChunkData => on_chunk_data, ChunkUnload => on_chunk_unload, BlockChange => on_block_change, @@ -536,8 +537,14 @@ impl Server { let _ = self.conn.as_mut().unwrap().write_packet(p); // TODO handle errors } - fn on_keep_alive(&mut self, keep_alive: packet::play::clientbound::KeepAliveClientbound) { - self.write_packet(packet::play::serverbound::KeepAliveServerbound { + fn on_keep_alive_i64(&mut self, keep_alive: packet::play::clientbound::KeepAliveClientbound_i64) { + self.write_packet(packet::play::serverbound::KeepAliveServerbound_i64 { + id: keep_alive.id, + }); + } + + fn on_keep_alive_varint(&mut self, keep_alive: packet::play::clientbound::KeepAliveClientbound_VarInt) { + self.write_packet(packet::play::serverbound::KeepAliveServerbound_VarInt { id: keep_alive.id, }); }