Allows connecting to newer Forge servers, 1.13.2 to 1.16.5 at least, which use the FML2 handshake protocol: https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29 Tested with a modded 1.16.5 server Extends #88 #134 Forge FML (v1, for 1.7.10 - 1.12.2) * protocol: update Cargo.lock * protocol: send FML2 on fmlNetworkVersion: 2 * protocol: factor out read_raw_packet_from() * protocol: move plugin message writing from Server to Conn; add write_fml2_handshake_plugin_message * protocol: CommandNode: add forge:modid, forge:enum * forge: add fml2 handshake packets * server: handle fml:loginwrapper fml::handshake packets
This commit is contained in:
parent
1a257e2e90
commit
6b961622aa
|
@ -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
|
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.
|
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.
|
Support for older protocols will _not_ be dropped as newer protocols are added.
|
||||||
|
|
||||||
|
|
|
@ -840,9 +840,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.119"
|
version = "1.0.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3"
|
checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
|
|
|
@ -191,3 +191,121 @@ 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<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||||
|
Ok(Channel {
|
||||||
|
name: Serializable::read_from(buf)?,
|
||||||
|
version: Serializable::read_from(buf)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to<W: io::Write>(&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<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||||
|
Ok(Registry {
|
||||||
|
name: Serializable::read_from(buf)?,
|
||||||
|
marker: "".to_string(), // not in ModList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to<W: io::Write>(&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<VarInt, String>,
|
||||||
|
channels: LenPrefixed<VarInt, Channel>,
|
||||||
|
registries: LenPrefixed<VarInt, Registry>,
|
||||||
|
},
|
||||||
|
|
||||||
|
ModListReply {
|
||||||
|
mod_names: LenPrefixed<VarInt, String>,
|
||||||
|
channels: LenPrefixed<VarInt, Channel>,
|
||||||
|
registries: LenPrefixed<VarInt, Registry>,
|
||||||
|
},
|
||||||
|
|
||||||
|
ServerRegistry {
|
||||||
|
name: String,
|
||||||
|
snapshot_present: bool,
|
||||||
|
snapshot: Vec<u8>,
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigurationData {
|
||||||
|
filename: String,
|
||||||
|
contents: Vec<u8>,
|
||||||
|
},
|
||||||
|
|
||||||
|
Acknowledgement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FmlHandshake {
|
||||||
|
pub fn packet_by_id<R: io::Read>(id: i32, buf: &mut R) -> Result<Self, Error> {
|
||||||
|
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<R: io::Read>(_buf: &mut R) -> Result<Self, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to<W: io::Write>(&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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -971,7 +971,7 @@ pub enum Direction {
|
||||||
|
|
||||||
/// The protocol has multiple 'sub-protocols' or states which control which
|
/// The protocol has multiple 'sub-protocols' or states which control which
|
||||||
/// packet an id points to.
|
/// packet an id points to.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum State {
|
pub enum State {
|
||||||
Handshaking,
|
Handshaking,
|
||||||
Play,
|
Play,
|
||||||
|
@ -1036,7 +1036,7 @@ pub struct Conn {
|
||||||
|
|
||||||
cipher: Option<Aes128Cfb>,
|
cipher: Option<Aes128Cfb>,
|
||||||
|
|
||||||
compression_threshold: i32,
|
pub compression_threshold: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Conn {
|
impl Conn {
|
||||||
|
@ -1099,17 +1099,91 @@ impl Conn {
|
||||||
}
|
}
|
||||||
self.write_all(&buf)?;
|
self.write_all(&buf)?;
|
||||||
|
|
||||||
Result::Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_packet(&mut self) -> Result<packet::Packet, Error> {
|
pub fn write_plugin_message(&mut self, channel: &str, data: &[u8]) -> Result<(), Error> {
|
||||||
let len = VarInt::read_from(self)?.0 as usize;
|
if is_network_debug() {
|
||||||
|
debug!(
|
||||||
|
"Sending plugin message: channel={}, data={:?}",
|
||||||
|
channel, data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
debug_assert!(self.state == State::Play);
|
||||||
|
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::<VarShort>::new(data.to_vec()),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_fmlhs_plugin_message(&mut self, msg: &forge::FmlHs) -> Result<(), Error> {
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
msg.write_to(&mut buf)?;
|
||||||
|
|
||||||
|
self.write_plugin_message("FML|HS", &buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
successful,
|
||||||
|
data: data.to_vec(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_fml2_handshake_plugin_message(
|
||||||
|
&mut self,
|
||||||
|
message_id: VarInt,
|
||||||
|
msg: Option<&forge::fml2::FmlHandshake>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let Some(msg) = msg {
|
||||||
|
let mut inner_buf: Vec<u8> = vec![];
|
||||||
|
msg.write_to(&mut inner_buf)?;
|
||||||
|
|
||||||
|
let mut outer_buf: Vec<u8> = 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_login_plugin_response(message_id, true, &outer_buf)
|
||||||
|
} else {
|
||||||
|
unimplemented!() // successful: false, no payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn read_raw_packet_from<R: io::Read>(
|
||||||
|
buf: &mut R,
|
||||||
|
compression_threshold: i32,
|
||||||
|
) -> Result<(i32, Box<io::Cursor<Vec<u8>>>), Error> {
|
||||||
|
let len = VarInt::read_from(buf)?.0 as usize;
|
||||||
let mut ibuf = vec![0; len];
|
let mut ibuf = vec![0; len];
|
||||||
self.read_exact(&mut ibuf)?;
|
buf.read_exact(&mut ibuf)?;
|
||||||
|
|
||||||
let mut buf = io::Cursor::new(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;
|
let uncompressed_size = VarInt::read_from(&mut buf)?.0;
|
||||||
if uncompressed_size != 0 {
|
if uncompressed_size != 0 {
|
||||||
let mut new = Vec::with_capacity(uncompressed_size as usize);
|
let mut new = Vec::with_capacity(uncompressed_size as usize);
|
||||||
|
@ -1120,7 +1194,7 @@ impl Conn {
|
||||||
if is_network_debug() {
|
if is_network_debug() {
|
||||||
debug!(
|
debug!(
|
||||||
"Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
|
"Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
|
||||||
self.compression_threshold,
|
compression_threshold,
|
||||||
len,
|
len,
|
||||||
uncompressed_size,
|
uncompressed_size,
|
||||||
new.len()
|
new.len()
|
||||||
|
@ -1131,6 +1205,13 @@ impl Conn {
|
||||||
}
|
}
|
||||||
let id = VarInt::read_from(&mut buf)?.0;
|
let id = VarInt::read_from(&mut buf)?.0;
|
||||||
|
|
||||||
|
Ok((id, Box::new(buf)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_packet(&mut self) -> Result<packet::Packet, Error> {
|
||||||
|
let compression_threshold = self.compression_threshold;
|
||||||
|
let (id, mut buf) = Conn::read_raw_packet_from(self, compression_threshold)?;
|
||||||
|
|
||||||
let dir = match self.direction {
|
let dir = match self.direction {
|
||||||
Direction::Clientbound => Direction::Serverbound,
|
Direction::Clientbound => Direction::Serverbound,
|
||||||
Direction::Serverbound => Direction::Clientbound,
|
Direction::Serverbound => Direction::Clientbound,
|
||||||
|
@ -1224,6 +1305,7 @@ impl Conn {
|
||||||
|
|
||||||
// For modded servers, get the list of Forge mods installed
|
// For modded servers, get the list of Forge mods installed
|
||||||
let mut forge_mods: std::vec::Vec<crate::protocol::forge::ForgeMod> = vec![];
|
let mut forge_mods: std::vec::Vec<crate::protocol::forge::ForgeMod> = vec![];
|
||||||
|
let mut fml_network_version: Option<i64> = None;
|
||||||
if let Some(modinfo) = val.get("modinfo") {
|
if let Some(modinfo) = val.get("modinfo") {
|
||||||
if let Some(modinfo_type) = modinfo.get("type") {
|
if let Some(modinfo_type) = modinfo.get("type") {
|
||||||
if modinfo_type == "FML" {
|
if modinfo_type == "FML" {
|
||||||
|
@ -1240,6 +1322,7 @@ impl Conn {
|
||||||
.push(crate::protocol::forge::ForgeMod { modid, version });
|
.push(crate::protocol::forge::ForgeMod { modid, version });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fml_network_version = Some(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1267,6 +1350,13 @@ impl Conn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fml_network_version = Some(
|
||||||
|
forge_data
|
||||||
|
.get("fmlNetworkVersion")
|
||||||
|
.unwrap()
|
||||||
|
.as_i64()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -1301,6 +1391,7 @@ impl Conn {
|
||||||
.and_then(Value::as_str)
|
.and_then(Value::as_str)
|
||||||
.map(|v| v.to_owned()),
|
.map(|v| v.to_owned()),
|
||||||
forge_mods,
|
forge_mods,
|
||||||
|
fml_network_version,
|
||||||
},
|
},
|
||||||
ping,
|
ping,
|
||||||
))
|
))
|
||||||
|
@ -1352,6 +1443,7 @@ pub struct Status {
|
||||||
pub description: format::Component,
|
pub description: format::Component,
|
||||||
pub favicon: Option<String>,
|
pub favicon: Option<String>,
|
||||||
pub forge_mods: Vec<crate::protocol::forge::ForgeMod>,
|
pub forge_mods: Vec<crate::protocol::forge::ForgeMod>,
|
||||||
|
pub fml_network_version: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -3135,6 +3135,10 @@ pub enum CommandProperty {
|
||||||
EntitySummon,
|
EntitySummon,
|
||||||
Dimension,
|
Dimension,
|
||||||
UUID,
|
UUID,
|
||||||
|
ForgeModId,
|
||||||
|
ForgeEnum {
|
||||||
|
cls: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serializable for CommandNode {
|
impl Serializable for CommandNode {
|
||||||
|
@ -3264,6 +3268,10 @@ impl Serializable for CommandNode {
|
||||||
"minecraft:entity_summon" => CommandProperty::EntitySummon,
|
"minecraft:entity_summon" => CommandProperty::EntitySummon,
|
||||||
"minecraft:dimension" => CommandProperty::Dimension,
|
"minecraft:dimension" => CommandProperty::Dimension,
|
||||||
"minecraft:uuid" => CommandProperty::UUID,
|
"minecraft:uuid" => CommandProperty::UUID,
|
||||||
|
"forge:modid" => CommandProperty::ForgeModId,
|
||||||
|
"forge:enum" => CommandProperty::ForgeEnum {
|
||||||
|
cls: Serializable::read_from(buf)?,
|
||||||
|
},
|
||||||
_ => panic!("unsupported command node parser {}", parse),
|
_ => panic!("unsupported command node parser {}", parse),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -91,7 +91,7 @@ pub struct Game {
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn connect_to(&mut self, address: &str) {
|
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)
|
match protocol::Conn::new(&address, self.default_protocol_version)
|
||||||
.and_then(|conn| conn.do_status())
|
.and_then(|conn| conn.do_status())
|
||||||
{
|
{
|
||||||
|
@ -100,14 +100,18 @@ impl Game {
|
||||||
"Detected server protocol version {}",
|
"Detected server protocol version {}",
|
||||||
res.0.version.protocol
|
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) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Error pinging server {} to get protocol version: {:?}, defaulting to {}",
|
"Error pinging server {} to get protocol version: {:?}, defaulting to {}",
|
||||||
address, err, self.default_protocol_version
|
address, err, self.default_protocol_version
|
||||||
);
|
);
|
||||||
(self.default_protocol_version, vec![])
|
(self.default_protocol_version, vec![], None)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,6 +131,7 @@ impl Game {
|
||||||
&address,
|
&address,
|
||||||
protocol_version,
|
protocol_version,
|
||||||
forge_mods,
|
forge_mods,
|
||||||
|
fml_network_version,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::types::Gamemode;
|
||||||
use crate::world;
|
use crate::world;
|
||||||
use crate::world::block;
|
use crate::world::block;
|
||||||
use cgmath::prelude::*;
|
use cgmath::prelude::*;
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, info, warn};
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
@ -110,14 +110,17 @@ impl Server {
|
||||||
address: &str,
|
address: &str,
|
||||||
protocol_version: i32,
|
protocol_version: i32,
|
||||||
forge_mods: Vec<forge::ForgeMod>,
|
forge_mods: Vec<forge::ForgeMod>,
|
||||||
|
fml_network_version: Option<i64>,
|
||||||
) -> Result<Server, protocol::Error> {
|
) -> Result<Server, protocol::Error> {
|
||||||
let mut conn = protocol::Conn::new(address, protocol_version)?;
|
let mut conn = protocol::Conn::new(address, protocol_version)?;
|
||||||
|
|
||||||
let tag = if !forge_mods.is_empty() {
|
let tag = match fml_network_version {
|
||||||
"\0FML\0"
|
Some(1) => "\0FML\0",
|
||||||
} else {
|
Some(2) => "\0FML2\0",
|
||||||
""
|
None => "",
|
||||||
|
_ => panic!("unsupported FML network version: {:?}", fml_network_version),
|
||||||
};
|
};
|
||||||
|
|
||||||
let host = conn.host.clone() + tag;
|
let host = conn.host.clone() + tag;
|
||||||
let port = conn.port;
|
let port = conn.port;
|
||||||
conn.write_packet(protocol::packet::handshake::serverbound::Handshake {
|
conn.write_packet(protocol::packet::handshake::serverbound::Handshake {
|
||||||
|
@ -167,7 +170,6 @@ impl Server {
|
||||||
Some(rx),
|
Some(rx),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// TODO: avoid duplication
|
|
||||||
protocol::packet::Packet::LoginSuccess_UUID(val) => {
|
protocol::packet::Packet::LoginSuccess_UUID(val) => {
|
||||||
warn!("Server is running in offline mode");
|
warn!("Server is running in offline mode");
|
||||||
debug!("Login: {} {:?}", val.username, val.uuid);
|
debug!("Login: {} {:?}", val.username, val.uuid);
|
||||||
|
@ -188,7 +190,7 @@ impl Server {
|
||||||
protocol::packet::Packet::LoginDisconnect(val) => {
|
protocol::packet::Packet::LoginDisconnect(val) => {
|
||||||
return Err(protocol::Error::Disconnect(val.reason))
|
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))),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +227,7 @@ impl Server {
|
||||||
write.enable_encyption(&shared, false);
|
write.enable_encyption(&shared, false);
|
||||||
|
|
||||||
let uuid;
|
let uuid;
|
||||||
|
let compression_threshold = read.compression_threshold;
|
||||||
loop {
|
loop {
|
||||||
match read.read_packet()? {
|
match read.read_packet()? {
|
||||||
protocol::packet::Packet::SetInitialCompression(val) => {
|
protocol::packet::Packet::SetInitialCompression(val) => {
|
||||||
|
@ -248,7 +251,73 @@ impl Server {
|
||||||
protocol::packet::Packet::LoginDisconnect(val) => {
|
protocol::packet::Packet::LoginDisconnect(val) => {
|
||||||
return Err(protocol::Error::Disconnect(val.reason))
|
return Err(protocol::Error::Disconnect(val.reason))
|
||||||
}
|
}
|
||||||
val => return Err(protocol::Error::Err(format!("Wrong packet: {:?}", val))),
|
protocol::packet::Packet::LoginPluginRequest(req) => {
|
||||||
|
match req.channel.as_ref() {
|
||||||
|
"fml:loginwrapper" => {
|
||||||
|
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(
|
||||||
|
&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,
|
||||||
|
} => {
|
||||||
|
info!("ModList mod_names={:?} channels={:?} registries={:?}", mod_names, channels, registries);
|
||||||
|
write.write_fml2_handshake_plugin_message(
|
||||||
|
req.message_id,
|
||||||
|
Some(&ModListReply {
|
||||||
|
mod_names,
|
||||||
|
channels,
|
||||||
|
registries,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ServerRegistry {
|
||||||
|
name,
|
||||||
|
snapshot_present: _,
|
||||||
|
snapshot: _,
|
||||||
|
} => {
|
||||||
|
info!("ServerRegistry {:?}", name);
|
||||||
|
write.write_fml2_handshake_plugin_message(
|
||||||
|
req.message_id,
|
||||||
|
Some(&Acknowledgement),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ConfigurationData { filename, contents } => {
|
||||||
|
info!(
|
||||||
|
"ConfigurationData filename={:?} contents={}",
|
||||||
|
filename,
|
||||||
|
String::from_utf8_lossy(&contents)
|
||||||
|
);
|
||||||
|
write.write_fml2_handshake_plugin_message(
|
||||||
|
req.message_id,
|
||||||
|
Some(&Acknowledgement),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"unknown LoginPluginRequest fml:loginwrapper channel: {:?}",
|
||||||
|
channel
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("unsupported LoginPluginRequest channel: {:?}", req.channel),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val => return Err(protocol::Error::Err(format!("Wrong packet 2: {:?}", val))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,33 +1015,17 @@ impl Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove wrappers and directly call on Conn
|
||||||
fn write_fmlhs_plugin_message(&mut self, msg: &forge::FmlHs) {
|
fn write_fmlhs_plugin_message(&mut self, msg: &forge::FmlHs) {
|
||||||
use crate::protocol::Serializable;
|
let _ = self.conn.as_mut().unwrap().write_fmlhs_plugin_message(msg); // TODO handle errors
|
||||||
|
|
||||||
let mut buf: Vec<u8> = vec![];
|
|
||||||
msg.write_to(&mut buf).unwrap();
|
|
||||||
|
|
||||||
self.write_plugin_message("FML|HS", &buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_plugin_message(&mut self, channel: &str, data: &[u8]) {
|
fn write_plugin_message(&mut self, channel: &str, data: &[u8]) {
|
||||||
if protocol::is_network_debug() {
|
let _ = self
|
||||||
debug!(
|
.conn
|
||||||
"Sending plugin message: channel={}, data={:?}",
|
.as_mut()
|
||||||
channel, data
|
.unwrap()
|
||||||
);
|
.write_plugin_message(channel, data); // TODO handle errors
|
||||||
}
|
|
||||||
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::<protocol::VarShort>::new(data.to_vec()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_game_join_worldnames_ishard(
|
fn on_game_join_worldnames_ishard(
|
||||||
|
|
Loading…
Reference in New Issue