mirror of
https://github.com/mat-1/azalea.git
synced 2024-09-19 14:42:32 +00:00
add a few more login packets
This commit is contained in:
parent
999116ed7c
commit
227ba5511d
15 changed files with 181 additions and 24 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -30,6 +30,13 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "azalea-auth"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azalea-chat"
|
name = "azalea-chat"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -59,7 +66,9 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"azalea-auth",
|
||||||
"azalea-chat",
|
"azalea-chat",
|
||||||
|
"azalea-core",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -6,4 +6,5 @@ members = [
|
||||||
"azalea-protocol",
|
"azalea-protocol",
|
||||||
"azalea-chat",
|
"azalea-chat",
|
||||||
"azalea-core",
|
"azalea-core",
|
||||||
|
"azalea-auth",
|
||||||
]
|
]
|
||||||
|
|
9
azalea-auth/Cargo.toml
Normal file
9
azalea-auth/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "azalea-auth"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
uuid = "^0.8.2"
|
20
azalea-auth/src/game_profile.rs
Normal file
20
azalea-auth/src/game_profile.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Hash, Clone, Debug)]
|
||||||
|
pub struct GameProfile {
|
||||||
|
pub uuid: Uuid,
|
||||||
|
pub name: String,
|
||||||
|
pub properties: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameProfile {
|
||||||
|
pub fn new(uuid: Uuid, name: String) -> Self {
|
||||||
|
GameProfile {
|
||||||
|
uuid,
|
||||||
|
name,
|
||||||
|
properties: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
azalea-auth/src/lib.rs
Normal file
3
azalea-auth/src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
//! Handle Minecraft authentication.
|
||||||
|
|
||||||
|
pub mod game_profile;
|
|
@ -22,8 +22,6 @@ lazy_static! {
|
||||||
|
|
||||||
/// A chat component
|
/// A chat component
|
||||||
impl Component {
|
impl Component {
|
||||||
// TODO: is it possible to use a macro so this doesn't have to be duplicated?
|
|
||||||
|
|
||||||
pub fn get_base_mut(&mut self) -> &mut BaseComponent {
|
pub fn get_base_mut(&mut self) -> &mut BaseComponent {
|
||||||
match self {
|
match self {
|
||||||
Self::Text(c) => &mut c.base,
|
Self::Text(c) => &mut c.base,
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
//! A resource, like minecraft:stone
|
//! A resource, like minecraft:stone
|
||||||
|
|
||||||
pub struct ResourceLocation<'a> {
|
#[derive(Hash, Clone, Debug)]
|
||||||
pub namespace: &'a str,
|
pub struct ResourceLocation {
|
||||||
pub path: &'a str,
|
pub namespace: String,
|
||||||
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFAULT_NAMESPACE: &str = "minecraft";
|
static DEFAULT_NAMESPACE: &str = "minecraft";
|
||||||
// static REALMS_NAMESPACE: &str = "realms";
|
// static REALMS_NAMESPACE: &str = "realms";
|
||||||
|
|
||||||
impl<'a> ResourceLocation<'a> {
|
impl ResourceLocation {
|
||||||
pub fn new(resource_string: &str) -> Result<ResourceLocation, String> {
|
pub fn new(resource_string: &str) -> Result<ResourceLocation, String> {
|
||||||
let sep_byte_position_option = resource_string.chars().position(|c| c == ':');
|
let sep_byte_position_option = resource_string.chars().position(|c| c == ':');
|
||||||
let (namespace, path) = if let Some(sep_byte_position) = sep_byte_position_option {
|
let (namespace, path) = if let Some(sep_byte_position) = sep_byte_position_option {
|
||||||
|
@ -23,7 +24,16 @@ impl<'a> ResourceLocation<'a> {
|
||||||
} else {
|
} else {
|
||||||
(DEFAULT_NAMESPACE, resource_string)
|
(DEFAULT_NAMESPACE, resource_string)
|
||||||
};
|
};
|
||||||
Ok(ResourceLocation { namespace, path })
|
Ok(ResourceLocation {
|
||||||
|
namespace: namespace.to_string(),
|
||||||
|
path: path.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ResourceLocation {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}:{}", self.namespace, self.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl SerializableUuid for Uuid {
|
||||||
let most = ((array[0] as u64) << 32) | ((array[1] as u64) & 0xFFFFFFFF);
|
let most = ((array[0] as u64) << 32) | ((array[1] as u64) & 0xFFFFFFFF);
|
||||||
let least = ((array[2] as u64) << 32) | ((array[3] as u64) & 0xFFFFFFFF);
|
let least = ((array[2] as u64) << 32) | ((array[3] as u64) & 0xFFFFFFFF);
|
||||||
|
|
||||||
Uuid::from_u128((((most as u128) << 64) | least as u128).into())
|
Uuid::from_u128(((most as u128) << 64) | least as u128)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-recursion = "^0.3.2"
|
async-recursion = "^0.3.2"
|
||||||
async-trait = "0.1.51"
|
async-trait = "0.1.51"
|
||||||
|
azalea-auth = {path = "../azalea-auth"}
|
||||||
azalea-chat = {path = "../azalea-chat"}
|
azalea-chat = {path = "../azalea-chat"}
|
||||||
|
azalea-core = {path = "../azalea-core"}
|
||||||
byteorder = "^1.4.3"
|
byteorder = "^1.4.3"
|
||||||
bytes = "^1.1.0"
|
bytes = "^1.1.0"
|
||||||
serde = {version = "1.0.130", features = ["serde_derive"]}
|
serde = {version = "1.0.130", features = ["serde_derive"]}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Utilities for reading and writing for the Minecraft protocol
|
//! Utilities for reading and writing for the Minecraft protocol
|
||||||
|
|
||||||
use std::{future::Future, io::Write};
|
use std::io::Write;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
|
@ -35,6 +35,7 @@ pub trait Writable {
|
||||||
fn write_utf(&mut self, string: &str) -> 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_short(&mut self, n: u16) -> Result<(), std::io::Error>;
|
||||||
fn write_byte_array(&mut self, bytes: &[u8]) -> Result<(), std::io::Error>;
|
fn write_byte_array(&mut self, bytes: &[u8]) -> Result<(), std::io::Error>;
|
||||||
|
fn write_int(&mut self, n: i32) -> Result<(), std::io::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -79,7 +80,8 @@ impl Writable for Vec<u8> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), std::io::Error> {
|
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), std::io::Error> {
|
||||||
Ok(self.extend_from_slice(bytes))
|
self.extend_from_slice(bytes);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_varint(&mut self, mut value: i32) -> Result<(), std::io::Error> {
|
fn write_varint(&mut self, mut value: i32) -> Result<(), std::io::Error> {
|
||||||
|
@ -122,6 +124,10 @@ impl Writable for Vec<u8> {
|
||||||
self.write_varint(bytes.len() as i32)?;
|
self.write_varint(bytes.len() as i32)?;
|
||||||
self.write_bytes(bytes)
|
self.write_bytes(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_int(&mut self, n: i32) -> Result<(), std::io::Error> {
|
||||||
|
WriteBytesExt::write_i32::<BigEndian>(self, n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -133,6 +139,7 @@ pub trait Readable {
|
||||||
async fn read_utf(&mut self) -> Result<String, String>;
|
async fn read_utf(&mut self) -> Result<String, String>;
|
||||||
async fn read_utf_with_len(&mut self, max_length: u32) -> Result<String, String>;
|
async fn read_utf_with_len(&mut self, max_length: u32) -> Result<String, String>;
|
||||||
async fn read_byte(&mut self) -> Result<u8, String>;
|
async fn read_byte(&mut self) -> Result<u8, String>;
|
||||||
|
async fn read_int(&mut self) -> Result<i32, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -225,6 +232,13 @@ where
|
||||||
Err(_) => Err("Error reading byte".to_string()),
|
Err(_) => Err("Error reading byte".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn read_int(&mut self) -> Result<i32, String> {
|
||||||
|
match AsyncReadExt::read_i32(self).await {
|
||||||
|
Ok(r) => Ok(r),
|
||||||
|
Err(_) => Err("Error reading int".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
|
use super::LoginPacket;
|
||||||
|
use crate::mc_buf::{Readable, Writable};
|
||||||
|
use azalea_core::resource_location::ResourceLocation;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use tokio::io::BufReader;
|
use tokio::io::BufReader;
|
||||||
|
|
||||||
use crate::mc_buf::{Readable, Writable};
|
|
||||||
|
|
||||||
use super::LoginPacket;
|
|
||||||
|
|
||||||
#[derive(Hash, Clone, Debug)]
|
#[derive(Hash, Clone, Debug)]
|
||||||
pub struct ClientboundCustomQueryPacket {
|
pub struct ClientboundCustomQueryPacket {
|
||||||
pub transaction_id: u32,
|
pub transaction_id: u32,
|
||||||
// TODO: this should be a resource location
|
pub identifier: ResourceLocation,
|
||||||
pub identifier: String,
|
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +18,7 @@ impl ClientboundCustomQueryPacket {
|
||||||
|
|
||||||
pub fn write(&self, buf: &mut Vec<u8>) {
|
pub fn write(&self, buf: &mut Vec<u8>) {
|
||||||
buf.write_varint(self.transaction_id as i32).unwrap();
|
buf.write_varint(self.transaction_id as i32).unwrap();
|
||||||
buf.write_utf(&self.identifier).unwrap();
|
buf.write_utf(self.identifier.to_string().as_str()).unwrap();
|
||||||
buf.write_bytes(&self.data).unwrap();
|
buf.write_bytes(&self.data).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +26,7 @@ impl ClientboundCustomQueryPacket {
|
||||||
buf: &mut BufReader<T>,
|
buf: &mut BufReader<T>,
|
||||||
) -> Result<LoginPacket, String> {
|
) -> Result<LoginPacket, String> {
|
||||||
let transaction_id = buf.read_varint().await? as u32;
|
let transaction_id = buf.read_varint().await? as u32;
|
||||||
// TODO: this should be a resource location
|
let identifier = ResourceLocation::new(&buf.read_utf().await?)?;
|
||||||
let identifier = buf.read_utf().await?;
|
|
||||||
let data = buf.read_bytes(1048576).await?;
|
let data = buf.read_bytes(1048576).await?;
|
||||||
Ok(ClientboundCustomQueryPacket {
|
Ok(ClientboundCustomQueryPacket {
|
||||||
transaction_id,
|
transaction_id,
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
use super::LoginPacket;
|
||||||
|
use crate::mc_buf::{Readable, Writable};
|
||||||
|
use azalea_auth::game_profile::GameProfile;
|
||||||
|
use azalea_core::{resource_location::ResourceLocation, serializable_uuid::SerializableUuid};
|
||||||
|
use std::hash::Hash;
|
||||||
|
use tokio::io::BufReader;
|
||||||
|
|
||||||
|
#[derive(Hash, Clone, Debug)]
|
||||||
|
pub struct ClientboundGameProfilePacket {
|
||||||
|
pub game_profile: GameProfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientboundGameProfilePacket {
|
||||||
|
pub fn get(self) -> LoginPacket {
|
||||||
|
LoginPacket::ClientboundGameProfilePacket(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, buf: &mut Vec<u8>) {
|
||||||
|
for n in self.game_profile.uuid.to_int_array() {
|
||||||
|
buf.write_int(n as i32).unwrap();
|
||||||
|
}
|
||||||
|
buf.write_utf(self.game_profile.name.as_str()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>(
|
||||||
|
buf: &mut BufReader<T>,
|
||||||
|
) -> Result<LoginPacket, String> {
|
||||||
|
let uuid = SerializableUuid::from_int_array(
|
||||||
|
buf.read_int().await?,
|
||||||
|
buf.read_int().await?,
|
||||||
|
buf.read_int().await?,
|
||||||
|
buf.read_int().await?,
|
||||||
|
);
|
||||||
|
let name = buf.read_utf(16).await?;
|
||||||
|
ClientboundGameProfilePacket {
|
||||||
|
game_profile: GameProfile::new(uuid, name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
use std::hash::Hash;
|
||||||
|
use tokio::io::BufReader;
|
||||||
|
|
||||||
|
use crate::mc_buf::Readable;
|
||||||
|
|
||||||
|
use super::LoginPacket;
|
||||||
|
|
||||||
|
#[derive(Hash, Clone, Debug)]
|
||||||
|
pub struct ClientboundLoginCompressionPacket {
|
||||||
|
pub compression_threshold: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientboundLoginCompressionPacket {
|
||||||
|
pub fn get(self) -> LoginPacket {
|
||||||
|
LoginPacket::ClientboundLoginCompressionPacket(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, buf: &mut Vec<u8>) {
|
||||||
|
buf.write_varint(self.compression_threshold).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>(
|
||||||
|
buf: &mut BufReader<T>,
|
||||||
|
) -> Result<LoginPacket, String> {
|
||||||
|
let compression_threshold = buf.read_varint().await?;
|
||||||
|
|
||||||
|
Ok(ClientboundLoginCompressionPacket {
|
||||||
|
compression_threshold
|
||||||
|
}
|
||||||
|
.get())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
pub mod clientbound_custom_query_packet;
|
pub mod clientbound_custom_query_packet;
|
||||||
|
pub mod clientbound_game_profile_packet;
|
||||||
pub mod clientbound_hello_packet;
|
pub mod clientbound_hello_packet;
|
||||||
|
pub mod clientbound_login_compression_packet;
|
||||||
pub mod serverbound_hello_packet;
|
pub mod serverbound_hello_packet;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
@ -15,8 +17,12 @@ where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
ClientboundCustomQueryPacket(clientbound_custom_query_packet::ClientboundCustomQueryPacket),
|
ClientboundCustomQueryPacket(clientbound_custom_query_packet::ClientboundCustomQueryPacket),
|
||||||
ServerboundHelloPacket(serverbound_hello_packet::ServerboundHelloPacket),
|
ClientboundGameProfilePacket(clientbound_game_profile_packet::ClientboundGameProfilePacket),
|
||||||
ClientboundHelloPacket(clientbound_hello_packet::ClientboundHelloPacket),
|
ClientboundHelloPacket(clientbound_hello_packet::ClientboundHelloPacket),
|
||||||
|
ClientboundLoginCompressionPacket(
|
||||||
|
clientbound_login_compression_packet::ClientboundLoginCompressionPacket,
|
||||||
|
),
|
||||||
|
ServerboundHelloPacket(serverbound_hello_packet::ServerboundHelloPacket),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -24,16 +30,20 @@ impl ProtocolPacket for LoginPacket {
|
||||||
fn id(&self) -> u32 {
|
fn id(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
LoginPacket::ClientboundCustomQueryPacket(_packet) => 0x04,
|
LoginPacket::ClientboundCustomQueryPacket(_packet) => 0x04,
|
||||||
LoginPacket::ServerboundHelloPacket(_packet) => 0x00,
|
LoginPacket::ClientboundGameProfilePacket(_packet) => 0x02,
|
||||||
LoginPacket::ClientboundHelloPacket(_packet) => 0x01,
|
LoginPacket::ClientboundHelloPacket(_packet) => 0x01,
|
||||||
|
LoginPacket::ClientboundLoginCompressionPacket(_packet) => 0x03,
|
||||||
|
LoginPacket::ServerboundHelloPacket(_packet) => 0x00,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, buf: &mut Vec<u8>) {
|
fn write(&self, buf: &mut Vec<u8>) {
|
||||||
match self {
|
match self {
|
||||||
LoginPacket::ClientboundCustomQueryPacket(packet) => packet.write(buf),
|
LoginPacket::ClientboundCustomQueryPacket(packet) => packet.write(buf),
|
||||||
LoginPacket::ServerboundHelloPacket(packet) => packet.write(buf),
|
LoginPacket::ClientboundGameProfilePacket(packet) => packet.write(buf),
|
||||||
LoginPacket::ClientboundHelloPacket(packet) => packet.write(buf),
|
LoginPacket::ClientboundHelloPacket(packet) => packet.write(buf),
|
||||||
|
LoginPacket::ClientboundLoginCompressionPacket(packet) => packet.write(buf),
|
||||||
|
LoginPacket::ServerboundHelloPacket(packet) => packet.write(buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,9 +59,18 @@ impl ProtocolPacket for LoginPacket {
|
||||||
Ok(match flow {
|
Ok(match flow {
|
||||||
PacketFlow::ServerToClient => match id {
|
PacketFlow::ServerToClient => match id {
|
||||||
0x01 => clientbound_hello_packet::ClientboundHelloPacket::read(buf).await?,
|
0x01 => clientbound_hello_packet::ClientboundHelloPacket::read(buf).await?,
|
||||||
|
0x02 => {
|
||||||
|
clientbound_game_profile_packet::ClientboundGameProfilePacket::read(buf).await?
|
||||||
|
}
|
||||||
0x04 => {
|
0x04 => {
|
||||||
clientbound_custom_query_packet::ClientboundCustomQueryPacket::read(buf).await?
|
clientbound_custom_query_packet::ClientboundCustomQueryPacket::read(buf).await?
|
||||||
}
|
}
|
||||||
|
0x03 => {
|
||||||
|
clientbound_login_compression_packet::ClientboundLoginCompressionPacket::read(
|
||||||
|
buf,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
_ => return Err(format!("Unknown ServerToClient status packet id: {}", id)),
|
_ => return Err(format!("Unknown ServerToClient status packet id: {}", id)),
|
||||||
},
|
},
|
||||||
PacketFlow::ClientToServer => match id {
|
PacketFlow::ClientToServer => match id {
|
||||||
|
|
|
@ -10,7 +10,9 @@ pub async fn write_packet(packet: impl ProtocolPacket, stream: &mut TcpStream) {
|
||||||
|
|
||||||
// write the packet id
|
// write the packet id
|
||||||
let mut id_and_data_buf = vec![];
|
let mut id_and_data_buf = vec![];
|
||||||
id_and_data_buf.write_varint(packet.id() as i32);
|
id_and_data_buf
|
||||||
|
.write_varint(packet.id() as i32)
|
||||||
|
.expect("Writing packet id failed");
|
||||||
packet.write(&mut id_and_data_buf);
|
packet.write(&mut id_and_data_buf);
|
||||||
|
|
||||||
// write the packet data
|
// write the packet data
|
||||||
|
@ -18,7 +20,9 @@ pub async fn write_packet(packet: impl ProtocolPacket, stream: &mut TcpStream) {
|
||||||
// make a new buffer that has the length at the beginning
|
// make a new buffer that has the length at the beginning
|
||||||
// and id+data at the end
|
// and id+data at the end
|
||||||
let mut complete_buf: Vec<u8> = Vec::new();
|
let mut complete_buf: Vec<u8> = Vec::new();
|
||||||
complete_buf.write_varint(id_and_data_buf.len() as i32);
|
complete_buf
|
||||||
|
.write_varint(id_and_data_buf.len() as i32)
|
||||||
|
.expect("Writing packet length failed");
|
||||||
complete_buf.append(&mut id_and_data_buf);
|
complete_buf.append(&mut id_and_data_buf);
|
||||||
|
|
||||||
// finally, write and flush to the stream
|
// finally, write and flush to the stream
|
||||||
|
|
Loading…
Reference in a new issue