rust_mc_proto 0.1.19

lightweight minecraft protocol support in pure rust
Documentation
use uuid::Uuid;

use super::*;
use std::{io::Cursor, net::TcpListener, thread, time::Duration};

#[test]
fn test_varints() -> Result<(), ProtocolError> {
    /*
    
    Sample VarInts:

    | Value        | Hex bytes                    |
    | ------------ | ---------------------------- |
    | 0            | 0x00                         |
    | 1            | 0x01                         |
    | 2            | 0x02                         |
    | 127          | 0x7f                         |
    | 128          | 0x80, 0x01                   |
    | 255          | 0xff, 0x01                   |
    | 25565        | 0xdd, 0xc7, 0x01             |
    | 2097151      | 0xff, 0xff, 0x7f             |
    | 2147483647   | 0xff, 0xff, 0xff, 0xff, 0x07 |
    | -1           | 0xff, 0xff, 0xff, 0xff, 0x0f |
    | -2147483648  | 0x80, 0x80, 0x80, 0x80, 0x08 |

     */

    let mut packet = Packet::empty(0x00);

    packet.write_u8_varint(0)?;
    packet.write_u8_varint(1)?;
    packet.write_u8_varint(2)?;
    packet.write_u8_varint(127)?;
    packet.write_u8_varint(128)?;
    packet.write_u8_varint(255)?;
    packet.write_u16_varint(25565)?;
    packet.write_u32_varint(2097151)?;
    packet.write_u32_varint(2147483647)?;
    packet.write_i8_varint(-1)?;
    packet.write_i32_varint(-2147483648)?;

    packet.get_mut().set_position(0);
    
    assert_eq!(packet.read_bytes(1)?, &[0x00]); // 0
    assert_eq!(packet.read_bytes(1)?, &[0x01]); // 1
    assert_eq!(packet.read_bytes(1)?, &[0x02]); // 2
    assert_eq!(packet.read_bytes(1)?, &[0x7f]); // 127
    assert_eq!(packet.read_bytes(2)?, &[0x80, 0x01]); // 128
    assert_eq!(packet.read_bytes(2)?, &[0xff, 0x01]); // 255
    assert_eq!(packet.read_bytes(3)?, &[0xdd, 0xc7, 0x01]); // 25565
    assert_eq!(packet.read_bytes(3)?, &[0xff, 0xff, 0x7f]); // 2097151
    assert_eq!(packet.read_bytes(5)?, &[0xff, 0xff, 0xff, 0xff, 0x07]); // 2147483647
    assert_eq!(packet.read_bytes(5)?, &[0xff, 0xff, 0xff, 0xff, 0x0f]); // -1
    assert_eq!(packet.read_bytes(5)?, &[0x80, 0x80, 0x80, 0x80, 0x08]); // -2147483648

    packet.get_mut().set_position(0);
    
    assert_eq!(packet.read_u8_varint()?, 0);
    assert_eq!(packet.read_u8_varint()?, 1);
    assert_eq!(packet.read_u8_varint()?, 2);
    assert_eq!(packet.read_u8_varint()?, 127);
    assert_eq!(packet.read_u8_varint()?, 128);
    assert_eq!(packet.read_u8_varint()?, 255);
    assert_eq!(packet.read_u16_varint()?, 25565);
    assert_eq!(packet.read_u32_varint()?, 2097151);
    assert_eq!(packet.read_u32_varint()?, 2147483647);
    assert_eq!(packet.read_i32_varint()?, -1);
    assert_eq!(packet.read_i32_varint()?, -2147483648);

    Ok(())
}

