2019-05-05 21:37:37 -04:00
|
|
|
use byteorder::WriteBytesExt;
|
2019-05-22 19:01:14 -04:00
|
|
|
use log::debug;
|
2020-06-21 15:17:24 -04:00
|
|
|
/// Implements https://wiki.vg/Minecraft_Forge_Handshake
|
|
|
|
use std::io;
|
2019-05-05 21:37:37 -04:00
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
use super::{Error, LenPrefixed, Serializable, VarInt};
|
2019-05-05 21:37:37 -04:00
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
pub enum Phase {
|
|
|
|
// Client handshake states (written)
|
|
|
|
Start,
|
|
|
|
WaitingServerData,
|
|
|
|
WaitingServerComplete,
|
|
|
|
PendingComplete,
|
|
|
|
|
|
|
|
// Server handshake states (read)
|
|
|
|
WaitingCAck,
|
|
|
|
|
|
|
|
// Both client and server handshake states (different values on the wire)
|
|
|
|
Complete,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for Phase {
|
|
|
|
/// Read server handshake state from server
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
|
|
|
let phase: i8 = Serializable::read_from(buf)?;
|
|
|
|
Ok(match phase {
|
|
|
|
2 => Phase::WaitingCAck,
|
|
|
|
3 => Phase::Complete,
|
|
|
|
_ => panic!("bad FML|HS server phase: {}", phase),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Send client handshake state from client
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
buf.write_u8(match self {
|
|
|
|
Phase::WaitingServerData => 2,
|
|
|
|
Phase::WaitingServerComplete => 3,
|
|
|
|
Phase::PendingComplete => 4,
|
|
|
|
Phase::Complete => 5,
|
|
|
|
_ => panic!("bad FML|HS client phase: {:?}", self),
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
|
|
pub struct ForgeMod {
|
|
|
|
pub modid: String,
|
|
|
|
pub version: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for ForgeMod {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
|
|
|
Ok(ForgeMod {
|
|
|
|
modid: Serializable::read_from(buf)?,
|
|
|
|
version: Serializable::read_from(buf)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
self.modid.write_to(buf)?;
|
|
|
|
self.version.write_to(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ModIdMapping {
|
|
|
|
pub name: String,
|
|
|
|
pub id: VarInt,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for ModIdMapping {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
|
|
|
Ok(ModIdMapping {
|
|
|
|
name: Serializable::read_from(buf)?,
|
|
|
|
id: Serializable::read_from(buf)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
self.name.write_to(buf)?;
|
|
|
|
self.id.write_to(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-28 21:27:30 -04:00
|
|
|
pub static BLOCK_NAMESPACE: &str = "\u{1}";
|
|
|
|
pub static ITEM_NAMESPACE: &str = "\u{2}";
|
2019-05-15 15:22:24 -04:00
|
|
|
|
2019-05-05 21:37:37 -04:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum FmlHs {
|
|
|
|
ServerHello {
|
|
|
|
fml_protocol_version: i8,
|
|
|
|
override_dimension: Option<i32>,
|
|
|
|
},
|
|
|
|
ClientHello {
|
|
|
|
fml_protocol_version: i8,
|
|
|
|
},
|
|
|
|
ModList {
|
|
|
|
mods: LenPrefixed<VarInt, ForgeMod>,
|
|
|
|
},
|
|
|
|
RegistryData {
|
|
|
|
has_more: bool,
|
|
|
|
name: String,
|
|
|
|
ids: LenPrefixed<VarInt, ModIdMapping>,
|
|
|
|
substitutions: LenPrefixed<VarInt, String>,
|
|
|
|
dummies: LenPrefixed<VarInt, String>,
|
|
|
|
},
|
|
|
|
ModIdData {
|
|
|
|
mappings: LenPrefixed<VarInt, ModIdMapping>,
|
|
|
|
block_substitutions: LenPrefixed<VarInt, String>,
|
|
|
|
item_substitutions: LenPrefixed<VarInt, String>,
|
|
|
|
},
|
|
|
|
HandshakeAck {
|
|
|
|
phase: Phase,
|
|
|
|
},
|
|
|
|
HandshakeReset,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for FmlHs {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
|
|
|
let discriminator: u8 = Serializable::read_from(buf)?;
|
|
|
|
|
|
|
|
match discriminator {
|
|
|
|
0 => {
|
|
|
|
let fml_protocol_version: i8 = Serializable::read_from(buf)?;
|
|
|
|
let override_dimension = if fml_protocol_version > 1 {
|
|
|
|
let dimension: i32 = Serializable::read_from(buf)?;
|
|
|
|
Some(dimension)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
debug!(
|
|
|
|
"FML|HS ServerHello: fml_protocol_version={}, override_dimension={:?}",
|
|
|
|
fml_protocol_version, override_dimension
|
|
|
|
);
|
2019-05-05 21:37:37 -04:00
|
|
|
|
|
|
|
Ok(FmlHs::ServerHello {
|
|
|
|
fml_protocol_version,
|
|
|
|
override_dimension,
|
|
|
|
})
|
2020-06-21 15:17:24 -04:00
|
|
|
}
|
2019-05-05 21:37:37 -04:00
|
|
|
1 => panic!("Received unexpected FML|HS ClientHello from server"),
|
2020-06-21 15:17:24 -04:00
|
|
|
2 => Ok(FmlHs::ModList {
|
|
|
|
mods: Serializable::read_from(buf)?,
|
|
|
|
}),
|
2019-05-05 21:37:37 -04:00
|
|
|
3 => {
|
2020-01-08 21:57:57 -05:00
|
|
|
let protocol_version = super::current_protocol_version();
|
2019-05-11 21:37:33 -04:00
|
|
|
|
|
|
|
if protocol_version >= 47 {
|
|
|
|
Ok(FmlHs::RegistryData {
|
|
|
|
has_more: Serializable::read_from(buf)?,
|
|
|
|
name: Serializable::read_from(buf)?,
|
|
|
|
ids: Serializable::read_from(buf)?,
|
|
|
|
substitutions: Serializable::read_from(buf)?,
|
|
|
|
dummies: Serializable::read_from(buf)?,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Ok(FmlHs::ModIdData {
|
|
|
|
mappings: Serializable::read_from(buf)?,
|
|
|
|
block_substitutions: Serializable::read_from(buf)?,
|
2020-06-21 15:17:24 -04:00
|
|
|
item_substitutions: Serializable::read_from(buf)?,
|
2019-05-11 21:37:33 -04:00
|
|
|
})
|
|
|
|
}
|
2020-06-21 15:17:24 -04:00
|
|
|
}
|
|
|
|
255 => Ok(FmlHs::HandshakeAck {
|
|
|
|
phase: Serializable::read_from(buf)?,
|
|
|
|
}),
|
2019-05-05 21:37:37 -04:00
|
|
|
_ => panic!("Unhandled FML|HS packet: discriminator={}", discriminator),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
match self {
|
2020-06-21 15:17:24 -04:00
|
|
|
FmlHs::ClientHello {
|
|
|
|
fml_protocol_version,
|
|
|
|
} => {
|
2019-05-05 21:37:37 -04:00
|
|
|
buf.write_u8(1)?;
|
|
|
|
fml_protocol_version.write_to(buf)
|
2020-06-21 15:17:24 -04:00
|
|
|
}
|
2019-05-05 21:37:37 -04:00
|
|
|
FmlHs::ModList { mods } => {
|
|
|
|
buf.write_u8(2)?;
|
|
|
|
mods.write_to(buf)
|
2020-06-21 15:17:24 -04:00
|
|
|
}
|
2019-05-05 21:37:37 -04:00
|
|
|
FmlHs::HandshakeAck { phase } => {
|
|
|
|
buf.write_u8(255)?;
|
|
|
|
phase.write_to(buf)
|
2020-06-21 15:17:24 -04:00
|
|
|
}
|
|
|
|
_ => unimplemented!(),
|
2019-05-05 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-23 16:47:30 -05:00
|
|
|
|
|
|
|
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!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|