aboutsummaryrefslogtreecommitdiff
path: root/minecraft-protocol/src/connection.rs
blob: e0d781c87c11f4ceee05fafb74b53b810a8c2861 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! parse sending and receiving packets with a server.

use crate::packets::ConnectionProtocol;
use crate::{mc_buf, packets::Packet, ServerIpAddress};
use tokio::io::AsyncWriteExt;
use tokio::{
    io::{AsyncReadExt, BufReader},
    net::TcpStream,
};

pub enum PacketFlow {
    ClientToServer,
    ServerToClient,
}

pub struct Connection {
    pub state: ConnectionProtocol,
    pub flow: PacketFlow,
    /// The buffered writer
    pub stream: TcpStream,
}

impl Connection {
    pub async fn new(address: &ServerIpAddress) -> Result<Connection, String> {
        let ip = address.ip;
        let port = address.port;

        let stream = TcpStream::connect(format!("{}:{}", ip, port))
            .await
            .map_err(|_| "Failed to connect to server")?;

        // enable tcp_nodelay
        stream
            .set_nodelay(true)
            .expect("Error enabling tcp_nodelay");

        Ok(Connection {
            state: ConnectionProtocol::Handshaking,
            flow: PacketFlow::ClientToServer,
            stream,
        })
    }

    pub fn switch_state(&mut self, state: ConnectionProtocol) {
        self.state = state;
    }

    pub async fn read_packet(&mut self) -> Result<(), String> {
        // what this does:
        // 1. reads the first 5 bytes, probably only some of this will be used to get the packet length
        // 2. how much we should read = packet length - 5
        // 3. read the rest of the packet and add it to the cursor

        // the first thing minecraft sends us is the length as a varint, which can be up to 5 bytes long
        let mut buf = BufReader::with_capacity(4 * 1024 * 1024, &mut self.stream);
        println!("reading length varint");
        let (packet_size, packet_size_varint_size) = mc_buf::read_varint(&mut buf).await?;
        // then, minecraft tells us the packet id as a varint
        println!("reading id varint");
        let (packet_id, packet_id_size) = mc_buf::read_varint(&mut buf).await?;

        // if we recognize the packet id, parse it

        // TODO

        // otherwise, read the rest of the packet and throw it away
        let mut packet_data = Vec::with_capacity((packet_size - packet_id_size as i32) as usize);
        buf.read_buf(&mut packet_data).await.unwrap();
        println!("packet {:?}", packet_data);

        Ok(())
    }

    /// Write a packet to the server
    pub async fn send_packet(&mut self, packet: &impl Packet) {
        // TODO: implement compression

        // packet structure:
        // length (varint) + id (varint) + data

        // write the packet id
        let mut id_and_data_buf = vec![];
        mc_buf::write_varint(&mut id_and_data_buf, packet.get_id() as i32);
        packet.write(&mut id_and_data_buf);

        // write the packet data

        // make a new buffer that has the length at the beginning
        // and id+data at the end
        let mut complete_buf: Vec<u8> = Vec::new();
        mc_buf::write_varint(&mut complete_buf, id_and_data_buf.len() as i32);
        complete_buf.append(&mut id_and_data_buf);

        // finally, write and flush to the stream
        self.stream.write_all(&complete_buf).await.unwrap();
        self.stream.flush().await.unwrap();
    }
}