#[test]
fn test_varlongs() -> Result<(), ProtocolError> {
    /*
    
    Sample VarLongs:

    | Value                 | Hex bytes                                                  |
    | --------------------- | ---------------------------------------------------------- |
    | 0                     | 0x00                                                       |
    | 1                     | 0x01                                                       |
    | 2                     | 0x02                                                       |
    | 127                   | 0x7f                                                       |
    | 128                   | 0x80, 0x01                                                 |
    | 255                   | 0xff, 0x01                                                 |
    | 2147483647            | 0xff, 0xff, 0xff, 0xff, 0x07                               |
    | 9223372036854775807   | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,      |
    | -1                    | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 |
    | -2147483648           | 0x80, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01 |
    | -9223372036854775808  | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01 |
    
     */

    let mut packet = Packet::empty(0x00);

    packet.write_u8_varlong(0)?;
    packet.write_u8_varlong(1)?;
    packet.write_u8_varlong(2)?;
    packet.write_u8_varlong(127)?;
    packet.write_u8_varlong(128)?;
    packet.write_u8_varlong(255)?;
    packet.write_u32_varlong(2147483647)?;
    packet.write_u64_varlong(9223372036854775807)?;
    packet.write_i8_varlong(-1)?;
    packet.write_i32_varlong(-2147483648)?;
    packet.write_i64_varlong(-9223372036854775808)?;

    packet.get_mut().set_position(0);

    assert_eq!(packet.read_bytes(1)?, &[0x00]); // 0
    assert_eq!(packet.read_bytes(1)?, &[0x01]); // 1
    assert_eq!(packet.read_bytes(1)?, &[0x02]); // 2
    assert_eq!(packet.read_bytes(1)?, &[0x7f]); // 127
    assert_eq!(packet.read_bytes(2)?, &[0x80, 0x01]); // 128
    assert_eq!(packet.read_bytes(2)?, &[0xff, 0x01]); // 255
    assert_eq!(packet.read_bytes(5)?, &[0xff, 0xff, 0xff, 0xff, 0x07]); // 2147483647
    assert_eq!(packet.read_bytes(9)?, &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]); // 9223372036854775807
    assert_eq!(packet.read_bytes(10)?, &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]); // -1
    assert_eq!(packet.read_bytes(10)?, &[0x80, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01]); // -2147483648
    assert_eq!(packet.read_bytes(10)?, &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01]); // -9223372036854775808

    packet.get_mut().set_position(0);

    assert_eq!(packet.read_u8_varlong()?, 0);
    assert_eq!(packet.read_u8_varlong()?, 1);
    assert_eq!(packet.read_u8_varlong()?, 2);
    assert_eq!(packet.read_u8_varlong()?, 127);
    assert_eq!(packet.read_u8_varlong()?, 128);
    assert_eq!(packet.read_u8_varlong()?, 255);
    assert_eq!(packet.read_u32_varlong()?, 2147483647);
    assert_eq!(packet.read_u64_varlong()?, 9223372036854775807);
    assert_eq!(packet.read_i8_varlong()?, -1);
    assert_eq!(packet.read_i32_varlong()?, -2147483648);
    assert_eq!(packet.read_i64_varlong()?, -9223372036854775808);

    Ok(())
}

