From 24e6e7436febc612e09aede9294dd54a6da92e81 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Thu, 21 Jan 2021 18:52:41 -0800 Subject: [PATCH 01/18] protocol: update Cargo.lock --- protocol/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/Cargo.lock b/protocol/Cargo.lock index d094b56a..190892b2 100644 --- a/protocol/Cargo.lock +++ b/protocol/Cargo.lock @@ -840,9 +840,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.119" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3" +checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab" [[package]] name = "serde_json" From 1a8b743232d2869bd4cadb8288ed3d599ed1cb4d Mon Sep 17 00:00:00 2001 From: ice_iix Date: Thu, 21 Jan 2021 18:53:22 -0800 Subject: [PATCH 02/18] protocol: send FML2 on fmlNetworkVersion: 2 --- protocol/src/protocol/mod.rs | 5 +++++ src/main.rs | 7 ++++--- src/server/mod.rs | 11 +++++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 5b59cbec..8b6cd636 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1224,6 +1224,7 @@ impl Conn { // For modded servers, get the list of Forge mods installed let mut forge_mods: std::vec::Vec = vec![]; + let mut fml_network_version: Option = None; if let Some(modinfo) = val.get("modinfo") { if let Some(modinfo_type) = modinfo.get("type") { if modinfo_type == "FML" { @@ -1240,6 +1241,7 @@ impl Conn { .push(crate::protocol::forge::ForgeMod { modid, version }); } } + fml_network_version = Some(1); } } } else { @@ -1267,6 +1269,7 @@ impl Conn { } } } + fml_network_version = Some(forge_data.get("fmlNetworkVersion").unwrap().as_i64().unwrap()); } Ok(( @@ -1301,6 +1304,7 @@ impl Conn { .and_then(Value::as_str) .map(|v| v.to_owned()), forge_mods, + fml_network_version, }, ping, )) @@ -1352,6 +1356,7 @@ pub struct Status { pub description: format::Component, pub favicon: Option, pub forge_mods: Vec, + pub fml_network_version: Option, } #[derive(Debug)] diff --git a/src/main.rs b/src/main.rs index fba2f41f..877294d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -91,7 +91,7 @@ pub struct Game { impl Game { pub fn connect_to(&mut self, address: &str) { - let (protocol_version, forge_mods) = + let (protocol_version, forge_mods, fml_network_version) = match protocol::Conn::new(&address, self.default_protocol_version) .and_then(|conn| conn.do_status()) { @@ -100,14 +100,14 @@ impl Game { "Detected server protocol version {}", res.0.version.protocol ); - (res.0.version.protocol, res.0.forge_mods) + (res.0.version.protocol, res.0.forge_mods, res.0.fml_network_version) } Err(err) => { warn!( "Error pinging server {} to get protocol version: {:?}, defaulting to {}", address, err, self.default_protocol_version ); - (self.default_protocol_version, vec![]) + (self.default_protocol_version, vec![], None) } }; @@ -127,6 +127,7 @@ impl Game { &address, protocol_version, forge_mods, + fml_network_version, )) .unwrap(); }); diff --git a/src/server/mod.rs b/src/server/mod.rs index 2f4018af..e855c2af 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -110,14 +110,17 @@ impl Server { address: &str, protocol_version: i32, forge_mods: Vec, + fml_network_version: Option, ) -> Result { let mut conn = protocol::Conn::new(address, protocol_version)?; - let tag = if !forge_mods.is_empty() { - "\0FML\0" - } else { - "" + let tag = match fml_network_version { + Some(1) => "\0FML\0", + Some(2) => "\0FML2\0", + None => "", + _ => panic!("unsupported FML network version: {:?}", fml_network_version), }; + let host = conn.host.clone() + tag; let port = conn.port; conn.write_packet(protocol::packet::handshake::serverbound::Handshake { From 20cc6e12c1acec3967e2f5c893eae34fceb94475 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Thu, 21 Jan 2021 18:54:28 -0800 Subject: [PATCH 03/18] cargo fmt --- protocol/src/protocol/mod.rs | 8 +++++++- src/main.rs | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 8b6cd636..1e36c1c8 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1269,7 +1269,13 @@ impl Conn { } } } - fml_network_version = Some(forge_data.get("fmlNetworkVersion").unwrap().as_i64().unwrap()); + fml_network_version = Some( + forge_data + .get("fmlNetworkVersion") + .unwrap() + .as_i64() + .unwrap(), + ); } Ok(( diff --git a/src/main.rs b/src/main.rs index 877294d9..115de2e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -100,7 +100,11 @@ impl Game { "Detected server protocol version {}", res.0.version.protocol ); - (res.0.version.protocol, res.0.forge_mods, res.0.fml_network_version) + ( + res.0.version.protocol, + res.0.forge_mods, + res.0.fml_network_version, + ) } Err(err) => { warn!( From 167483c7824302ff1f16a5ff2f68da3348bea2f1 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Fri, 22 Jan 2021 17:43:16 -0800 Subject: [PATCH 04/18] protocol: factor out read_raw_packet_from() --- protocol/src/protocol/mod.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 1e36c1c8..41530250 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1102,14 +1102,19 @@ impl Conn { Result::Ok(()) } - pub fn read_packet(&mut self) -> Result { - let len = VarInt::read_from(self)?.0 as usize; + #[allow(clippy::type_complexity)] + pub fn read_raw_packet_from( + buf: &mut R, + compression_threshold: i32, + network_debug: bool, + ) -> Result<(i32, Box>>), Error> { + let len = VarInt::read_from(buf)?.0 as usize; let mut ibuf = vec![0; len]; - self.read_exact(&mut ibuf)?; + buf.read_exact(&mut ibuf)?; let mut buf = io::Cursor::new(ibuf); - if self.compression_threshold >= 0 { + if compression_threshold >= 0 { let uncompressed_size = VarInt::read_from(&mut buf)?.0; if uncompressed_size != 0 { let mut new = Vec::with_capacity(uncompressed_size as usize); @@ -1117,10 +1122,10 @@ impl Conn { let mut reader = ZlibDecoder::new(buf); reader.read_to_end(&mut new)?; } - if is_network_debug() { + if network_debug { debug!( "Decompressed threshold={} len={} uncompressed_size={} to {} bytes", - self.compression_threshold, + compression_threshold, len, uncompressed_size, new.len() @@ -1131,6 +1136,14 @@ impl Conn { } let id = VarInt::read_from(&mut buf)?.0; + Ok((id, Box::new(buf))) + } + + pub fn read_packet(&mut self) -> Result { + let compression_threshold = self.compression_threshold; + let (id, mut buf) = + Conn::read_raw_packet_from(self, compression_threshold, is_network_debug())?; + let dir = match self.direction { Direction::Clientbound => Direction::Serverbound, Direction::Serverbound => Direction::Clientbound, From 13e4fccade2b0eeb5ec8155f5743eae61d633043 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Fri, 22 Jan 2021 18:00:02 -0800 Subject: [PATCH 05/18] server: begin parsing fml:loginwrapper inner packets --- protocol/src/protocol/mod.rs | 8 +++----- src/server/mod.rs | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 41530250..0b9ffd15 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1036,7 +1036,7 @@ pub struct Conn { cipher: Option, - compression_threshold: i32, + pub compression_threshold: i32, } impl Conn { @@ -1106,7 +1106,6 @@ impl Conn { pub fn read_raw_packet_from( buf: &mut R, compression_threshold: i32, - network_debug: bool, ) -> Result<(i32, Box>>), Error> { let len = VarInt::read_from(buf)?.0 as usize; let mut ibuf = vec![0; len]; @@ -1122,7 +1121,7 @@ impl Conn { let mut reader = ZlibDecoder::new(buf); reader.read_to_end(&mut new)?; } - if network_debug { + if is_network_debug() { debug!( "Decompressed threshold={} len={} uncompressed_size={} to {} bytes", compression_threshold, @@ -1141,8 +1140,7 @@ impl Conn { pub fn read_packet(&mut self) -> Result { let compression_threshold = self.compression_threshold; - let (id, mut buf) = - Conn::read_raw_packet_from(self, compression_threshold, is_network_debug())?; + let (id, mut buf) = Conn::read_raw_packet_from(self, compression_threshold)?; let dir = match self.direction { Direction::Clientbound => Direction::Serverbound, diff --git a/src/server/mod.rs b/src/server/mod.rs index e855c2af..bc515e08 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -170,7 +170,6 @@ impl Server { Some(rx), )); } - // TODO: avoid duplication protocol::packet::Packet::LoginSuccess_UUID(val) => { warn!("Server is running in offline mode"); debug!("Login: {} {:?}", val.username, val.uuid); @@ -191,7 +190,7 @@ impl Server { protocol::packet::Packet::LoginDisconnect(val) => { return Err(protocol::Error::Disconnect(val.reason)) } - val => return Err(protocol::Error::Err(format!("Wrong packet: {:?}", val))), + val => return Err(protocol::Error::Err(format!("Wrong packet 1: {:?}", val))), }; } @@ -228,6 +227,7 @@ impl Server { write.enable_encyption(&shared, false); let uuid; + let compression_threshold = read.compression_threshold; loop { match read.read_packet()? { protocol::packet::Packet::SetInitialCompression(val) => { @@ -251,7 +251,19 @@ impl Server { protocol::packet::Packet::LoginDisconnect(val) => { return Err(protocol::Error::Disconnect(val.reason)) } - val => return Err(protocol::Error::Err(format!("Wrong packet: {:?}", val))), + protocol::packet::Packet::LoginPluginRequest(val) => match val.channel.as_ref() { + "fml:loginwrapper" => { + println!("fml:loginwrapper packet: message_id={:?}, channel={:?}, data={:?} bytes", val.message_id, val.channel, val.data.len()); + let (id, data) = protocol::Conn::read_raw_packet_from( + &mut std::io::Cursor::new(val.data), + compression_threshold, + )?; + println!("inner packet id = {:?}, data = {:?} bytes", id, data); + // TODO: handle inner packets + } + _ => panic!("unsupported LoginPluginRequest channel: {:?}", val.channel), + }, + val => return Err(protocol::Error::Err(format!("Wrong packet 2: {:?}", val))), } } From 39f5cc8da850ca3f39f297fa0c0c4dd1dd7b365b Mon Sep 17 00:00:00 2001 From: ice_iix Date: Fri, 22 Jan 2021 18:19:12 -0800 Subject: [PATCH 06/18] Get inner packet channel --- src/server/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index bc515e08..fbbca13f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -253,9 +253,13 @@ impl Server { } protocol::packet::Packet::LoginPluginRequest(val) => match val.channel.as_ref() { "fml:loginwrapper" => { - println!("fml:loginwrapper packet: message_id={:?}, channel={:?}, data={:?} bytes", val.message_id, val.channel, val.data.len()); + debug!("fml:loginwrapper packet: message_id={:?}, channel={:?}, data={:?} bytes", val.message_id, val.channel, val.data); + let mut cursor = std::io::Cursor::new(val.data); + let channel: String = protocol::Serializable::read_from(&mut cursor)?; + debug!("fml:loginwrapper inner channel = {:?}", channel); // fml:handshake + let (id, data) = protocol::Conn::read_raw_packet_from( - &mut std::io::Cursor::new(val.data), + &mut cursor, compression_threshold, )?; println!("inner packet id = {:?}, data = {:?} bytes", id, data); From 07fb3e965a192e604617d88ffa1ed3c7a5c43971 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Fri, 22 Jan 2021 19:08:03 -0800 Subject: [PATCH 07/18] protocol/forge: add fml2 handshake packets --- protocol/src/protocol/forge.rs | 115 +++++++++++++++++++++++++++++++++ src/server/mod.rs | 18 ++++-- 2 files changed, 128 insertions(+), 5 deletions(-) diff --git a/protocol/src/protocol/forge.rs b/protocol/src/protocol/forge.rs index 4dd92531..249f6114 100644 --- a/protocol/src/protocol/forge.rs +++ b/protocol/src/protocol/forge.rs @@ -191,3 +191,118 @@ impl Serializable for FmlHs { } } } + +pub mod fml2 { + // https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29 + use super::*; + + #[derive(Clone, Default, Debug)] + pub struct Channel { + pub name: String, + pub version: String, + } + + impl Serializable for Channel { + fn read_from(buf: &mut R) -> Result { + Ok(Channel { + name: Serializable::read_from(buf)?, + version: Serializable::read_from(buf)?, + }) + } + + fn write_to(&self, buf: &mut W) -> Result<(), Error> { + self.name.write_to(buf)?; + self.version.write_to(buf) + } + } + + #[derive(Clone, Default, Debug)] + pub struct Registry { + pub name: String, + pub marker: String, + } + + impl Serializable for Registry { + fn read_from(_buf: &mut R) -> Result { + unimplemented!() + } + + fn write_to(&self, buf: &mut W) -> Result<(), Error> { + self.name.write_to(buf)?; + self.marker.write_to(buf) + } + } + + #[derive(Debug)] + pub enum FmlHandshake { + ModList { + mod_names: LenPrefixed, + channels: LenPrefixed, + registries: LenPrefixed, + }, + + ModListReply { + mod_names: LenPrefixed, + channels: LenPrefixed, + registries: LenPrefixed, + }, + + ServerRegistry { + name: String, + snapshot_present: bool, + snapshot: Vec, + }, + + ConfigurationData { + filename: String, + contents: Vec, + }, + + Acknowledgement, + } + + impl FmlHandshake { + pub fn packet_by_id(id: i32, buf: &mut R) -> Result { + Ok(match id { + 1 => FmlHandshake::ModList { + mod_names: Serializable::read_from(buf)?, + channels: Serializable::read_from(buf)?, + registries: Serializable::read_from(buf)?, + }, + 3 => FmlHandshake::ServerRegistry { + name: Serializable::read_from(buf)?, + snapshot_present: Serializable::read_from(buf)?, + snapshot: Serializable::read_from(buf)?, + }, + 4 => FmlHandshake::ConfigurationData { + filename: Serializable::read_from(buf)?, + contents: Serializable::read_from(buf)?, + }, + _ => unimplemented!(), + }) + } + } + + impl Serializable for FmlHandshake { + fn read_from(_buf: &mut R) -> Result { + unimplemented!() + } + + fn write_to(&self, buf: &mut W) -> Result<(), Error> { + match self { + FmlHandshake::ModListReply { + mod_names, + channels, + registries, + } => { + VarInt(2).write_to(buf)?; + mod_names.write_to(buf)?; + channels.write_to(buf)?; + registries.write_to(buf) + } + FmlHandshake::Acknowledgement => VarInt(99).write_to(buf), + _ => unimplemented!(), + } + } + } +} diff --git a/src/server/mod.rs b/src/server/mod.rs index fbbca13f..659773cf 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -253,17 +253,25 @@ impl Server { } protocol::packet::Packet::LoginPluginRequest(val) => match val.channel.as_ref() { "fml:loginwrapper" => { - debug!("fml:loginwrapper packet: message_id={:?}, channel={:?}, data={:?} bytes", val.message_id, val.channel, val.data); let mut cursor = std::io::Cursor::new(val.data); let channel: String = protocol::Serializable::read_from(&mut cursor)?; - debug!("fml:loginwrapper inner channel = {:?}", channel); // fml:handshake - let (id, data) = protocol::Conn::read_raw_packet_from( + let (id, mut data) = protocol::Conn::read_raw_packet_from( &mut cursor, compression_threshold, )?; - println!("inner packet id = {:?}, data = {:?} bytes", id, data); - // TODO: handle inner packets + + match channel.as_ref() { + "fml:handshake" => { + let packet = + forge::fml2::FmlHandshake::packet_by_id(id, &mut data)?; + println!("packet = {:?}", packet); + } + _ => panic!( + "unknown LoginPluginRequest fml:loginwrapper channel: {:?}", + channel + ), + } } _ => panic!("unsupported LoginPluginRequest channel: {:?}", val.channel), }, From f2ffebdd8953140ea1e0aa1f12f5148fe5308526 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Fri, 22 Jan 2021 19:18:44 -0800 Subject: [PATCH 08/18] server: match fml2 handshake message packets --- src/server/mod.rs | 74 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 659773cf..549926af 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -251,30 +251,62 @@ impl Server { protocol::packet::Packet::LoginDisconnect(val) => { return Err(protocol::Error::Disconnect(val.reason)) } - protocol::packet::Packet::LoginPluginRequest(val) => match val.channel.as_ref() { - "fml:loginwrapper" => { - let mut cursor = std::io::Cursor::new(val.data); - let channel: String = protocol::Serializable::read_from(&mut cursor)?; - - let (id, mut data) = protocol::Conn::read_raw_packet_from( - &mut cursor, - compression_threshold, - )?; - - match channel.as_ref() { - "fml:handshake" => { - let packet = - forge::fml2::FmlHandshake::packet_by_id(id, &mut data)?; - println!("packet = {:?}", packet); + protocol::packet::Packet::LoginPluginRequest(val) => { + match val.channel.as_ref() { + "fml:loginwrapper" => { + let mut cursor = std::io::Cursor::new(val.data); + let channel: String = protocol::Serializable::read_from(&mut cursor)?; + + let (id, mut data) = protocol::Conn::read_raw_packet_from( + &mut cursor, + compression_threshold, + )?; + + match channel.as_ref() { + "fml:handshake" => { + let packet = + forge::fml2::FmlHandshake::packet_by_id(id, &mut data)?; + use forge::fml2::FmlHandshake::*; + match packet { + ModList { + mod_names, + channels, + registries, + } => { + println!("ModList mod_names={:?} channels={:?} registries={:?}", mod_names, channels, registries); + // TODO: send ModListReply + } + ServerRegistry { + name, + snapshot_present, + snapshot: _snapshot, + } => { + println!( + "ServerRegistry {:?} snapshot_present {:?}", + name, snapshot_present + ); + // TODO: send Acknowledgement + } + ConfigurationData { filename, contents } => { + println!( + "ConfigurationData filename={:?} contents={}", + filename, + String::from_utf8_lossy(&contents) + ); + // TODO: send Acknowledgement + } + _ => unimplemented!(), + } + } + _ => panic!( + "unknown LoginPluginRequest fml:loginwrapper channel: {:?}", + channel + ), } - _ => panic!( - "unknown LoginPluginRequest fml:loginwrapper channel: {:?}", - channel - ), } + _ => panic!("unsupported LoginPluginRequest channel: {:?}", val.channel), } - _ => panic!("unsupported LoginPluginRequest channel: {:?}", val.channel), - }, + } val => return Err(protocol::Error::Err(format!("Wrong packet 2: {:?}", val))), } } From c306d03e72d9b3b352012a58a63c4ee2211a54c0 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Fri, 22 Jan 2021 20:06:31 -0800 Subject: [PATCH 09/18] Send client-side packets --- protocol/src/protocol/forge.rs | 9 ++++++--- src/server/mod.rs | 26 ++++++++++++++------------ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/protocol/src/protocol/forge.rs b/protocol/src/protocol/forge.rs index 249f6114..8c8e5352 100644 --- a/protocol/src/protocol/forge.rs +++ b/protocol/src/protocol/forge.rs @@ -223,8 +223,11 @@ pub mod fml2 { } impl Serializable for Registry { - fn read_from(_buf: &mut R) -> Result { - unimplemented!() + fn read_from(buf: &mut R) -> Result { + Ok(Registry { + name: Serializable::read_from(buf)?, + marker: "".to_string() // not in ModList + }) } fn write_to(&self, buf: &mut W) -> Result<(), Error> { @@ -238,7 +241,7 @@ pub mod fml2 { ModList { mod_names: LenPrefixed, channels: LenPrefixed, - registries: LenPrefixed, + registries: LenPrefixed, }, ModListReply { diff --git a/src/server/mod.rs b/src/server/mod.rs index 549926af..ab517043 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -25,7 +25,7 @@ use crate::types::Gamemode; use crate::world; use crate::world::block; use cgmath::prelude::*; -use log::{debug, error, warn}; +use log::{debug, error, warn, info}; use rand::{self, Rng}; use std::collections::HashMap; use std::hash::BuildHasherDefault; @@ -267,33 +267,35 @@ impl Server { let packet = forge::fml2::FmlHandshake::packet_by_id(id, &mut data)?; use forge::fml2::FmlHandshake::*; + use protocol::Serializable; match packet { ModList { mod_names, channels, registries, } => { - println!("ModList mod_names={:?} channels={:?} registries={:?}", mod_names, channels, registries); - // TODO: send ModListReply + info!("ModList mod_names={:?} channels={:?} registries={:?}", mod_names, channels, registries); + ModListReply { + mod_names, + channels, + registries, + }.write_to(&mut write)? } ServerRegistry { name, - snapshot_present, - snapshot: _snapshot, + snapshot_present: _, + snapshot: _, } => { - println!( - "ServerRegistry {:?} snapshot_present {:?}", - name, snapshot_present - ); - // TODO: send Acknowledgement + info!("ServerRegistry {:?}", name); + Acknowledgement.write_to(&mut write)? } ConfigurationData { filename, contents } => { - println!( + info!( "ConfigurationData filename={:?} contents={}", filename, String::from_utf8_lossy(&contents) ); - // TODO: send Acknowledgement + Acknowledgement.write_to(&mut write)? } _ => unimplemented!(), } From a29b6b2c34dde1d9056574111016a16888724ef3 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 08:44:17 -0800 Subject: [PATCH 10/18] cargo fmt --- src/server/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index ab517043..9479022e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -25,7 +25,7 @@ use crate::types::Gamemode; use crate::world; use crate::world::block; use cgmath::prelude::*; -use log::{debug, error, warn, info}; +use log::{debug, error, info, warn}; use rand::{self, Rng}; use std::collections::HashMap; use std::hash::BuildHasherDefault; @@ -279,7 +279,8 @@ impl Server { mod_names, channels, registries, - }.write_to(&mut write)? + } + .write_to(&mut write)? } ServerRegistry { name, From 6ae092b16cd38f4187d46388a734bacf85c71e34 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 09:16:42 -0800 Subject: [PATCH 11/18] protocol: move plugin message writing from Server to Conn; add write_fml2_handshake_plugin_message --- protocol/src/protocol/forge.rs | 2 +- protocol/src/protocol/mod.rs | 42 ++++++++++++++++++++++++++- src/server/mod.rs | 52 +++++++++++++--------------------- 3 files changed, 62 insertions(+), 34 deletions(-) diff --git a/protocol/src/protocol/forge.rs b/protocol/src/protocol/forge.rs index 8c8e5352..254a45cb 100644 --- a/protocol/src/protocol/forge.rs +++ b/protocol/src/protocol/forge.rs @@ -226,7 +226,7 @@ pub mod fml2 { fn read_from(buf: &mut R) -> Result { Ok(Registry { name: Serializable::read_from(buf)?, - marker: "".to_string() // not in ModList + marker: "".to_string(), // not in ModList }) } diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 0b9ffd15..2153d293 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1099,7 +1099,47 @@ impl Conn { } self.write_all(&buf)?; - Result::Ok(()) + Ok(()) + } + + pub fn write_plugin_message(&mut self, channel: &str, data: &[u8]) -> Result<(), Error> { + if is_network_debug() { + debug!( + "Sending plugin message: channel={}, data={:?}", + channel, data + ); + } + if self.protocol_version >= 47 { + self.write_packet(packet::play::serverbound::PluginMessageServerbound { + channel: channel.to_string(), + data: data.to_vec(), + })?; + } else { + self.write_packet(packet::play::serverbound::PluginMessageServerbound_i16 { + channel: channel.to_string(), + data: LenPrefixedBytes::::new(data.to_vec()), + })?; + } + + Ok(()) + } + + pub fn write_fmlhs_plugin_message(&mut self, msg: &forge::FmlHs) -> Result<(), Error> { + let mut buf: Vec = vec![]; + msg.write_to(&mut buf).unwrap(); + + self.write_plugin_message("FML|HS", &buf) + } + + pub fn write_fml2_handshake_plugin_message( + &mut self, + msg: &forge::fml2::FmlHandshake, + ) -> Result<(), Error> { + let mut buf: Vec = vec![]; + msg.write_to(&mut buf).unwrap(); + // TODO: double-wrap + + self.write_plugin_message("fml:loginwrapper", &buf) } #[allow(clippy::type_complexity)] diff --git a/src/server/mod.rs b/src/server/mod.rs index 9479022e..7beb8cc5 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -267,7 +267,6 @@ impl Server { let packet = forge::fml2::FmlHandshake::packet_by_id(id, &mut data)?; use forge::fml2::FmlHandshake::*; - use protocol::Serializable; match packet { ModList { mod_names, @@ -275,12 +274,13 @@ impl Server { registries, } => { info!("ModList mod_names={:?} channels={:?} registries={:?}", mod_names, channels, registries); - ModListReply { - mod_names, - channels, - registries, - } - .write_to(&mut write)? + write.write_fml2_handshake_plugin_message( + &ModListReply { + mod_names, + channels, + registries, + }, + )?; } ServerRegistry { name, @@ -288,7 +288,9 @@ impl Server { snapshot: _, } => { info!("ServerRegistry {:?}", name); - Acknowledgement.write_to(&mut write)? + write.write_fml2_handshake_plugin_message( + &Acknowledgement, + )?; } ConfigurationData { filename, contents } => { info!( @@ -296,7 +298,9 @@ impl Server { filename, String::from_utf8_lossy(&contents) ); - Acknowledgement.write_to(&mut write)? + write.write_fml2_handshake_plugin_message( + &Acknowledgement, + )?; } _ => unimplemented!(), } @@ -1008,33 +1012,17 @@ impl Server { } } + // TODO: remove wrappers and directly call on Conn fn write_fmlhs_plugin_message(&mut self, msg: &forge::FmlHs) { - use crate::protocol::Serializable; - - let mut buf: Vec = vec![]; - msg.write_to(&mut buf).unwrap(); - - self.write_plugin_message("FML|HS", &buf); + let _ = self.conn.as_mut().unwrap().write_fmlhs_plugin_message(msg); // TODO handle errors } fn write_plugin_message(&mut self, channel: &str, data: &[u8]) { - if protocol::is_network_debug() { - debug!( - "Sending plugin message: channel={}, data={:?}", - channel, data - ); - } - if self.protocol_version >= 47 { - self.write_packet(packet::play::serverbound::PluginMessageServerbound { - channel: channel.to_string(), - data: data.to_vec(), - }); - } else { - self.write_packet(packet::play::serverbound::PluginMessageServerbound_i16 { - channel: channel.to_string(), - data: crate::protocol::LenPrefixedBytes::::new(data.to_vec()), - }); - } + let _ = self + .conn + .as_mut() + .unwrap() + .write_plugin_message(channel, data); // TODO handle errors } fn on_game_join_worldnames_ishard( From 09e423dd1fdac24e59a54d5a76340eb7f984e47f Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 09:27:42 -0800 Subject: [PATCH 12/18] protocol: double-wrapped write_fml2_handshake_plugin_message --- protocol/src/protocol/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 2153d293..bbbfdd39 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1126,7 +1126,7 @@ impl Conn { pub fn write_fmlhs_plugin_message(&mut self, msg: &forge::FmlHs) -> Result<(), Error> { let mut buf: Vec = vec![]; - msg.write_to(&mut buf).unwrap(); + msg.write_to(&mut buf)?; self.write_plugin_message("FML|HS", &buf) } @@ -1135,11 +1135,16 @@ impl Conn { &mut self, msg: &forge::fml2::FmlHandshake, ) -> Result<(), Error> { - let mut buf: Vec = vec![]; - msg.write_to(&mut buf).unwrap(); - // TODO: double-wrap + let mut inner_buf: Vec = vec![]; + msg.write_to(&mut inner_buf)?; + + let mut outer_buf: Vec = vec![]; + "fml:handshake".to_string().write_to(&mut outer_buf)?; + // TODO: write_packet, compression? + VarInt(inner_buf.len() as i32).write_to(&mut outer_buf)?; + inner_buf.write_to(&mut outer_buf)?; - self.write_plugin_message("fml:loginwrapper", &buf) + self.write_plugin_message("fml:loginwrapper", &outer_buf) } #[allow(clippy::type_complexity)] From a44d693e1f3efec6b0dea1a92df5910dc9026b07 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 11:30:52 -0800 Subject: [PATCH 13/18] Send login::LoginPluginResponse, not play::PluginMessageServerbound --- protocol/src/protocol/mod.rs | 35 +++++++++++++++++++++++++---------- src/server/mod.rs | 19 +++++++++++-------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index bbbfdd39..392de1bc 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -971,7 +971,7 @@ pub enum Direction { /// The protocol has multiple 'sub-protocols' or states which control which /// packet an id points to. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum State { Handshaking, Play, @@ -1109,6 +1109,7 @@ impl Conn { channel, data ); } + debug_assert!(self.state == State::Play); if self.protocol_version >= 47 { self.write_packet(packet::play::serverbound::PluginMessageServerbound { channel: channel.to_string(), @@ -1131,20 +1132,33 @@ impl Conn { self.write_plugin_message("FML|HS", &buf) } + pub fn write_login_plugin_response(&mut self, message_id: VarInt, successful: bool, data: &[u8]) -> Result<(), Error> { + debug_assert!(self.state == State::Login); + self.write_packet(packet::login::serverbound::LoginPluginResponse { + message_id, + successful, + data: data.to_vec() + }) + } + pub fn write_fml2_handshake_plugin_message( &mut self, - msg: &forge::fml2::FmlHandshake, + message_id: VarInt, + msg: Option<&forge::fml2::FmlHandshake>, ) -> Result<(), Error> { - let mut inner_buf: Vec = vec![]; - msg.write_to(&mut inner_buf)?; + if let Some(msg) = msg { + let mut inner_buf: Vec = vec![]; + msg.write_to(&mut inner_buf)?; - let mut outer_buf: Vec = vec![]; - "fml:handshake".to_string().write_to(&mut outer_buf)?; - // TODO: write_packet, compression? - VarInt(inner_buf.len() as i32).write_to(&mut outer_buf)?; - inner_buf.write_to(&mut outer_buf)?; + let mut outer_buf: Vec = vec![]; + "fml:handshake".to_string().write_to(&mut outer_buf)?; + VarInt(inner_buf.len() as i32).write_to(&mut outer_buf)?; + inner_buf.write_to(&mut outer_buf)?; - self.write_plugin_message("fml:loginwrapper", &outer_buf) + self.write_login_plugin_response(message_id, true, &inner_buf) + } else { + unimplemented!() // successful: false, no payload + } } #[allow(clippy::type_complexity)] @@ -1232,6 +1246,7 @@ impl Conn { } pub fn set_compresssion(&mut self, threshold: i32) { + println!("set_compression {:?}", threshold); self.compression_threshold = threshold; } diff --git a/src/server/mod.rs b/src/server/mod.rs index 7beb8cc5..3fbee91a 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -251,10 +251,10 @@ impl Server { protocol::packet::Packet::LoginDisconnect(val) => { return Err(protocol::Error::Disconnect(val.reason)) } - protocol::packet::Packet::LoginPluginRequest(val) => { - match val.channel.as_ref() { + protocol::packet::Packet::LoginPluginRequest(req) => { + match req.channel.as_ref() { "fml:loginwrapper" => { - let mut cursor = std::io::Cursor::new(val.data); + let mut cursor = std::io::Cursor::new(req.data); let channel: String = protocol::Serializable::read_from(&mut cursor)?; let (id, mut data) = protocol::Conn::read_raw_packet_from( @@ -275,11 +275,12 @@ impl Server { } => { info!("ModList mod_names={:?} channels={:?} registries={:?}", mod_names, channels, registries); write.write_fml2_handshake_plugin_message( - &ModListReply { + req.message_id, + Some(&ModListReply { mod_names, channels, registries, - }, + }), )?; } ServerRegistry { @@ -289,7 +290,8 @@ impl Server { } => { info!("ServerRegistry {:?}", name); write.write_fml2_handshake_plugin_message( - &Acknowledgement, + req.message_id, + Some(&Acknowledgement), )?; } ConfigurationData { filename, contents } => { @@ -299,7 +301,8 @@ impl Server { String::from_utf8_lossy(&contents) ); write.write_fml2_handshake_plugin_message( - &Acknowledgement, + req.message_id, + Some(&Acknowledgement), )?; } _ => unimplemented!(), @@ -311,7 +314,7 @@ impl Server { ), } } - _ => panic!("unsupported LoginPluginRequest channel: {:?}", val.channel), + _ => panic!("unsupported LoginPluginRequest channel: {:?}", req.channel), } } val => return Err(protocol::Error::Err(format!("Wrong packet 2: {:?}", val))), From 7695863a3b0b97e4a7e79d9bd8b8cd66d2aaeab9 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 11:47:22 -0800 Subject: [PATCH 14/18] protocol: log write_login_plugin_response() messages when network debugging --- protocol/src/protocol/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 392de1bc..83578644 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1133,6 +1133,14 @@ impl Conn { } pub fn write_login_plugin_response(&mut self, message_id: VarInt, successful: bool, data: &[u8]) -> Result<(), Error> { + if is_network_debug() { + debug!( + "Sending login plugin message: message_id={:?}, successful={:?}, data={:?}", + message_id, + successful, + data, + ); + } debug_assert!(self.state == State::Login); self.write_packet(packet::login::serverbound::LoginPluginResponse { message_id, From 416240f72081bbcd83a1d9f6eb7cf97d8e592933 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 11:51:15 -0800 Subject: [PATCH 15/18] Fix writing outer packet --- protocol/src/protocol/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 83578644..f771e909 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1163,7 +1163,7 @@ impl Conn { VarInt(inner_buf.len() as i32).write_to(&mut outer_buf)?; inner_buf.write_to(&mut outer_buf)?; - self.write_login_plugin_response(message_id, true, &inner_buf) + self.write_login_plugin_response(message_id, true, &outer_buf) } else { unimplemented!() // successful: false, no payload } From 3728b5cfe0dabb31706c83323b44583ff714cfcd Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 12:08:39 -0800 Subject: [PATCH 16/18] protocol: CommandNode: add forge:modid, forge:enum --- protocol/src/protocol/packet.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/protocol/src/protocol/packet.rs b/protocol/src/protocol/packet.rs index a7527cad..aee65a8f 100644 --- a/protocol/src/protocol/packet.rs +++ b/protocol/src/protocol/packet.rs @@ -3135,6 +3135,12 @@ pub enum CommandProperty { EntitySummon, Dimension, UUID, + ForgeModId { + modid: String, + }, + ForgeEnum { + cls: String, + } } impl Serializable for CommandNode { @@ -3264,6 +3270,12 @@ impl Serializable for CommandNode { "minecraft:entity_summon" => CommandProperty::EntitySummon, "minecraft:dimension" => CommandProperty::Dimension, "minecraft:uuid" => CommandProperty::UUID, + "forge:modid" => CommandProperty::ForgeModId { + modid: Serializable::read_from(buf)?, + }, + "forge:enum" => CommandProperty::ForgeEnum { + cls: Serializable::read_from(buf)?, + }, _ => panic!("unsupported command node parser {}", parse), }) } else { From ceefeb2e117ab4a1488904e8c956fdcb51e8940d Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 12:18:08 -0800 Subject: [PATCH 17/18] Fix forge:modid CommandNode --- protocol/src/protocol/packet.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/protocol/src/protocol/packet.rs b/protocol/src/protocol/packet.rs index aee65a8f..d2a56ae6 100644 --- a/protocol/src/protocol/packet.rs +++ b/protocol/src/protocol/packet.rs @@ -3135,9 +3135,7 @@ pub enum CommandProperty { EntitySummon, Dimension, UUID, - ForgeModId { - modid: String, - }, + ForgeModId, ForgeEnum { cls: String, } @@ -3270,9 +3268,7 @@ impl Serializable for CommandNode { "minecraft:entity_summon" => CommandProperty::EntitySummon, "minecraft:dimension" => CommandProperty::Dimension, "minecraft:uuid" => CommandProperty::UUID, - "forge:modid" => CommandProperty::ForgeModId { - modid: Serializable::read_from(buf)?, - }, + "forge:modid" => CommandProperty::ForgeModId, "forge:enum" => CommandProperty::ForgeEnum { cls: Serializable::read_from(buf)?, }, From db69e84dd713d7fab70418a9a9827e9810b3a1e9 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sat, 23 Jan 2021 13:22:22 -0800 Subject: [PATCH 18/18] Update readme, cleanup, format --- README.md | 2 +- protocol/src/protocol/mod.rs | 14 ++++++++------ protocol/src/protocol/packet.rs | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 951e196d..dd28ded0 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ development is not in lock-step with the server version. The level of support varies, but the goal is to support major versions from 1.7.10 up to the current latest major version. Occasionally, snapshots are also supported. -Forge servers are currently supported on 1.7.10 - 1.12.2. +Forge servers are supported on 1.7.10 - 1.12.2 (FML) and 1.13.2 - 1.16.5 (FML2). Support for older protocols will _not_ be dropped as newer protocols are added. diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index f771e909..eca606fc 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -1132,20 +1132,23 @@ impl Conn { self.write_plugin_message("FML|HS", &buf) } - pub fn write_login_plugin_response(&mut self, message_id: VarInt, successful: bool, data: &[u8]) -> Result<(), Error> { + pub fn write_login_plugin_response( + &mut self, + message_id: VarInt, + successful: bool, + data: &[u8], + ) -> Result<(), Error> { if is_network_debug() { debug!( "Sending login plugin message: message_id={:?}, successful={:?}, data={:?}", - message_id, - successful, - data, + message_id, successful, data, ); } debug_assert!(self.state == State::Login); self.write_packet(packet::login::serverbound::LoginPluginResponse { message_id, successful, - data: data.to_vec() + data: data.to_vec(), }) } @@ -1254,7 +1257,6 @@ impl Conn { } pub fn set_compresssion(&mut self, threshold: i32) { - println!("set_compression {:?}", threshold); self.compression_threshold = threshold; } diff --git a/protocol/src/protocol/packet.rs b/protocol/src/protocol/packet.rs index d2a56ae6..cbffa9f1 100644 --- a/protocol/src/protocol/packet.rs +++ b/protocol/src/protocol/packet.rs @@ -3138,7 +3138,7 @@ pub enum CommandProperty { ForgeModId, ForgeEnum { cls: String, - } + }, } impl Serializable for CommandNode {