init commit??
This commit is contained in:
parent
32c09ce144
commit
39df5454a2
73
Cargo.lock
generated
Normal file
73
Cargo.lock
generated
Normal file
@ -0,0 +1,73 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "bytebuffer"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7bfaf7cd08cacd74cdc6b521c37ac39cbc92692e5ab5c21ed5657a749b577c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_mc_proto"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytebuffer",
|
||||
"flate2",
|
||||
"varint-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "varint-rs"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23"
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "rust_mc_proto"
|
||||
description = "Minecraft packets protocol in pure rust"
|
||||
|
||||
license-file = "LICENSE"
|
||||
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
varint-rs = "2.2.0"
|
||||
flate2 = "1.0.30"
|
||||
bytebuffer = "2.2.0"
|
13
LICENSE
Normal file
13
LICENSE
Normal file
@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
305
src/lib.rs
Normal file
305
src/lib.rs
Normal file
@ -0,0 +1,305 @@
|
||||
use std::io::{Write, Read};
|
||||
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
|
||||
use bytebuffer::ByteBuffer;
|
||||
use varint_rs::{VarintWriter, VarintReader};
|
||||
use flate2::{Compress, Compression, Decompress, FlushCompress, Status, FlushDecompress};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProtocolError {
|
||||
AddressParseError,
|
||||
DataRanOutError,
|
||||
StringParseError,
|
||||
StreamConnectError,
|
||||
VarIntError,
|
||||
ReadError,
|
||||
WriteError,
|
||||
ZlibError,
|
||||
UnsignedShortError
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Packet {
|
||||
pub id: u8,
|
||||
pub buffer: ByteBuffer
|
||||
}
|
||||
|
||||
impl VarintWriter for Packet {
|
||||
type Error = ProtocolError;
|
||||
|
||||
fn write(&mut self, byte: u8) -> Result<(), Self::Error> {
|
||||
match Write::write(&mut self.buffer, &[byte]) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(ProtocolError::WriteError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VarintReader for Packet {
|
||||
type Error = ProtocolError;
|
||||
|
||||
fn read(&mut self) -> Result<u8, Self::Error> {
|
||||
let mut buf = vec![0; 1];
|
||||
|
||||
match Read::read(&mut self.buffer, &mut buf) {
|
||||
Ok(i) => {
|
||||
if i == 1 {
|
||||
Ok(buf[0])
|
||||
} else {
|
||||
Err(ProtocolError::ReadError)
|
||||
}
|
||||
},
|
||||
Err(_) => Err(ProtocolError::ReadError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
pub fn new(id: u8, buffer: ByteBuffer) -> Packet {
|
||||
Packet {
|
||||
id,
|
||||
buffer
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bytes(id: u8, data: &[u8]) -> Packet {
|
||||
Packet {
|
||||
id,
|
||||
buffer: ByteBuffer::from_bytes(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty(id: u8) -> Packet {
|
||||
Packet {
|
||||
id,
|
||||
buffer: ByteBuffer::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_string(&mut self, s: String) -> Result<(), ProtocolError> {
|
||||
let bytes = s.as_bytes();
|
||||
|
||||
self.write_usize_varint(bytes.len())?;
|
||||
|
||||
for b in bytes {
|
||||
self.write(*b)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_string(&mut self) -> Result<String, ProtocolError> {
|
||||
let size = self.read_usize_varint()?;
|
||||
let mut bytes: Vec<u8> = vec![0; size];
|
||||
|
||||
for _ in 0..size {
|
||||
bytes.push(self.read()?);
|
||||
}
|
||||
|
||||
match String::from_utf8(bytes) {
|
||||
Ok(i) => Ok(i),
|
||||
Err(_) => Err(ProtocolError::StringParseError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_unsigned_short(&mut self, short: u16) -> Result<(), ProtocolError> {
|
||||
match self.buffer.write_all(&short.to_be_bytes()) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(ProtocolError::UnsignedShortError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Connection {
|
||||
pub stream: TcpStream,
|
||||
pub addr: SocketAddr,
|
||||
compress: bool,
|
||||
compress_threashold: usize
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn build(addr: &str) -> Result<Connection, ProtocolError> {
|
||||
let addr = match addr.to_socket_addrs() {
|
||||
Ok(mut i) => { match i.next() {
|
||||
Some(i) => { i },
|
||||
None => { return Err(ProtocolError::AddressParseError) },
|
||||
} },
|
||||
Err(_) => { return Err(ProtocolError::AddressParseError) },
|
||||
};
|
||||
|
||||
let stream: TcpStream = match TcpStream::connect(&addr) {
|
||||
Ok(i) => i,
|
||||
Err(_) => { return Err(ProtocolError::StreamConnectError) },
|
||||
};
|
||||
|
||||
Ok(Connection {
|
||||
stream,
|
||||
addr,
|
||||
compress: false,
|
||||
compress_threashold: 0
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(addr: &str) -> Connection {
|
||||
Self::build(addr).unwrap()
|
||||
}
|
||||
|
||||
pub fn set_compression(&mut self, threashold: usize) {
|
||||
self.compress = true;
|
||||
self.compress_threashold = threashold;
|
||||
}
|
||||
|
||||
pub fn read_packet(&mut self) -> Result<Packet, ProtocolError> {
|
||||
if !self.compress {
|
||||
let length = self.read_usize_varint()?;
|
||||
|
||||
let packet_id = self.read_u8_varint()?;
|
||||
let mut data: Vec<u8> = vec![0; length - 1];
|
||||
match self.stream.read_exact(&mut data) {
|
||||
Ok(i) => i,
|
||||
Err(_) => { return Err(ProtocolError::ReadError) },
|
||||
};
|
||||
|
||||
Ok(Packet::from_bytes(packet_id, &data))
|
||||
} else {
|
||||
let packet_length = self.read_usize_varint()?;
|
||||
let data_length = self.read_usize_varint()?;
|
||||
|
||||
if data_length == 0 {
|
||||
let mut data: Vec<u8> = vec![0; packet_length - 1];
|
||||
match self.stream.read_exact(&mut data) {
|
||||
Ok(i) => i,
|
||||
Err(_) => { return Err(ProtocolError::ReadError) },
|
||||
};
|
||||
|
||||
let mut data_buf = ByteBuffer::from_vec(decompress_zlib(&data)?);
|
||||
|
||||
let packet_id = match data_buf.read_u8_varint() {
|
||||
Ok(i) => i,
|
||||
Err(_) => { return Err(ProtocolError::VarIntError) },
|
||||
};
|
||||
let mut data: Vec<u8> = vec![0; data_length - 1];
|
||||
match data_buf.read_exact(&mut data) {
|
||||
Ok(i) => i,
|
||||
Err(_) => { return Err(ProtocolError::ReadError) },
|
||||
};
|
||||
|
||||
Ok(Packet::from_bytes(packet_id, &data))
|
||||
} else {
|
||||
let packet_id = self.read_u8_varint()?;
|
||||
let mut data: Vec<u8> = vec![0; data_length - 1];
|
||||
match self.stream.read_exact(&mut data) {
|
||||
Ok(i) => i,
|
||||
Err(_) => { return Err(ProtocolError::ReadError) },
|
||||
};
|
||||
|
||||
Ok(Packet::from_bytes(packet_id, &data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_packet(&mut self, packet: &Packet) -> Result<(), ProtocolError> {
|
||||
let mut buf = ByteBuffer::new();
|
||||
|
||||
if !self.compress {
|
||||
match buf.write_usize_varint(packet.buffer.len() + 1) {
|
||||
Ok(_) => {},
|
||||
Err(_) => { return Err(ProtocolError::WriteError) },
|
||||
};
|
||||
match buf.write_u8_varint(packet.id) {
|
||||
Ok(_) => {},
|
||||
Err(_) => { return Err(ProtocolError::WriteError) },
|
||||
};
|
||||
match buf.write_all(packet.buffer.as_bytes()) {
|
||||
Ok(_) => {},
|
||||
Err(_) => { return Err(ProtocolError::WriteError) },
|
||||
};
|
||||
} else {
|
||||
let mut pack = ByteBuffer::new();
|
||||
|
||||
if packet.buffer.len() < self.compress_threashold {
|
||||
pack.write_usize_varint(0).unwrap();
|
||||
pack.write_u8_varint(packet.id).unwrap();
|
||||
pack.write_all(packet.buffer.as_bytes()).unwrap();
|
||||
} else {
|
||||
let mut data = ByteBuffer::new();
|
||||
|
||||
data.write_u8_varint(packet.id).unwrap();
|
||||
data.write_all(packet.buffer.as_bytes()).unwrap();
|
||||
|
||||
let data = compress_zlib(data.as_bytes())?;
|
||||
|
||||
pack.write_usize_varint(packet.buffer.len() + 1).unwrap();
|
||||
pack.write_all(&data).unwrap();
|
||||
}
|
||||
|
||||
buf.write_usize_varint(pack.len()).unwrap();
|
||||
buf.write_all(pack.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
self.stream.write_all(buf.as_bytes()).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
self.stream.shutdown(std::net::Shutdown::Both).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl VarintWriter for Connection {
|
||||
type Error = ProtocolError;
|
||||
|
||||
fn write(&mut self, byte: u8) -> Result<(), Self::Error> {
|
||||
match Write::write(&mut self.stream, &[byte]) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(ProtocolError::WriteError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VarintReader for Connection {
|
||||
type Error = ProtocolError;
|
||||
|
||||
fn read(&mut self) -> Result<u8, Self::Error> {
|
||||
let mut buf = vec![0; 1];
|
||||
|
||||
match Read::read(&mut self.stream, &mut buf) {
|
||||
Ok(i) => {
|
||||
if i == 1 {
|
||||
Ok(buf[0])
|
||||
} else {
|
||||
Err(ProtocolError::ReadError)
|
||||
}
|
||||
},
|
||||
Err(_) => Err(ProtocolError::ReadError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compress_zlib(bytes: &[u8]) -> Result<Vec<u8>, ProtocolError> {
|
||||
let mut compresser = Compress::new(Compression::best(), true);
|
||||
let mut output: Vec<u8> = Vec::new();
|
||||
match compresser.compress_vec(&bytes, &mut output, FlushCompress::Finish) {
|
||||
Ok(i) => {
|
||||
match i {
|
||||
Status::Ok => Ok(output),
|
||||
_ => Err(ProtocolError::ZlibError)
|
||||
}
|
||||
},
|
||||
Err(_) => Err(ProtocolError::ZlibError)
|
||||
}
|
||||
}
|
||||
|
||||
fn decompress_zlib(bytes: &[u8]) -> Result<Vec<u8>, ProtocolError> {
|
||||
let mut compresser = Decompress::new(true);
|
||||
let mut output: Vec<u8> = Vec::new();
|
||||
match compresser.decompress_vec(&bytes, &mut output, FlushDecompress::Finish) {
|
||||
Ok(i) => {
|
||||
match i {
|
||||
Status::Ok => Ok(output),
|
||||
_ => Err(ProtocolError::ZlibError)
|
||||
}
|
||||
},
|
||||
Err(_) => Err(ProtocolError::ZlibError)
|
||||
}
|
||||
}
|
37
src/main.rs
Normal file
37
src/main.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use rust_mc_proto::{Connection, Packet, ProtocolError};
|
||||
use varint_rs::{VarintReader, VarintWriter};
|
||||
use std::io::Write;
|
||||
|
||||
fn send_handshake(conn: &mut Connection,
|
||||
protocol_version: u16,
|
||||
server_address: &str,
|
||||
server_port: u16,
|
||||
next_state: u8) -> Result<(), ProtocolError> {
|
||||
let mut packet = Packet::empty(0x00);
|
||||
packet.write_u16_varint(protocol_version)?;
|
||||
packet.write_string(server_address.to_string())?;
|
||||
packet.write_unsigned_short(server_port)?;
|
||||
packet.write_u8_varint(next_state)?;
|
||||
|
||||
packet.buffer.set_rpos(0);
|
||||
packet.buffer.set_wpos(0);
|
||||
|
||||
conn.write_packet(&packet)
|
||||
}
|
||||
|
||||
fn send_status_request(conn: &mut Connection) -> Result<(), ProtocolError> {
|
||||
conn.write_packet(&Packet::empty(0x00))
|
||||
}
|
||||
|
||||
fn read_status_response(conn: &mut Connection) -> Result<String, ProtocolError> {
|
||||
let mut packet = conn.read_packet()?;
|
||||
packet.read_string()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut conn = Connection::new("localhost:25565");
|
||||
|
||||
send_handshake(&mut conn, 765, "localhost", 25565, 1).unwrap();
|
||||
send_status_request(&mut conn).unwrap();
|
||||
println!("{}", read_status_response(&mut conn).unwrap());
|
||||
}
|
Loading…
Reference in New Issue
Block a user