#[test]
fn test_data_transfer() -> Result<(), ProtocolError> {
    fn server_thread(listener: TcpListener) -> Result<(), ProtocolError> {
        for stream in listener.incoming() {
            let mut stream = MCConnTcp::new(stream.or(Err(ProtocolError::StreamConnectError))?);

            stream.set_compression(Some(5));

            let mut packet = stream.read_packet()?;

            stream.write_packet(&Packet::build(packet.id(), |pack| {
                pack.write_boolean(packet.read_boolean()?)?;
                pack.write_byte(packet.read_byte()?)?;
                pack.write_bytes(&packet.read_bytes(10)?)?;
                pack.write_double(packet.read_double()?)?;
                pack.write_float(packet.read_float()?)?;
                pack.write_varint(packet.read_varint()?)?;
                pack.write_varlong(packet.read_varlong()?)?;
                pack.write_int(packet.read_int()?)?;
                pack.write_long(packet.read_long()?)?;
                pack.write_short(packet.read_short()?)?;
                pack.write_uuid(&packet.read_uuid()?)?;
                pack.write_string(&packet.read_string()?)?;
                Ok(())
            })?)?;

            stream.set_compression(None);

            let mut packet = stream.read_packet()?;

            stream.write_packet(&Packet::build(packet.id(), |pack| {
                pack.write_boolean(packet.read_boolean()?)?;
                pack.write_byte(packet.read_byte()?)?;
                pack.write_bytes(&packet.read_bytes(10)?)?;
                pack.write_double(packet.read_double()?)?;
                pack.write_float(packet.read_float()?)?;
                pack.write_varint(packet.read_varint()?)?;
                pack.write_varlong(packet.read_varlong()?)?;
                pack.write_int(packet.read_int()?)?;
                pack.write_long(packet.read_long()?)?;
                pack.write_short(packet.read_short()?)?;
                pack.write_uuid(&packet.read_uuid()?)?;
                pack.write_string(&packet.read_string()?)?;
                Ok(())
            })?)?;
        }

        Ok(())
    }

    fn test_conn(conn: &mut MinecraftConnection<TcpStream>) -> Result<(), ProtocolError> {
        conn.write_packet(&Packet::build(0xfe, |pack| {
            pack.write_boolean(true)?;
            pack.write_byte(0x12)?;
            pack.write_bytes(&vec![0x01, 0x56, 0x47, 0x48, 0xf5, 0xc2, 0x45, 0x98, 0xde, 0x99])?;
            pack.write_double(123456789.123456789f64)?;
            pack.write_float(789456.44422f32)?;
            pack.write_varint(468927512)?;
            pack.write_varlong(99859652365236523)?;
            pack.write_int(77861346i32)?;
            pack.write_long(789465123545678946i64)?;
            pack.write_short(1233i16)?;
            pack.write_uuid(&Uuid::try_parse("550e8400-e29b-41d4-a716-446655440000").map_err(|_| ProtocolError::CloneError)?)?;
            pack.write_string("&packet.read_string()?")?;
            Ok(())
        })?)?;
    
        let mut packet = conn.read_packet()?;
    
        assert_eq!(packet.read_boolean()?, true);
        assert_eq!(packet.read_byte()?, 0x12);
        assert_eq!(packet.read_bytes(10)?, vec![0x01, 0x56, 0x47, 0x48, 0xf5, 0xc2, 0x45, 0x98, 0xde, 0x99]);
        assert_eq!(packet.read_double()?, 123456789.123456789f64);
        assert_eq!(packet.read_float()?, 789456.44422f32);
        assert_eq!(packet.read_varint()?, 468927512);
        assert_eq!(packet.read_varlong()?, 99859652365236523);
        assert_eq!(packet.read_int()?, 77861346i32);
        assert_eq!(packet.read_long()?, 789465123545678946i64);
        assert_eq!(packet.read_short()?, 1233i16);
        assert_eq!(packet.read_uuid()?, Uuid::try_parse("550e8400-e29b-41d4-a716-446655440000").map_err(|_| ProtocolError::CloneError)?);
        assert_eq!(packet.read_string()?, "&packet.read_string()?");

        Ok(())
    }

    let listener =
        TcpListener::bind("127.0.0.1:0").or(Err(ProtocolError::StreamConnectError))?;

    let addr = listener.local_addr().expect("local addr error");

    thread::spawn(move || {
        server_thread(listener).expect("server error")
    });
    
    let mut conn = loop {
        if let Ok(conn) = MCConnTcp::connect(addr) {
            break conn;
        } else {
            thread::sleep(Duration::from_millis(10));
        }
    };

    conn.set_compression(Some(5));

    test_conn(&mut conn)?;

    conn.set_compression(None);

    test_conn(&mut conn)?;

    Ok(())
}

#[test]
fn test_compression() -> Result<(), ProtocolError> {
    let mut conn = MCConn::new(Cursor::new(Vec::new()));
    conn.set_compression(Some(5));

    let mut packet_1 = Packet::empty(0x12);
    packet_1.write_bytes(b"1234567890qwertyuiopasdfghjklzxcvbnm")?;
    dbg!(&packet_1);
    conn.write_packet(&packet_1)?;

    conn.get_mut().set_position(0);

    let mut packet_2 = conn.read_packet()?;

    assert_eq!(
        packet_2.read_bytes(36)?,
        b"1234567890qwertyuiopasdfghjklzxcvbnm"
    );

    Ok(())
}