1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

oh yeah it compiles

This commit is contained in:
mat 2021-12-15 13:43:57 -06:00
parent ace1405007
commit 732de94d7b
8 changed files with 192 additions and 80 deletions

View file

@ -1,11 +1,10 @@
///! Connect to Minecraft servers. ///! Connect to Minecraft servers.
use minecraft_protocol::{ use minecraft_protocol::{
connect::Connection, connect::HandshakeConnection,
packets::{ packets::{
handshake::client_intention_packet::ClientIntentionPacket, handshake::client_intention_packet::ClientIntentionPacket,
login::serverbound_hello_packet::ServerboundHelloPacket, login::{serverbound_hello_packet::ServerboundHelloPacket, LoginPacket},
status::clientbound_status_response_packet::ClientboundStatusResponsePacket, ConnectionProtocol, PROTOCOL_VERSION,
ConnectionProtocol, Packet, PROTOCOL_VERSION,
}, },
resolver, ServerAddress, resolver, ServerAddress,
}; };
@ -15,10 +14,10 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> {
let resolved_address = resolver::resolve_address(address).await?; let resolved_address = resolver::resolve_address(address).await?;
let mut conn = Connection::new(&resolved_address).await?; let mut conn = HandshakeConnection::new(&resolved_address).await?;
// handshake // handshake
conn.send_packet( conn.write(
ClientIntentionPacket { ClientIntentionPacket {
protocol_version: PROTOCOL_VERSION, protocol_version: PROTOCOL_VERSION,
hostname: address.host.clone(), hostname: address.host.clone(),
@ -28,16 +27,15 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> {
.get(), .get(),
) )
.await; .await;
conn.switch_state(ConnectionProtocol::Login); let mut conn = conn.login();
// login start // login start
conn.send_packet(ServerboundHelloPacket { username }.get()) conn.write(ServerboundHelloPacket { username }.get()).await;
.await;
// encryption request // encryption request
let packet = conn.read_packet().await.unwrap(); let packet = conn.read().await.unwrap();
let encryption_request_packet = match packet { let encryption_request_packet = match packet {
Packet::ClientboundHelloPacket(p) => p, LoginPacket::ClientboundHelloPacket(p) => p,
_ => Err(format!("Invalid packet type: {:?}", packet))?, _ => Err(format!("Invalid packet type: {:?}", packet))?,
}; };

View file

@ -1,13 +1,13 @@
///! Ping Minecraft servers. ///! Ping Minecraft servers.
use minecraft_protocol::{ use minecraft_protocol::{
connect::Connection, connect::HandshakeConnection,
packets::{ packets::{
handshake::client_intention_packet::ClientIntentionPacket, handshake::client_intention_packet::ClientIntentionPacket,
status::{ status::{
clientbound_status_response_packet::ClientboundStatusResponsePacket, clientbound_status_response_packet::ClientboundStatusResponsePacket,
serverbound_status_request_packet::ServerboundStatusRequestPacket, serverbound_status_request_packet::ServerboundStatusRequestPacket, StatusPacket,
}, },
ConnectionProtocol, Packet, PROTOCOL_VERSION, ConnectionProtocol, PROTOCOL_VERSION,
}, },
resolver, ServerAddress, resolver, ServerAddress,
}; };
@ -17,10 +17,10 @@ pub async fn ping_server(
) -> Result<ClientboundStatusResponsePacket, String> { ) -> Result<ClientboundStatusResponsePacket, String> {
let resolved_address = resolver::resolve_address(address).await?; let resolved_address = resolver::resolve_address(address).await?;
let mut conn = Connection::new(&resolved_address).await?; let mut conn = HandshakeConnection::new(&resolved_address).await?;
// send the client intention packet and switch to the status state // send the client intention packet and switch to the status state
conn.send_packet( conn.write(
ClientIntentionPacket { ClientIntentionPacket {
protocol_version: PROTOCOL_VERSION, protocol_version: PROTOCOL_VERSION,
hostname: address.host.clone(), hostname: address.host.clone(),
@ -30,16 +30,15 @@ pub async fn ping_server(
.get(), .get(),
) )
.await; .await;
conn.switch_state(ConnectionProtocol::Status); let mut conn = conn.status();
// send the empty status request packet // send the empty status request packet
conn.send_packet(ServerboundStatusRequestPacket {}.get()) conn.write(ServerboundStatusRequestPacket {}.get()).await;
.await;
let packet = conn.read_packet().await.unwrap(); let packet = conn.read().await.unwrap();
Ok(match packet { Ok(match packet {
Packet::ClientboundStatusResponsePacket(p) => p, StatusPacket::ClientboundStatusResponsePacket(p) => p,
_ => Err("Invalid packet type".to_string())?, _ => Err("Invalid packet type".to_string())?,
}) })
} }

View file

@ -1,6 +1,12 @@
//! parse sending and receiving packets with a server. //! parse sending and receiving packets with a server.
use crate::packets::ConnectionProtocol; use crate::packets::game::GamePacket;
use crate::packets::handshake::HandshakePacket;
use crate::packets::login::LoginPacket;
use crate::packets::status::StatusPacket;
use crate::packets::{ConnectionProtocol, ProtocolPacket};
use crate::read::read_packet;
use crate::write::write_packet;
use crate::{mc_buf, packets::Packet, ServerIpAddress}; use crate::{mc_buf, packets::Packet, ServerIpAddress};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::{ use tokio::{
@ -13,15 +19,32 @@ pub enum PacketFlow {
ServerToClient, ServerToClient,
} }
pub struct Connection { pub struct HandshakeConnection {
pub state: ConnectionProtocol,
pub flow: PacketFlow, pub flow: PacketFlow,
/// The buffered writer /// The buffered writer
pub stream: TcpStream, pub stream: TcpStream,
} }
impl Connection { pub struct GameConnection {
pub async fn new(address: &ServerIpAddress) -> Result<Connection, String> { pub flow: PacketFlow,
/// The buffered writer
pub stream: TcpStream,
}
pub struct StatusConnection {
pub flow: PacketFlow,
/// The buffered writer
pub stream: TcpStream,
}
pub struct LoginConnection {
pub flow: PacketFlow,
/// The buffered writer
pub stream: TcpStream,
}
impl HandshakeConnection {
pub async fn new(address: &ServerIpAddress) -> Result<HandshakeConnection, String> {
let ip = address.ip; let ip = address.ip;
let port = address.port; let port = address.port;
@ -34,67 +57,65 @@ impl Connection {
.set_nodelay(true) .set_nodelay(true)
.expect("Error enabling tcp_nodelay"); .expect("Error enabling tcp_nodelay");
Ok(Connection { Ok(HandshakeConnection {
state: ConnectionProtocol::Handshake,
flow: PacketFlow::ServerToClient, flow: PacketFlow::ServerToClient,
stream, stream,
}) })
} }
pub fn switch_state(&mut self, state: ConnectionProtocol) { pub fn login(self) -> LoginConnection {
self.state = state; LoginConnection {
flow: self.flow,
stream: self.stream,
}
} }
pub async fn read_packet(&mut self) -> Result<Packet, String> { pub fn status(self) -> StatusConnection {
// what this does: StatusConnection {
// 1. reads the first 5 bytes, probably only some of this will be used to get the packet length flow: self.flow,
// 2. how much we should read = packet length - 5 stream: self.stream,
// 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 pub async fn read(&mut self) -> Result<HandshakePacket, String> {
let mut buf = BufReader::with_capacity(4 * 1024 * 1024, &mut self.stream); read_packet::<HandshakePacket>(&self.flow, &mut self.stream).await
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 /// Write a packet to the server
pub async fn send_packet(&mut self, packet: Packet) { pub async fn write(&mut self, packet: HandshakePacket) {
// TODO: implement compression write_packet(packet, &mut self.stream).await;
}
// packet structure: }
// length (varint) + id (varint) + data
impl GameConnection {
// write the packet id pub async fn read(&mut self) -> Result<GamePacket, String> {
let mut id_and_data_buf = vec![]; read_packet::<GamePacket>(&self.flow, &mut self.stream).await
mc_buf::write_varint(&mut id_and_data_buf, packet.id() as i32); }
packet.write(&mut id_and_data_buf);
/// Write a packet to the server
// write the packet data pub async fn write(&mut self, packet: GamePacket) {
write_packet(packet, &mut self.stream).await;
// 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); impl StatusConnection {
complete_buf.append(&mut id_and_data_buf); pub async fn read(&mut self) -> Result<StatusPacket, String> {
read_packet::<StatusPacket>(&self.flow, &mut self.stream).await
// finally, write and flush to the stream }
self.stream.write_all(&complete_buf).await.unwrap();
self.stream.flush().await.unwrap(); /// Write a packet to the server
pub async fn write(&mut self, packet: StatusPacket) {
write_packet(packet, &mut self.stream).await;
}
}
impl LoginConnection {
pub async fn read(&mut self) -> Result<LoginPacket, String> {
read_packet::<LoginPacket>(&self.flow, &mut self.stream).await
}
/// Write a packet to the server
pub async fn write(&mut self, packet: LoginPacket) {
write_packet(packet, &mut self.stream).await;
} }
} }

View file

@ -6,7 +6,9 @@ use std::str::FromStr;
pub mod connect; pub mod connect;
pub mod mc_buf; pub mod mc_buf;
pub mod packets; pub mod packets;
pub mod read;
pub mod resolver; pub mod resolver;
pub mod write;
#[derive(Debug)] #[derive(Debug)]
pub struct ServerAddress { pub struct ServerAddress {

View file

@ -1,2 +1,41 @@
use async_trait::async_trait;
use tokio::io::BufReader;
use crate::connect::PacketFlow;
use super::ProtocolPacket;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum GamePacket {} pub enum GamePacket
where
Self: Sized, {}
#[async_trait]
impl ProtocolPacket for GamePacket {
fn id(&self) -> u32 {
match self {
_ => 0x00,
}
}
fn write(&self, buf: &mut Vec<u8>) {
match self {
_ => (),
}
}
/// Read a packet by its id, ConnectionProtocol, and flow
async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>(
id: u32,
flow: &PacketFlow,
buf: &mut BufReader<T>,
) -> Result<GamePacket, String>
where
Self: Sized,
{
match flow {
PacketFlow::ServerToClient => Err("HandshakePacket::read not implemented".to_string()),
PacketFlow::ClientToServer => Err("HandshakePacket::read not implemented".to_string()),
}
}
}

View file

@ -1,7 +1,5 @@
pub mod client_intention_packet; pub mod client_intention_packet;
use std::f32::consts::E;
use async_trait::async_trait; use async_trait::async_trait;
use tokio::io::BufReader; use tokio::io::BufReader;

View file

@ -0,0 +1,28 @@
use tokio::{io::BufReader, net::TcpStream};
use crate::{connect::PacketFlow, mc_buf, packets::ProtocolPacket};
pub async fn read_packet<P: ProtocolPacket>(
flow: &PacketFlow,
stream: &mut TcpStream,
) -> Result<P, 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, 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 = P::read(packet_id.try_into().unwrap(), &flow, &mut buf).await?;
Ok(packet)
}

View file

@ -0,0 +1,27 @@
use tokio::{io::AsyncWriteExt, net::TcpStream};
use crate::{mc_buf, packets::ProtocolPacket};
pub async fn write_packet(packet: impl ProtocolPacket, stream: &mut TcpStream) {
// 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
stream.write_all(&complete_buf).await.unwrap();
stream.flush().await.unwrap();
}