diff --git a/minecraft-protocol/src/mc_buf.rs b/minecraft-protocol/src/mc_buf.rs index b42a33bb..54ba1f7d 100644 --- a/minecraft-protocol/src/mc_buf.rs +++ b/minecraft-protocol/src/mc_buf.rs @@ -10,51 +10,67 @@ use tokio::io::{AsyncRead, AsyncReadExt}; const MAX_STRING_LENGTH: u16 = 32767; // const MAX_COMPONENT_STRING_LENGTH: u32 = 262144; -pub fn write_byte(buf: &mut Vec, n: u8) { - WriteBytesExt::write_u8(buf, n).unwrap(); +#[async_trait] +pub trait Writable { + fn write_byte(&mut self, n: u8) -> Result<(), std::io::Error>; + fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), std::io::Error>; + fn write_varint(&mut self, value: i32) -> Result<(), std::io::Error>; + fn write_utf_with_len(&mut self, string: &str, len: usize) -> Result<(), std::io::Error>; + fn write_utf(&mut self, string: &str) -> Result<(), std::io::Error>; + fn write_short(&mut self, n: u16) -> Result<(), std::io::Error>; + fn write_byte_array(&mut self, bytes: &[u8]) -> Result<(), std::io::Error>; } -pub fn write_bytes(buf: &mut Vec, bytes: &[u8]) { - buf.extend_from_slice(bytes); -} - -pub fn write_varint(buf: &mut Vec, mut value: i32) { - let mut buffer = [0]; - if value == 0 { - buf.write_all(&buffer).unwrap(); +#[async_trait] +impl Writable for Vec { + fn write_byte(&mut self, n: u8) -> Result<(), std::io::Error> { + WriteBytesExt::write_u8(self, n) } - while value != 0 { - buffer[0] = (value & 0b0111_1111) as u8; - value = (value >> 7) & (i32::max_value() >> 6); - if value != 0 { - buffer[0] |= 0b1000_0000; + + fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), std::io::Error> { + Ok(self.extend_from_slice(bytes)) + } + + fn write_varint(&mut self, mut value: i32) -> Result<(), std::io::Error> { + let mut buffer = [0]; + if value == 0 { + self.write_all(&buffer).unwrap(); } - buf.write_all(&buffer).unwrap(); + while value != 0 { + buffer[0] = (value & 0b0111_1111) as u8; + value = (value >> 7) & (i32::max_value() >> 6); + if value != 0 { + buffer[0] |= 0b1000_0000; + } + self.write_all(&buffer)?; + } + Ok(()) } -} -pub fn write_utf_with_len(buf: &mut Vec, string: &str, len: usize) { - if string.len() > len { - panic!( - "String too big (was {} bytes encoded, max {})", - string.len(), - len - ); + fn write_utf_with_len(&mut self, string: &str, len: usize) -> Result<(), std::io::Error> { + if string.len() > len { + panic!( + "String too big (was {} bytes encoded, max {})", + string.len(), + len + ); + } + self.write_varint(string.len() as i32); + self.write_bytes(string.as_bytes()) } - write_varint(buf, string.len() as i32); - write_bytes(buf, string.as_bytes()); -} -pub fn write_utf(buf: &mut Vec, string: &str) { - write_utf_with_len(buf, string, MAX_STRING_LENGTH.into()); -} -pub fn write_short(buf: &mut Vec, n: u16) { - WriteBytesExt::write_u16::(buf, n).unwrap(); -} + fn write_utf(&mut self, string: &str) -> Result<(), std::io::Error> { + self.write_utf_with_len(string, MAX_STRING_LENGTH.into()) + } -pub fn write_byte_array(buf: &mut Vec, bytes: &[u8]) { - write_varint(buf, bytes.len() as i32); - write_bytes(buf, bytes); + fn write_short(&mut self, n: u16) -> Result<(), std::io::Error> { + WriteBytesExt::write_u16::(self, n) + } + + fn write_byte_array(&mut self, bytes: &[u8]) -> Result<(), std::io::Error> { + self.write_varint(bytes.len() as i32); + self.write_bytes(bytes) + } } #[async_trait] @@ -159,11 +175,11 @@ mod tests { #[test] fn test_write_varint() { let mut buf = Vec::new(); - write_varint(&mut buf, 123456); + buf.write_varint(123456); assert_eq!(buf, vec![192, 196, 7]); let mut buf = Vec::new(); - write_varint(&mut buf, 0); + buf.write_varint(0); assert_eq!(buf, vec![0]); } diff --git a/minecraft-protocol/src/packets/handshake/client_intention_packet.rs b/minecraft-protocol/src/packets/handshake/client_intention_packet.rs index 3f7e3b37..868626b3 100644 --- a/minecraft-protocol/src/packets/handshake/client_intention_packet.rs +++ b/minecraft-protocol/src/packets/handshake/client_intention_packet.rs @@ -2,7 +2,7 @@ use std::hash::Hash; use tokio::io::BufReader; -use crate::{mc_buf, packets::ConnectionProtocol}; +use crate::{mc_buf::Writable, packets::ConnectionProtocol}; use super::HandshakePacket; @@ -21,10 +21,10 @@ impl ClientIntentionPacket { } pub fn write(&self, buf: &mut Vec) { - mc_buf::write_varint(buf, self.protocol_version as i32); - mc_buf::write_utf(buf, &self.hostname); - mc_buf::write_short(buf, self.port); - mc_buf::write_varint(buf, self.intention.clone() as i32); + buf.write_varint(self.protocol_version as i32).unwrap(); + buf.write_utf(&self.hostname).unwrap(); + buf.write_short(self.port).unwrap(); + buf.write_varint(self.intention.clone() as i32).unwrap(); } pub async fn read( diff --git a/minecraft-protocol/src/packets/login/serverbound_hello_packet.rs b/minecraft-protocol/src/packets/login/serverbound_hello_packet.rs index 69448074..32a6dadc 100644 --- a/minecraft-protocol/src/packets/login/serverbound_hello_packet.rs +++ b/minecraft-protocol/src/packets/login/serverbound_hello_packet.rs @@ -1,7 +1,7 @@ use std::hash::Hash; use tokio::io::BufReader; -use crate::mc_buf; +use crate::mc_buf::Writable; use super::LoginPacket; @@ -16,7 +16,7 @@ impl ServerboundHelloPacket { } pub fn write(&self, buf: &mut Vec) { - mc_buf::write_utf(buf, &self.username); + buf.write_utf(&self.username).unwrap(); } pub async fn read( diff --git a/minecraft-protocol/src/write.rs b/minecraft-protocol/src/write.rs index 529bb210..3d8540eb 100644 --- a/minecraft-protocol/src/write.rs +++ b/minecraft-protocol/src/write.rs @@ -1,6 +1,6 @@ use tokio::{io::AsyncWriteExt, net::TcpStream}; -use crate::{mc_buf, packets::ProtocolPacket}; +use crate::{mc_buf::Writable, packets::ProtocolPacket}; pub async fn write_packet(packet: impl ProtocolPacket, stream: &mut TcpStream) { // TODO: implement compression @@ -10,7 +10,7 @@ pub async fn write_packet(packet: impl ProtocolPacket, stream: &mut TcpStream) { // write the packet id let mut id_and_data_buf = vec![]; - mc_buf::write_varint(&mut id_and_data_buf, packet.id() as i32); + id_and_data_buf.write_varint(packet.id() as i32); packet.write(&mut id_and_data_buf); // write the packet data @@ -18,7 +18,7 @@ pub async fn write_packet(packet: impl ProtocolPacket, stream: &mut TcpStream) { // make a new buffer that has the length at the beginning // and id+data at the end let mut complete_buf: Vec = Vec::new(); - mc_buf::write_varint(&mut complete_buf, id_and_data_buf.len() as i32); + complete_buf.write_varint(id_and_data_buf.len() as i32); complete_buf.append(&mut id_and_data_buf); // finally, write and flush to the stream