Add login client bound packets
This commit is contained in:
parent
3d6dd8ed87
commit
764dfda8ed
35
src/lib.rs
35
src/lib.rs
@ -1,14 +1,19 @@
|
|||||||
//! This crate implements Minecraft protocol.
|
//! This crate implements Minecraft protocol.
|
||||||
//!
|
//!
|
||||||
//! Information about protocol can be found at https://wiki.vg/Protocol.
|
//! Information about protocol can be found at https://wiki.vg/Protocol.
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
|
||||||
use io::Error as IoError;
|
use io::Error as IoError;
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
|
||||||
use serde_json::error::Error as JsonError;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
|
use byteorder::ReadBytesExt;
|
||||||
|
use byteorder::WriteBytesExt;
|
||||||
|
use mc_varint::{VarIntRead, VarIntWrite};
|
||||||
|
use serde_json::error::Error as JsonError;
|
||||||
|
use uuid::parser::ParseError as UuidParseError;
|
||||||
|
|
||||||
|
use crate::chat::Message;
|
||||||
|
|
||||||
pub mod chat;
|
pub mod chat;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
@ -72,6 +77,9 @@ pub enum DecodeError {
|
|||||||
},
|
},
|
||||||
/// Boolean are parsed from byte. Valid byte value are 0 or 1.
|
/// Boolean are parsed from byte. Valid byte value are 0 or 1.
|
||||||
NonBoolValue,
|
NonBoolValue,
|
||||||
|
UuidParseError {
|
||||||
|
uuid_parse_error: UuidParseError,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IoError> for DecodeError {
|
impl From<IoError> for DecodeError {
|
||||||
@ -92,6 +100,12 @@ impl From<FromUtf8Error> for DecodeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<UuidParseError> for DecodeError {
|
||||||
|
fn from(uuid_parse_error: UuidParseError) -> Self {
|
||||||
|
DecodeError::UuidParseError { uuid_parse_error }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait Packet {
|
trait Packet {
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
@ -107,6 +121,8 @@ trait PacketRead {
|
|||||||
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError>;
|
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError>;
|
||||||
|
|
||||||
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>;
|
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>;
|
||||||
|
|
||||||
|
fn read_chat_message(&mut self) -> Result<Message, DecodeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait adds additional helper methods for `Write` to write protocol data.
|
/// Trait adds additional helper methods for `Write` to write protocol data.
|
||||||
@ -116,6 +132,8 @@ trait PacketWrite {
|
|||||||
fn write_string(&mut self, value: &str, max_length: u32) -> Result<(), EncodeError>;
|
fn write_string(&mut self, value: &str, max_length: u32) -> Result<(), EncodeError>;
|
||||||
|
|
||||||
fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError>;
|
fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError>;
|
||||||
|
|
||||||
|
fn write_chat_message(&mut self, value: &Message) -> Result<(), EncodeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> PacketRead for R {
|
impl<R: Read> PacketRead for R {
|
||||||
@ -148,6 +166,13 @@ impl<R: Read> PacketRead for R {
|
|||||||
|
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_chat_message(&mut self) -> Result<Message, DecodeError> {
|
||||||
|
let json = self.read_string(STRING_MAX_LENGTH)?;
|
||||||
|
let message = Message::from_json(&json)?;
|
||||||
|
|
||||||
|
Ok(message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Write> PacketWrite for W {
|
impl<W: Write> PacketWrite for W {
|
||||||
@ -180,4 +205,8 @@ impl<W: Write> PacketWrite for W {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_chat_message(&mut self, value: &Message) -> Result<(), EncodeError> {
|
||||||
|
self.write_string(&value.to_json()?, STRING_MAX_LENGTH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
201
src/login.rs
201
src/login.rs
@ -1,9 +1,14 @@
|
|||||||
use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite};
|
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
/// Login maximum length.
|
use mc_varint::{VarIntRead, VarIntWrite};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::chat::Message;
|
||||||
|
use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite, STRING_MAX_LENGTH};
|
||||||
|
|
||||||
const LOGIN_MAX_LENGTH: u32 = 16;
|
const LOGIN_MAX_LENGTH: u32 = 16;
|
||||||
|
const SERVER_ID_MAX_LENGTH: u32 = 20;
|
||||||
|
const HYPHENATED_UUID_LENGTH: u32 = 36;
|
||||||
|
|
||||||
pub enum LoginServerBoundPacket {
|
pub enum LoginServerBoundPacket {
|
||||||
LoginStart(LoginStart),
|
LoginStart(LoginStart),
|
||||||
@ -12,11 +17,11 @@ pub enum LoginServerBoundPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum LoginClientBoundPacket {
|
pub enum LoginClientBoundPacket {
|
||||||
Disconnect,
|
LoginDisconnect(LoginDisconnect),
|
||||||
EncryptionRequest,
|
EncryptionRequest(EncryptionRequest),
|
||||||
LoginSuccess,
|
LoginSuccess(LoginSuccess),
|
||||||
SetCompression,
|
SetCompression(SetCompression),
|
||||||
LoginPluginRequest,
|
LoginPluginRequest(LoginPluginRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoginServerBoundPacket {
|
impl LoginServerBoundPacket {
|
||||||
@ -160,3 +165,183 @@ impl Packet for LoginPluginResponse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LoginDisconnect {
|
||||||
|
pub reason: Message,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginDisconnect {
|
||||||
|
pub fn new(reason: Message) -> LoginClientBoundPacket {
|
||||||
|
let login_disconnect = LoginDisconnect { reason };
|
||||||
|
|
||||||
|
LoginClientBoundPacket::LoginDisconnect(login_disconnect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for LoginDisconnect {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_chat_message(&self.reason)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let reason = reader.read_chat_message()?;
|
||||||
|
|
||||||
|
Ok(LoginDisconnect { reason })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EncryptionRequest {
|
||||||
|
pub server_id: String,
|
||||||
|
pub public_key: Vec<u8>,
|
||||||
|
pub verify_token: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncryptionRequest {
|
||||||
|
pub fn new(
|
||||||
|
server_id: String,
|
||||||
|
public_key: Vec<u8>,
|
||||||
|
verify_token: Vec<u8>,
|
||||||
|
) -> LoginClientBoundPacket {
|
||||||
|
let encryption_request = EncryptionRequest {
|
||||||
|
server_id,
|
||||||
|
public_key,
|
||||||
|
verify_token,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginClientBoundPacket::EncryptionRequest(encryption_request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for EncryptionRequest {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_string(&self.server_id, SERVER_ID_MAX_LENGTH)?;
|
||||||
|
writer.write_byte_array(&self.public_key)?;
|
||||||
|
writer.write_byte_array(&self.verify_token)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let server_id = reader.read_string(SERVER_ID_MAX_LENGTH)?;
|
||||||
|
let public_key = reader.read_byte_array()?;
|
||||||
|
let verify_token = reader.read_byte_array()?;
|
||||||
|
|
||||||
|
Ok(EncryptionRequest {
|
||||||
|
server_id,
|
||||||
|
public_key,
|
||||||
|
verify_token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoginSuccess {
|
||||||
|
pub uuid: Uuid,
|
||||||
|
pub username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginSuccess {
|
||||||
|
pub fn new(uuid: Uuid, username: String) -> LoginClientBoundPacket {
|
||||||
|
let login_success = LoginSuccess { uuid, username };
|
||||||
|
|
||||||
|
LoginClientBoundPacket::LoginSuccess(login_success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for LoginSuccess {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
let uuid_hyphenated_string = self.uuid.to_hyphenated().to_string();
|
||||||
|
|
||||||
|
writer.write_string(&uuid_hyphenated_string, HYPHENATED_UUID_LENGTH)?;
|
||||||
|
writer.write_string(&self.username, LOGIN_MAX_LENGTH)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let uuid_hyphenated_string = reader.read_string(HYPHENATED_UUID_LENGTH)?;
|
||||||
|
|
||||||
|
let uuid = Uuid::parse_str(&uuid_hyphenated_string)?;
|
||||||
|
let username = reader.read_string(LOGIN_MAX_LENGTH)?;
|
||||||
|
|
||||||
|
Ok(LoginSuccess { uuid, username })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SetCompression {
|
||||||
|
pub threshold: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetCompression {
|
||||||
|
pub fn new(threshold: i32) -> LoginClientBoundPacket {
|
||||||
|
let set_compression = SetCompression { threshold };
|
||||||
|
|
||||||
|
LoginClientBoundPacket::SetCompression(set_compression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for SetCompression {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_var_i32(self.threshold)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let threshold = reader.read_var_i32()?;
|
||||||
|
|
||||||
|
Ok(SetCompression { threshold })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoginPluginRequest {
|
||||||
|
pub message_id: i32,
|
||||||
|
pub channel: String,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginPluginRequest {
|
||||||
|
pub fn new(message_id: i32, channel: String, data: Vec<u8>) -> LoginClientBoundPacket {
|
||||||
|
let login_plugin_request = LoginPluginRequest {
|
||||||
|
message_id,
|
||||||
|
channel,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginClientBoundPacket::LoginPluginRequest(login_plugin_request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for LoginPluginRequest {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
|
writer.write_var_i32(self.message_id)?;
|
||||||
|
writer.write_string(&self.channel, STRING_MAX_LENGTH)?;
|
||||||
|
writer.write_all(&self.data)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
||||||
|
let message_id = reader.read_var_i32()?;
|
||||||
|
let channel = reader.read_string(STRING_MAX_LENGTH)?;
|
||||||
|
let mut data = Vec::new();
|
||||||
|
reader.read_to_end(data.as_mut())?;
|
||||||
|
|
||||||
|
Ok(LoginPluginRequest {
|
||||||
|
message_id,
|
||||||
|
channel,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user