diff options
| author | mat <github@matdoes.dev> | 2021-12-13 00:07:21 -0600 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2021-12-13 00:07:21 -0600 |
| commit | c96ae8fce4e53ea9fad111ac7f479f2fa33ef859 (patch) | |
| tree | 2d35061fa712464b225317f56a806d0dd269ca82 /minecraft-protocol/src/connect.rs | |
| parent | 2c3bf3b79e133acd01580144771a7cf238ecc4ee (diff) | |
| download | azalea-drasl-c96ae8fce4e53ea9fad111ac7f479f2fa33ef859.tar.xz | |
start implementing joining servers
Diffstat (limited to 'minecraft-protocol/src/connect.rs')
| -rw-r--r-- | minecraft-protocol/src/connect.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/minecraft-protocol/src/connect.rs b/minecraft-protocol/src/connect.rs new file mode 100644 index 00000000..5b750802 --- /dev/null +++ b/minecraft-protocol/src/connect.rs @@ -0,0 +1,100 @@ +//! 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::Handshake, + flow: PacketFlow::ServerToClient, + stream, + }) + } + + pub fn switch_state(&mut self, state: ConnectionProtocol) { + self.state = state; + } + + pub async fn read_packet(&mut self) -> Result<Packet, 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 + // 4. figure out what packet this is and parse it + + // 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); + + let (_packet_size, _packet_size_varint_size) = mc_buf::read_varint(&mut buf).await?; + + // then, minecraft tells us the packet id as a varint + let (packet_id, _packet_id_size) = mc_buf::read_varint(&mut buf).await?; + + // if we recognize the packet id, parse it + + let packet = Packet::read( + packet_id.try_into().unwrap(), + &self.state, + &self.flow, + &mut buf, + ) + .await?; + + Ok(packet) + } + + /// Write a packet to the server + pub async fn send_packet(&mut self, packet: 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.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(); + } +} |
