this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Handshaking, Logging in and PacketBuilder

Closes issues #6 and #7

- Implemented basic handshaking logic as well as logging in and reaching the "play" state
- Introduced a PacketBuilder for easier packet creation
- Created a new data type called PrefixedArray ( According to the minecraft.wiki's documentation)

Rouffy 184c3a39 121d3cef

+331 -2
+115
src/api.rs
··· 1 + use std::{ 2 + fs::File, 3 + io::{Read, Write}, 4 + net::TcpStream, 5 + }; 6 + 7 + use crate::{types::packet::PacketBuilder, types::prefixed_array::PrefixedArray}; 8 + 9 + // Used as the first ever packet sent for the TCP connection, to set the intent that the connection will use 10 + pub fn sb_handshake(intent: i32, stream: &mut TcpStream) { 11 + let packet = PacketBuilder::new(Some(0x00)) 12 + .add_varint(772) 13 + .add_string("127.0.0.1") 14 + .add_ushort(25565 as u16) 15 + .add_varint(intent) 16 + .build(); 17 + 18 + stream.write_all(&packet).unwrap(); 19 + stream.flush().unwrap(); 20 + } 21 + 22 + // Request server information ( Intent must be set to 1 when calling sb_handshake) 23 + #[allow(dead_code)] 24 + fn sb_status() { 25 + let mut stream = TcpStream::connect("127.0.0.1:25565").unwrap(); 26 + sb_handshake(1, &mut stream); 27 + let packet = PacketBuilder::new(Some(0x00)).build(); 28 + 29 + stream.write_all(&packet).unwrap(); 30 + stream.flush().unwrap(); 31 + } 32 + 33 + // Good to have for crash logs 34 + pub fn sb_client_brand(stream: &mut TcpStream) { 35 + let packet = PacketBuilder::new(Some(0x02)) 36 + .add_string("minecraft:brand") 37 + .add_string("meartis-client") 38 + .build(); 39 + 40 + stream.write_all(&packet).unwrap(); 41 + stream.flush().unwrap(); 42 + } 43 + 44 + // Used to login into the minecraft server ( Intent must be set to 2 when calling sb_handshake 45 + pub fn sb_login(stream: &mut TcpStream) { 46 + sb_handshake(2, stream); 47 + 48 + let mut urandom = File::open("/dev/urandom").unwrap(); 49 + let mut uuid_buffer: [u8; 16] = [0u8; 16]; 50 + 51 + urandom.read_exact(&mut uuid_buffer).unwrap(); 52 + 53 + let packet = PacketBuilder::new(Some(0x00)) 54 + .add_string("roufpup2") 55 + .add_slice(&uuid_buffer) 56 + .build(); 57 + 58 + stream.write_all(&packet).unwrap(); 59 + stream.flush().unwrap(); 60 + } 61 + 62 + // After receiving succesful login response from the server confirm that it has been received 63 + pub fn sb_login_acknowledged(stream: &mut TcpStream) { 64 + let packet = PacketBuilder::new(Some(0x03)).build(); 65 + 66 + stream.write_all(&packet).unwrap(); 67 + stream.flush().unwrap(); 68 + } 69 + 70 + // After logging in we need to stay connected to the server while answering a keep alive hearbeats 71 + pub fn sb_keep_alive(stream: &mut TcpStream, buffer: Vec<u8>) { 72 + let mut packet = PacketBuilder::new(None).add_slice(&buffer).build(); 73 + 74 + stream.write_all(&mut packet).unwrap(); 75 + stream.flush().unwrap(); 76 + } 77 + 78 + // Declares player settings when they connect 79 + pub fn sb_client_information(stream: &mut TcpStream) { 80 + let packet = PacketBuilder::new(Some(0x00)) 81 + .add_string("en_us") 82 + .add_u8(12 as u8) 83 + .add_varint(0 as i32) 84 + .add_u8(0x01 as u8) 85 + .add_u8(0x7f as u8) 86 + .add_varint(1 as i32) 87 + .add_u8(0x00 as u8) 88 + .add_u8(0x01 as u8) 89 + .add_varint(0 as i32) 90 + .build(); 91 + 92 + stream.write_all(&packet).unwrap(); 93 + stream.flush().unwrap(); 94 + } 95 + 96 + // Declares the known packs to the server ( Required for configuration to finalize) 97 + pub fn sb_known_packs(stream: &mut TcpStream) { 98 + let packet = PacketBuilder::new(Some(0x07)) 99 + .add_slice( 100 + &PrefixedArray::new() 101 + .add_value(["minecraft", "core", "1.21.8"]) 102 + .construct_buffer(), 103 + ) 104 + .build(); 105 + 106 + stream.write_all(&packet).unwrap(); 107 + stream.flush().unwrap(); 108 + } 109 + 110 + // Tells the server that the configuration confirmation has been received and we can proceed to the next state 111 + pub fn sb_acknowledge_finish_configuration(stream: &mut TcpStream) { 112 + let mut packet = PacketBuilder::new(Some(0x03)).build(); 113 + stream.write_all(&mut packet).unwrap(); 114 + stream.flush().unwrap(); 115 + }
+55 -2
src/main.rs
··· 1 - use std::net::TcpStream; 1 + use std::{io::Read, net::TcpStream}; 2 + 3 + use crate::{ 4 + api::{ 5 + sb_acknowledge_finish_configuration, sb_client_brand, sb_client_information, sb_keep_alive, 6 + sb_known_packs, sb_login, sb_login_acknowledged, 7 + }, 8 + utils::read_varing_from_stream, 9 + }; 10 + 11 + pub mod api; 12 + pub mod types; 13 + pub mod utils; 2 14 3 15 fn main() { 4 - println!("Hello meartis!") 16 + let mut stream = TcpStream::connect("127.0.0.1:25565").unwrap(); 17 + // TODO we need to have a more robust state management 18 + let mut state = "login"; 19 + 20 + // Program entry point 21 + sb_login(&mut stream); 22 + 23 + // TODO we neeb better TCP/API management 24 + loop { 25 + let data_size = read_varing_from_stream(&mut stream); 26 + let mut buffer = vec![0; data_size as usize]; 27 + 28 + stream.read_exact(&mut buffer).unwrap(); 29 + 30 + match buffer[0] { 31 + 0x02 => { 32 + if state == "login" { 33 + sb_login_acknowledged(&mut stream); 34 + state = "configuration"; 35 + 36 + sb_client_brand(&mut stream); 37 + sb_client_information(&mut stream); 38 + } 39 + } 40 + 0x03 => { 41 + if state == "configuration" { 42 + sb_acknowledge_finish_configuration(&mut stream); 43 + } 44 + } 45 + 0x04 => { 46 + if state == "configuration" { 47 + sb_keep_alive(&mut stream, buffer); 48 + } 49 + } 50 + 0x0E => { 51 + if state == "configuration" { 52 + sb_known_packs(&mut stream); 53 + } 54 + } 55 + _ => println!("ToDo: {:#04X} : {:#04X?}", buffer[0], buffer), 56 + } 57 + } 5 58 }
+2
src/types/mod.rs
··· 1 + pub mod packet; 2 + pub mod prefixed_array;
+47
src/types/packet.rs
··· 1 + use crate::utils::{string_to_buffer, varint_to_buffer}; 2 + 3 + pub struct PacketBuilder { 4 + buffer: Vec<u8>, 5 + } 6 + 7 + impl PacketBuilder { 8 + pub fn new(packet_id: Option<i32>) -> Self { 9 + let mut pb = PacketBuilder { buffer: Vec::new() }; 10 + if let Some(value) = packet_id { 11 + pb.add_varint(value); 12 + } 13 + pb 14 + } 15 + 16 + pub fn add_varint(&mut self, value: i32) -> &mut Self { 17 + varint_to_buffer(value, &mut self.buffer); 18 + self 19 + } 20 + 21 + pub fn add_string(&mut self, value: &str) -> &mut Self { 22 + string_to_buffer(value, &mut self.buffer); 23 + self 24 + } 25 + 26 + pub fn add_ushort(&mut self, value: u16) -> &mut Self { 27 + self.buffer.extend_from_slice(&value.to_be_bytes().to_vec()); 28 + self 29 + } 30 + 31 + pub fn add_u8(&mut self, value: u8) -> &mut Self { 32 + self.buffer.push(value); 33 + self 34 + } 35 + 36 + pub fn add_slice(&mut self, value: &[u8]) -> &mut Self { 37 + self.buffer.extend_from_slice(value); 38 + self 39 + } 40 + 41 + pub fn build(&mut self) -> Vec<u8> { 42 + let mut final_packet: Vec<u8> = Vec::new(); 43 + varint_to_buffer(self.buffer.len() as i32, &mut final_packet); 44 + final_packet.extend_from_slice(&self.buffer); 45 + final_packet 46 + } 47 + }
+63
src/types/prefixed_array.rs
··· 1 + use crate::utils::{string_to_buffer, varint_to_buffer}; 2 + 3 + pub struct PrefixedArray<P> { 4 + store: Vec<P>, 5 + } 6 + 7 + pub trait ArrayElement<A> { 8 + fn add_value(value: A, store: &mut Vec<A>); 9 + fn construct_buffer(store: &Vec<A>) -> Vec<u8>; 10 + } 11 + 12 + impl<R> PrefixedArray<R> { 13 + pub fn new() -> Self { 14 + PrefixedArray::<R> { store: Vec::new() } 15 + } 16 + pub fn add_value(&mut self, value: R) -> &mut Self 17 + where 18 + R: ArrayElement<R>, 19 + { 20 + R::add_value(value, &mut self.store); 21 + self 22 + } 23 + 24 + pub fn construct_buffer(&mut self) -> Vec<u8> 25 + where 26 + R: ArrayElement<R>, 27 + { 28 + R::construct_buffer(&self.store) 29 + } 30 + } 31 + 32 + impl ArrayElement<&str> for &str { 33 + fn add_value<'a>(value: &'a str, store: &mut Vec<&'a str>) { 34 + store.push(value); 35 + } 36 + 37 + fn construct_buffer(store: &Vec<&str>) -> Vec<u8> { 38 + let mut buffer = Vec::new(); 39 + varint_to_buffer(store.len() as i32, &mut buffer); 40 + for str in store.iter() { 41 + string_to_buffer(str, &mut buffer); 42 + } 43 + buffer 44 + } 45 + } 46 + 47 + impl ArrayElement<[&str; 3]> for [&str; 3] { 48 + fn add_value<'a>(value: [&'a str; 3], store: &mut Vec<[&'a str; 3]>) { 49 + store.push(value); 50 + } 51 + 52 + fn construct_buffer(store: &Vec<[&str; 3]>) -> Vec<u8> { 53 + let mut buffer = Vec::new(); 54 + varint_to_buffer(store.len() as i32, &mut buffer); 55 + store.iter().for_each(|x| { 56 + for string in x { 57 + string_to_buffer(string, &mut buffer); 58 + } 59 + }); 60 + 61 + buffer 62 + } 63 + }
+49
src/utils.rs
··· 1 + use std::{io::Read, net::TcpStream}; 2 + 3 + pub(crate) fn string_to_buffer(value: &str, buffer: &mut Vec<u8>) { 4 + varint_to_buffer(value.len() as i32, buffer); 5 + buffer.extend_from_slice(value.as_bytes()); 6 + } 7 + 8 + pub(crate) fn varint_to_buffer(mut value: i32, buffer: &mut Vec<u8>) { 9 + let mask: i32 = 0b0111_1111; 10 + loop { 11 + // get only the first 7 bits 12 + let mut chunk = (mask & value) as u8; 13 + 14 + // prepare the next 7 bits by pushing them at the start 15 + value >>= 7; 16 + 17 + // flip the last bit to indicate if there is more data to read 18 + if value != 0 { 19 + chunk |= 0b1000_0000; 20 + } 21 + 22 + buffer.push(chunk); 23 + 24 + if value == 0 { 25 + break; 26 + } 27 + } 28 + } 29 + 30 + pub fn read_varing_from_stream(stream: &mut TcpStream) -> i32 { 31 + let mut buffer: [u8; 1] = [0]; 32 + let mut final_value: i32 = 0; 33 + let mut shift_amount: i32 = 0; 34 + 35 + loop { 36 + stream.read_exact(&mut buffer).unwrap(); 37 + let mut value = (buffer[0] & 0b0111_1111) as i32; 38 + 39 + value = value << (7 * shift_amount); 40 + final_value |= value; 41 + 42 + if (buffer[0] & 0b_1000_0000) as i32 == 0 { 43 + break; 44 + } 45 + 46 + shift_amount += 1; 47 + } 48 + final_value 49 + }