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

update codegen and use resourcelocation names for packets

This commit is contained in:
mat 2024-11-27 04:59:13 +00:00
parent 170ffb07d0
commit f8cd7ed1de
45 changed files with 665 additions and 646 deletions

View file

@ -11,7 +11,7 @@ use std::{
io::{Cursor, Write},
};
use azalea_buf::{BufReadError, AzaleaRead, AzaleaReadVar, AzaleaWriteVar, AzaleaWrite};
use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
pub use behavior::BlockBehavior;
pub use generated::{blocks, properties};
pub use range::BlockStates;

View file

@ -3,9 +3,7 @@ use std::io::{Cursor, Write};
use std::{collections::HashSet, hash::Hash};
#[cfg(feature = "azalea-buf")]
use azalea_buf::{
BufReadError, AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWriteVar, AzaleaWrite,
};
use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
#[cfg(feature = "azalea-buf")]
use azalea_chat::FormattedText;

View file

@ -10,9 +10,9 @@ mod write;
pub use azalea_buf_macros::*;
pub use definitions::*;
pub use read::{BufReadError, AzaleaRead, AzaleaReadVar};
pub use read::{AzaleaRead, AzaleaReadVar, BufReadError};
pub use serializable_uuid::*;
pub use write::{AzaleaWriteVar, AzaleaWrite};
pub use write::{AzaleaWrite, AzaleaWriteVar};
// const DEFAULT_NBT_QUOTA: u32 = 2097152;
const MAX_STRING_LENGTH: u16 = 32767;

View file

@ -196,9 +196,7 @@ impl<K: AzaleaRead + Send + Eq + Hash, V: AzaleaRead + Send> AzaleaRead for Hash
}
}
impl<K: AzaleaRead + Send + Eq + Hash, V: AzaleaReadVar + Send> AzaleaReadVar
for HashMap<K, V>
{
impl<K: AzaleaRead + Send + Eq + Hash, V: AzaleaReadVar + Send> AzaleaReadVar for HashMap<K, V> {
fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let length = i32::azalea_read_var(buf)? as usize;
let mut contents = HashMap::with_capacity(usize::min(length, 65536));

View file

@ -1,7 +1,7 @@
use std::fmt::Display;
#[cfg(feature = "azalea-buf")]
use azalea_buf::{BufReadError, AzaleaRead, AzaleaWrite};
use azalea_buf::{AzaleaRead, AzaleaWrite, BufReadError};
use once_cell::sync::Lazy;
use serde::{de, Deserialize, Deserializer, Serialize};
#[cfg(feature = "simdnbt")]

View file

@ -17,13 +17,13 @@ use azalea_entity::{
};
use azalea_physics::PhysicsPlugin;
use azalea_protocol::{
common::ClientInformation,
common::client_information::ClientInformation,
connect::{Connection, ConnectionError, Proxy},
packets::{
config::{ClientboundConfigPacket, ServerboundConfigPacket},
game::ServerboundGamePacket,
handshake::{
s_client_intention::ServerboundClientIntention, ClientboundHandshakePacket,
s_intention::ServerboundIntention, ClientboundHandshakePacket,
ServerboundHandshakePacket,
},
login::{
@ -349,7 +349,7 @@ impl Client {
JoinError,
> {
// handshake
conn.write(ServerboundClientIntention {
conn.write(ServerboundIntention {
protocol_version: PROTOCOL_VERSION,
hostname: address.host.clone(),
port: address.port,

View file

@ -1,7 +1,7 @@
use azalea_buf::AzaleaWrite;
use azalea_core::resource_location::ResourceLocation;
use azalea_protocol::{
common::ClientInformation,
common::client_information::ClientInformation,
packets::config::{
s_client_information::ServerboundClientInformation,
s_custom_payload::ServerboundCustomPayload,

View file

@ -30,7 +30,7 @@ pub mod respawn;
pub mod task_pool;
pub use account::{Account, AccountOpts};
pub use azalea_protocol::common::ClientInformation;
pub use azalea_protocol::common::client_information::ClientInformation;
pub use client::{
start_ecs_runner, Client, DefaultPlugins, JoinError, JoinedClientBundle, StartClientOpts,
TickBroadcast,

View file

@ -216,6 +216,8 @@ pub fn process_packet_events(ecs: &mut World) {
})
.unwrap();
}
ClientboundConfigPacket::ServerLinks(_) => {}
ClientboundConfigPacket::CustomReportDetails(_) => {}
}
}
}

View file

@ -1458,7 +1458,7 @@ pub fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::TabList(_) => {}
ClientboundGamePacket::TagQuery(_) => {}
ClientboundGamePacket::TakeItemEntity(_) => {}
ClientboundGamePacket::Bundle(_) => {}
ClientboundGamePacket::BundleDelimiter(_) => {}
ClientboundGamePacket::DamageEvent(_) => {}
ClientboundGamePacket::HurtAnimation(_) => {}
@ -1471,7 +1471,7 @@ pub fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::PongResponse(_) => {}
ClientboundGamePacket::StoreCookie(_) => {}
ClientboundGamePacket::Transfer(_) => {}
ClientboundGamePacket::MoveMinecart(_) => {}
ClientboundGamePacket::MoveMinecartAlongTrack(_) => {}
ClientboundGamePacket::SetHeldSlot(_) => {}
ClientboundGamePacket::SetPlayerInventory(_) => {}
ClientboundGamePacket::ProjectilePower(_) => {}

View file

@ -6,7 +6,7 @@ use azalea_protocol::{
connect::{Connection, ConnectionError, Proxy},
packets::{
handshake::{
s_client_intention::ServerboundClientIntention, ClientboundHandshakePacket,
s_intention::ServerboundIntention, ClientboundHandshakePacket,
ServerboundHandshakePacket,
},
status::{
@ -74,7 +74,7 @@ pub async fn ping_server_with_connection(
mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
) -> Result<ClientboundStatusResponse, PingError> {
// send the client intention packet and switch to the status state
conn.write(ServerboundClientIntention {
conn.write(ServerboundIntention {
protocol_version: PROTOCOL_VERSION,
hostname: address.host.clone(),
port: address.port,

View file

@ -1,6 +1,6 @@
use std::io::{Cursor, Write};
use azalea_buf::{BufReadError, AzBuf, AzaleaRead, AzaleaWrite};
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
/// Represents Java's BitSet, a list of bits.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, AzBuf)]

View file

@ -3,7 +3,7 @@ use std::{
io::{Cursor, Write},
};
use azalea_buf::{BufReadError, AzaleaRead, AzaleaWrite};
use azalea_buf::{AzaleaRead, AzaleaWrite, BufReadError};
#[derive(Hash, Clone, Copy, Debug, PartialEq, Eq)]
pub enum Difficulty {

View file

@ -11,7 +11,7 @@ use std::{
str::FromStr,
};
use azalea_buf::{BufReadError, AzBuf, AzaleaRead, AzaleaWrite};
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

View file

@ -648,7 +648,8 @@ mod tests {
azalea_block::blocks::StoneSlab {
kind: azalea_block::properties::Type::Top,
waterlogged: false,
},
}
.into(),
);
assert!(
block_state.is_some(),
@ -704,7 +705,8 @@ mod tests {
west: azalea_block::properties::WallWest::Low,
up: false,
waterlogged: false,
},
}
.into(),
);
assert!(
block_state.is_some(),
@ -765,7 +767,8 @@ mod tests {
west: azalea_block::properties::WallWest::Low,
up: false,
waterlogged: false,
},
}
.into(),
);
assert!(
block_state.is_some(),

View file

@ -109,14 +109,9 @@ pub fn derive_c_config_packet(input: TokenStream) -> TokenStream {
)
}
#[derive(Debug)]
struct PacketListItem {
module: Ident,
name: Ident,
}
#[derive(Debug)]
struct PacketList {
packets: Vec<PacketListItem>,
packets: Vec<Ident>,
}
impl Parse for PacketList {
@ -124,15 +119,10 @@ impl Parse for PacketList {
let mut packets = vec![];
// example:
// c_change_difficulty::ClientboundChangeDifficultyPacket,
// c_change_difficulty
while let Ok(module) = input.parse::<Ident>() {
input.parse::<Token![::]>()?;
// ClientboundChangeDifficultyPacket
let name = input.parse::<Ident>()?;
packets.push(PacketListItem { module, name });
// change_difficulty,
// keep_alive,
while let Ok(packet_name) = input.parse::<Ident>() {
packets.push(packet_name);
if input.parse::<Token![,]>().is_err() {
break;
}
@ -145,8 +135,8 @@ impl Parse for PacketList {
#[derive(Debug)]
struct DeclareStatePackets {
name: Ident,
serverbound: PacketList,
clientbound: PacketList,
serverbound: PacketList,
}
impl Parse for DeclareStatePackets {
@ -154,26 +144,32 @@ impl Parse for DeclareStatePackets {
let name = input.parse()?;
input.parse::<Token![,]>()?;
let s_token: Ident = input.parse()?;
if s_token != "Serverbound" {
return Err(syn::Error::new(s_token.span(), "Expected `Serverbound`"));
}
input.parse::<Token![=>]>()?;
let content;
bracketed!(content in input);
let serverbound = content.parse()?;
input.parse::<Token![,]>()?;
let c_token: Ident = input.parse()?;
if c_token != "Clientbound" {
return Err(syn::Error::new(c_token.span(), "Expected `Clientbound`"));
let clientbound_token: Ident = input.parse()?;
if clientbound_token != "Clientbound" {
return Err(syn::Error::new(
clientbound_token.span(),
"Expected `Clientbound`",
));
}
input.parse::<Token![=>]>()?;
let content;
bracketed!(content in input);
let clientbound = content.parse()?;
input.parse::<Token![,]>()?;
let serverbound_token: Ident = input.parse()?;
if serverbound_token != "Serverbound" {
return Err(syn::Error::new(
serverbound_token.span(),
"Expected `Serverbound`",
));
}
input.parse::<Token![=>]>()?;
let content;
bracketed!(content in input);
let serverbound = content.parse()?;
Ok(DeclareStatePackets {
name,
serverbound,
@ -185,89 +181,55 @@ impl Parse for DeclareStatePackets {
pub fn declare_state_packets(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeclareStatePackets);
let s_state_name = Ident::new(&format!("Serverbound{}", input.name), input.name.span());
let c_state_name = Ident::new(&format!("Clientbound{}", input.name), input.name.span());
let clientbound_state_name =
Ident::new(&format!("Clientbound{}", input.name), input.name.span());
let serverbound_state_name =
Ident::new(&format!("Serverbound{}", input.name), input.name.span());
let state_name_litstr = syn::LitStr::new(&input.name.to_string(), input.name.span());
let has_s_packets = !input.serverbound.packets.is_empty();
let has_c_packets = !input.clientbound.packets.is_empty();
let has_clientbound_packets = !input.clientbound.packets.is_empty();
let has_serverbound_packets = !input.serverbound.packets.is_empty();
let mut mod_and_use_statements_contents = quote!();
let mut s_enum_contents = quote!();
let mut c_enum_contents = quote!();
let mut s_id_match_contents = quote!();
let mut c_id_match_contents = quote!();
let mut s_write_match_contents = quote!();
let mut c_write_match_contents = quote!();
let mut s_read_match_contents = quote!();
let mut c_read_match_contents = quote!();
let mut clientbound_enum_contents = quote!();
let mut serverbound_enum_contents = quote!();
let mut clientbound_id_match_contents = quote!();
let mut serverbound_id_match_contents = quote!();
let mut clientbound_write_match_contents = quote!();
let mut serverbound_write_match_contents = quote!();
let mut clientbound_read_match_contents = quote!();
let mut serverbound_read_match_contents = quote!();
for (id, PacketListItem { module, name }) in input.serverbound.packets.iter().enumerate() {
for (id, packet_name) in input.clientbound.packets.iter().enumerate() {
let id = id as u32;
let name_litstr = syn::LitStr::new(&name.to_string(), name.span());
let variant_name = variant_name_from(name);
let struct_name = packet_name_to_struct_name(packet_name, "clientbound");
let module_name = packet_name_to_module_name(packet_name, "clientbound");
let variant_name = packet_name_to_variant_name(packet_name);
let packet_name_litstr = syn::LitStr::new(&packet_name.to_string(), packet_name.span());
mod_and_use_statements_contents.extend(quote! {
pub mod #module;
pub use #module::#name;
pub mod #module_name;
pub use #module_name::#struct_name;
});
s_enum_contents.extend(quote! {
#variant_name(#module::#name),
clientbound_enum_contents.extend(quote! {
#variant_name(#module_name::#struct_name),
});
s_id_match_contents.extend(quote! {
#s_state_name::#variant_name(_packet) => #id,
clientbound_id_match_contents.extend(quote! {
#clientbound_state_name::#variant_name(_packet) => #id,
});
s_write_match_contents.extend(quote! {
#s_state_name::#variant_name(packet) => packet.write(buf),
clientbound_write_match_contents.extend(quote! {
#clientbound_state_name::#variant_name(packet) => packet.write(buf),
});
s_read_match_contents.extend(quote! {
clientbound_read_match_contents.extend(quote! {
#id => {
let data = #module::#name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse {
let data = #module_name::#struct_name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse {
source: e,
packet_id: #id,
backtrace: Box::new(std::backtrace::Backtrace::capture()),
packet_name: #name_litstr.to_string(),
})?;
#[cfg(debug_assertions)]
{
let mut leftover = Vec::new();
let _ = std::io::Read::read_to_end(buf, &mut leftover);
if !leftover.is_empty() {
return Err(Box::new(crate::read::ReadPacketError::LeftoverData { packet_name: #name_litstr.to_string(), data: leftover }));
}
}
data
},
});
}
for (id, PacketListItem { module, name }) in input.clientbound.packets.iter().enumerate() {
let id = id as u32;
let name_litstr = syn::LitStr::new(&name.to_string(), name.span());
let variant_name = variant_name_from(name);
mod_and_use_statements_contents.extend(quote! {
pub mod #module;
pub use #module::#name;
});
c_enum_contents.extend(quote! {
#variant_name(#module::#name),
});
c_id_match_contents.extend(quote! {
#c_state_name::#variant_name(_packet) => #id,
});
c_write_match_contents.extend(quote! {
#c_state_name::#variant_name(packet) => packet.write(buf),
});
c_read_match_contents.extend(quote! {
#id => {
let data = #module::#name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse {
source: e,
packet_id: #id,
backtrace: Box::new(std::backtrace::Backtrace::capture()),
packet_name: #name_litstr.to_string(),
packet_name: #packet_name_litstr.to_string(),
})?;
#[cfg(debug_assertions)]
{
@ -277,7 +239,7 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
return Err(
Box::new(
crate::read::ReadPacketError::LeftoverData {
packet_name: #name_litstr.to_string(),
packet_name: #packet_name_litstr.to_string(),
data: leftover
}
)
@ -288,20 +250,62 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
},
});
}
for (id, packet_name) in input.serverbound.packets.iter().enumerate() {
let id = id as u32;
if !has_s_packets {
s_id_match_contents.extend(quote! {
let struct_name = packet_name_to_struct_name(packet_name, "serverbound");
let module_name = packet_name_to_module_name(packet_name, "serverbound");
let variant_name = packet_name_to_variant_name(packet_name);
let packet_name_litstr = syn::LitStr::new(&packet_name.to_string(), packet_name.span());
mod_and_use_statements_contents.extend(quote! {
pub mod #module_name;
pub use #module_name::#struct_name;
});
serverbound_enum_contents.extend(quote! {
#variant_name(#module_name::#struct_name),
});
serverbound_id_match_contents.extend(quote! {
#serverbound_state_name::#variant_name(_packet) => #id,
});
serverbound_write_match_contents.extend(quote! {
#serverbound_state_name::#variant_name(packet) => packet.write(buf),
});
serverbound_read_match_contents.extend(quote! {
#id => {
let data = #module_name::#struct_name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse {
source: e,
packet_id: #id,
backtrace: Box::new(std::backtrace::Backtrace::capture()),
packet_name: #packet_name_litstr.to_string(),
})?;
#[cfg(debug_assertions)]
{
let mut leftover = Vec::new();
let _ = std::io::Read::read_to_end(buf, &mut leftover);
if !leftover.is_empty() {
return Err(Box::new(crate::read::ReadPacketError::LeftoverData { packet_name: #packet_name_litstr.to_string(), data: leftover }));
}
}
data
},
});
}
if !has_serverbound_packets {
serverbound_id_match_contents.extend(quote! {
_ => unreachable!("This enum is empty and can't exist.")
});
s_write_match_contents.extend(quote! {
serverbound_write_match_contents.extend(quote! {
_ => unreachable!("This enum is empty and can't exist.")
});
}
if !has_c_packets {
c_id_match_contents.extend(quote! {
if !has_clientbound_packets {
clientbound_id_match_contents.extend(quote! {
_ => unreachable!("This enum is empty and can't exist.")
});
c_write_match_contents.extend(quote! {
clientbound_write_match_contents.extend(quote! {
_ => unreachable!("This enum is empty and can't exist.")
});
}
@ -310,33 +314,33 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
#mod_and_use_statements_contents
#[derive(Clone, Debug)]
pub enum #s_state_name
where
Self: Sized,
{
#s_enum_contents
}
#[derive(Clone, Debug)]
pub enum #c_state_name
pub enum #clientbound_state_name
where
Self: Sized,
{
#c_enum_contents
#clientbound_enum_contents
}
#[derive(Clone, Debug)]
pub enum #serverbound_state_name
where
Self: Sized,
{
#serverbound_enum_contents
}
};
contents.extend(quote! {
#[allow(unreachable_code)]
impl crate::packets::ProtocolPacket for #s_state_name {
impl crate::packets::ProtocolPacket for #serverbound_state_name {
fn id(&self) -> u32 {
match self {
#s_id_match_contents
#serverbound_id_match_contents
}
}
fn write(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
match self {
#s_write_match_contents
#serverbound_write_match_contents
}
}
@ -344,20 +348,20 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
fn read(
id: u32,
buf: &mut std::io::Cursor<&[u8]>,
) -> Result<#s_state_name, Box<crate::read::ReadPacketError>>
) -> Result<#serverbound_state_name, Box<crate::read::ReadPacketError>>
where
Self: Sized,
{
Ok(match id {
#s_read_match_contents
#serverbound_read_match_contents
_ => return Err(Box::new(crate::read::ReadPacketError::UnknownPacketId { state_name: #state_name_litstr.to_string(), id })),
})
}
}
impl crate::packets::Packet<#s_state_name> for #s_state_name {
impl crate::packets::Packet<#serverbound_state_name> for #serverbound_state_name {
/// No-op, exists so you can pass a packet enum when a Packet<> is expected.
fn into_variant(self) -> #s_state_name {
fn into_variant(self) -> #serverbound_state_name {
self
}
}
@ -365,16 +369,16 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
contents.extend(quote! {
#[allow(unreachable_code)]
impl crate::packets::ProtocolPacket for #c_state_name {
impl crate::packets::ProtocolPacket for #clientbound_state_name {
fn id(&self) -> u32 {
match self {
#c_id_match_contents
#clientbound_id_match_contents
}
}
fn write(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
match self {
#c_write_match_contents
#clientbound_write_match_contents
}
}
@ -382,12 +386,12 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
fn read(
id: u32,
buf: &mut std::io::Cursor<&[u8]>,
) -> Result<#c_state_name, Box<crate::read::ReadPacketError>>
) -> Result<#clientbound_state_name, Box<crate::read::ReadPacketError>>
where
Self: Sized,
{
Ok(match id {
#c_read_match_contents
#clientbound_read_match_contents
_ => return Err(Box::new(crate::read::ReadPacketError::UnknownPacketId { state_name: #state_name_litstr.to_string(), id })),
})
}
@ -407,3 +411,48 @@ fn variant_name_from(name: &syn::Ident) -> syn::Ident {
}
syn::Ident::new(&variant_name, name.span())
}
fn packet_name_to_struct_name(name: &syn::Ident, direction: &str) -> syn::Ident {
let struct_name_snake = format!("{direction}_{name}");
let struct_name = to_camel_case(&struct_name_snake);
syn::Ident::new(&struct_name, name.span())
}
fn packet_name_to_module_name(name: &syn::Ident, direction: &str) -> syn::Ident {
let module_name_snake = format!("{}_{name}", direction.chars().next().unwrap());
let module_name = to_snake_case(&module_name_snake);
syn::Ident::new(&module_name, name.span())
}
fn packet_name_to_variant_name(name: &syn::Ident) -> syn::Ident {
let variant_name = to_camel_case(&name.to_string());
syn::Ident::new(&variant_name, name.span())
}
fn to_camel_case(snake_case: &str) -> String {
let mut camel_case = String::new();
let mut capitalize_next = true;
for c in snake_case.chars() {
if c == '_' {
capitalize_next = true;
} else {
if capitalize_next {
camel_case.push(c.to_ascii_uppercase());
} else {
camel_case.push(c);
}
capitalize_next = false;
}
}
camel_case
}
fn to_snake_case(camel_case: &str) -> String {
let mut snake_case = String::new();
for c in camel_case.chars() {
if c.is_ascii_uppercase() {
snake_case.push('_');
snake_case.push(c.to_ascii_lowercase());
} else {
snake_case.push(c);
}
}
snake_case
}

View file

@ -7,7 +7,7 @@ use azalea_protocol::{
connect::Connection,
packets::{
handshake::{
s_client_intention::ServerboundClientIntention, ClientboundHandshakePacket,
s_intention::ServerboundIntention, ClientboundHandshakePacket,
ServerboundHandshakePacket,
},
login::{s_hello::ServerboundHello, ServerboundLoginPacket},
@ -74,7 +74,7 @@ async fn handle_connection(stream: TcpStream) -> anyhow::Result<()> {
// the server or is going to join the game.
let intent = match conn.read().await {
Ok(packet) => match packet {
ServerboundHandshakePacket::ClientIntention(packet) => {
ServerboundHandshakePacket::Intention(packet) => {
info!(
"New connection: {0}, Version {1}, {2:?}",
ip.ip(),
@ -100,21 +100,17 @@ async fn handle_connection(stream: TcpStream) -> anyhow::Result<()> {
match conn.read().await {
Ok(p) => match p {
ServerboundStatusPacket::StatusRequest(_) => {
conn.write(
ClientboundStatusResponse {
description: PROXY_DESC.into(),
favicon: PROXY_FAVICON.clone(),
players: PROXY_PLAYERS.clone(),
version: PROXY_VERSION.clone(),
enforces_secure_chat: PROXY_SECURE_CHAT,
}
.into(),
)
conn.write(ClientboundStatusResponse {
description: PROXY_DESC.into(),
favicon: PROXY_FAVICON.clone(),
players: PROXY_PLAYERS.clone(),
version: PROXY_VERSION.clone(),
enforces_secure_chat: PROXY_SECURE_CHAT,
})
.await?;
}
ServerboundStatusPacket::PingRequest(p) => {
conn.write(ClientboundPongResponse { time: p.time }.into())
.await?;
conn.write(ClientboundPongResponse { time: p.time }).await?;
break;
}
},
@ -178,7 +174,7 @@ async fn handle_connection(stream: TcpStream) -> anyhow::Result<()> {
async fn transfer(
mut inbound: TcpStream,
intent: ServerboundClientIntention,
intent: ServerboundIntention,
hello: ServerboundHello,
) -> Result<(), Box<dyn Error>> {
let outbound = TcpStream::connect(PROXY_ADDR).await?;
@ -189,10 +185,10 @@ async fn transfer(
// received earlier to the proxy target
let mut outbound_conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket> =
Connection::wrap(outbound);
outbound_conn.write(intent.into()).await?;
outbound_conn.write(intent).await?;
let mut outbound_conn = outbound_conn.login();
outbound_conn.write(hello.into()).await?;
outbound_conn.write(hello).await?;
let mut outbound = outbound_conn.unwrap()?;

View file

@ -1,5 +1,3 @@
//! Some serializable data types that are used by several packets.
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite};
use azalea_core::bitset::FixedBitSet;
use bevy_ecs::component::Component;

View file

@ -0,0 +1,4 @@
//! Some serializable data types that are used by several packets.
pub mod client_information;
pub mod server_links;

View file

@ -0,0 +1,28 @@
use azalea_buf::AzBuf;
use azalea_chat::FormattedText;
#[derive(Clone, Debug, AzBuf)]
pub struct ServerLinkEntry {
pub kind: ServerLinkKind,
pub link: String,
}
#[derive(Clone, Debug, AzBuf)]
pub enum ServerLinkKind {
Known(KnownLinkKind),
Component(FormattedText),
}
#[derive(Clone, Copy, Debug, AzBuf)]
pub enum KnownLinkKind {
BugReport,
CommunityGuidelines,
Support,
Status,
Feedback,
Community,
Website,
Forums,
News,
Announcements,
}

View file

@ -111,6 +111,7 @@ mod tests {
packets::{
game::s_chat::{LastSeenMessagesUpdate, ServerboundChat},
login::{s_hello::ServerboundHello, ServerboundLoginPacket},
Packet,
},
read::{compression_decoder, read_packet},
write::{compression_encoder, serialize_packet, write_packet},
@ -121,10 +122,9 @@ mod tests {
let packet = ServerboundHello {
name: "test".to_string(),
profile_id: Uuid::nil(),
}
.into();
};
let mut stream = Vec::new();
write_packet(&packet, &mut stream, None, &mut None)
write_packet(&packet.into_variant(), &mut stream, None, &mut None)
.await
.unwrap();
@ -146,7 +146,7 @@ mod tests {
name: "test".to_string(),
profile_id: Uuid::nil(),
}
.into();
.into_variant();
let mut stream = Vec::new();
write_packet(&packet, &mut stream, None, &mut None)
.await
@ -170,13 +170,16 @@ mod tests {
async fn test_read_long_compressed_chat() {
let compression_threshold = 256;
let buf = serialize_packet(&ServerboundChat {
message: "a".repeat(256),
timestamp: 0,
salt: 0,
signature: None,
last_seen_messages: LastSeenMessagesUpdate::default(),
})
let buf = serialize_packet(
&ServerboundChat {
message: "a".repeat(256),
timestamp: 0,
salt: 0,
signature: None,
last_seen_messages: LastSeenMessagesUpdate::default(),
}
.into_variant(),
)
.unwrap();
let buf = compression_encoder(&buf, compression_threshold).unwrap();

View file

@ -0,0 +1,9 @@
use std::collections::HashMap;
use azalea_buf::AzBuf;
use azalea_protocol_macros::ClientboundConfigPacket;
#[derive(Clone, Debug, AzBuf, ClientboundConfigPacket)]
pub struct ClientboundCustomReportDetails {
pub details: HashMap<String, String>,
}

View file

@ -0,0 +1,9 @@
use azalea_buf::AzBuf;
use azalea_protocol_macros::ClientboundConfigPacket;
use crate::common::server_links::ServerLinkEntry;
#[derive(Clone, Debug, AzBuf, ClientboundConfigPacket)]
pub struct ClientboundServerLinks {
pub links: Vec<ServerLinkEntry>,
}

View file

@ -1,32 +1,36 @@
// NOTE: This file is generated automatically by codegen/packet.py.
// Don't edit it directly!
use azalea_protocol_macros::declare_state_packets;
declare_state_packets!(
ConfigPacket,
Serverbound => [
s_client_information::ServerboundClientInformation,
s_cookie_response::ServerboundCookieResponse,
s_custom_payload::ServerboundCustomPayload,
s_finish_configuration::ServerboundFinishConfiguration,
s_keep_alive::ServerboundKeepAlive,
s_pong::ServerboundPong,
s_resource_pack::ServerboundResourcePack,
s_select_known_packs::ServerboundSelectKnownPacks,
],
declare_state_packets!(ConfigPacket,
Clientbound => [
c_cookie_request::ClientboundCookieRequest,
c_custom_payload::ClientboundCustomPayload,
c_disconnect::ClientboundDisconnect,
c_finish_configuration::ClientboundFinishConfiguration,
c_keep_alive::ClientboundKeepAlive,
c_ping::ClientboundPing,
c_reset_chat::ClientboundResetChat,
c_registry_data::ClientboundRegistryData,
c_resource_pack_pop::ClientboundResourcePackPop,
c_resource_pack_push::ClientboundResourcePackPush,
c_store_cookie::ClientboundStoreCookie,
c_transfer::ClientboundTransfer,
c_update_enabled_features::ClientboundUpdateEnabledFeatures,
c_update_tags::ClientboundUpdateTags,
c_select_known_packs::ClientboundSelectKnownPacks,
keep_alive,
registry_data,
reset_chat,
resource_pack_pop,
resource_pack_push,
select_known_packs,
server_links,
disconnect,
finish_configuration,
ping,
cookie_request,
update_enabled_features,
update_tags,
transfer,
store_cookie,
custom_payload,
custom_report_details,
],
Serverbound => [
keep_alive,
resource_pack,
select_known_packs,
finish_configuration,
client_information,
cookie_response,
pong,
custom_payload,
]
);

View file

@ -1,7 +1,7 @@
use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundConfigPacket;
use crate::common::ClientInformation;
use crate::common::client_information::ClientInformation;
#[derive(Clone, Debug, AzBuf, ServerboundConfigPacket, PartialEq, Eq)]
pub struct ServerboundClientInformation {

View file

@ -2,4 +2,4 @@ use azalea_buf::AzBuf;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundBundle {}
pub struct ClientboundBundleDelimiter;

View file

@ -3,7 +3,7 @@ use azalea_core::position::Vec3;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundMoveMinecart {
pub struct ClientboundMoveMinecartAlongTrack {
#[var]
pub entity_id: u32,
pub lerp_steps: Vec<MinecartStep>,

View file

@ -1,34 +1,9 @@
use azalea_buf::AzBuf;
use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket;
use crate::common::server_links::ServerLinkEntry;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundServerLinks {
pub links: Vec<ServerLinkEntry>,
}
#[derive(Clone, Debug, AzBuf)]
pub struct ServerLinkEntry {
pub kind: ServerLinkKind,
pub link: String,
}
#[derive(Clone, Debug, AzBuf)]
pub enum ServerLinkKind {
Known(KnownLinkKind),
Component(FormattedText),
}
#[derive(Clone, Copy, Debug, AzBuf)]
pub enum KnownLinkKind {
BugReport,
CommunityGuidelines,
Support,
Status,
Feedback,
Community,
Website,
Forums,
News,
Announcements,
}

View file

@ -1,202 +1,204 @@
// NOTE: This file is generated automatically by codegen/packet.py.
// Don't edit it directly!
use azalea_protocol_macros::declare_state_packets;
// see GameProtocols.java in the decompiled vanilla source
declare_state_packets!(
GamePacket,
Serverbound => [
s_accept_teleportation::ServerboundAcceptTeleportation,
s_block_entity_tag_query::ServerboundBlockEntityTagQuery,
s_select_bundle_item::ServerboundSelectBundleItem,
s_change_difficulty::ServerboundChangeDifficulty,
s_chat_ack::ServerboundChatAck,
s_chat_command::ServerboundChatCommand,
s_chat_command_signed::ServerboundChatCommandSigned,
s_chat::ServerboundChat,
s_chat_session_update::ServerboundChatSessionUpdate,
s_chunk_batch_received::ServerboundChunkBatchReceived,
s_client_command::ServerboundClientCommand,
s_client_tick_end::ServerboundTickEnd,
s_client_information::ServerboundClientInformation,
s_command_suggestion::ServerboundCommandSuggestion,
s_configuration_acknowledged::ServerboundConfigurationAcknowledged,
s_container_button_click::ServerboundContainerButtonClick,
s_container_click::ServerboundContainerClick,
s_container_close::ServerboundContainerClose,
s_container_slot_state_changed::ServerboundContainerSlotStateChanged,
s_cookie_response::ServerboundCookieResponse,
s_custom_payload::ServerboundCustomPayload,
s_debug_sample_subscription::ServerboundDebugSampleSubscription,
s_edit_book::ServerboundEditBook,
s_entity_tag_query::ServerboundEntityTagQuery,
s_interact::ServerboundInteract,
s_jigsaw_generate::ServerboundJigsawGenerate,
s_keep_alive::ServerboundKeepAlive,
s_lock_difficulty::ServerboundLockDifficulty,
s_move_player_pos::ServerboundMovePlayerPos,
s_move_player_pos_rot::ServerboundMovePlayerPosRot,
s_move_player_rot::ServerboundMovePlayerRot,
s_move_player_status_only::ServerboundMovePlayerStatusOnly,
s_move_vehicle::ServerboundMoveVehicle,
s_paddle_boat::ServerboundPaddleBoat,
s_pick_item::ServerboundPickItem,
s_ping_request::ServerboundPingRequest,
s_place_recipe::ServerboundPlaceRecipe,
s_player_abilities::ServerboundPlayerAbilities,
s_player_action::ServerboundPlayerAction,
s_player_command::ServerboundPlayerCommand,
s_player_input::ServerboundPlayerInput,
s_pong::ServerboundPong,
s_recipe_book_change_settings::ServerboundRecipeBookChangeSettings,
s_recipe_book_seen_recipe::ServerboundRecipeBookSeenRecipe,
s_rename_item::ServerboundRenameItem,
s_resource_pack::ServerboundResourcePack,
s_seen_advancements::ServerboundSeenAdvancements,
s_select_trade::ServerboundSelectTrade,
s_set_beacon::ServerboundSetBeacon,
s_set_carried_item::ServerboundSetCarriedItem,
s_set_command_block::ServerboundSetCommandBlock,
s_set_command_minecart::ServerboundSetCommandMinecart,
s_set_creative_mode_slot::ServerboundSetCreativeModeSlot,
s_set_jigsaw_block::ServerboundSetJigsawBlock,
s_set_structure_block::ServerboundSetStructureBlock,
s_sign_update::ServerboundSignUpdate,
s_swing::ServerboundSwing,
s_teleport_to_entity::ServerboundTeleportToEntity,
s_use_item_on::ServerboundUseItemOn,
s_use_item::ServerboundUseItem,
],
declare_state_packets!(GamePacket,
Clientbound => [
c_bundle::ClientboundBundle,
c_add_entity::ClientboundAddEntity,
c_add_experience_orb::ClientboundAddExperienceOrb,
c_animate::ClientboundAnimate,
c_award_stats::ClientboundAwardStats,
c_block_changed_ack::ClientboundBlockChangedAck,
c_block_destruction::ClientboundBlockDestruction,
c_block_entity_data::ClientboundBlockEntityData,
c_block_event::ClientboundBlockEvent,
c_block_update::ClientboundBlockUpdate,
c_boss_event::ClientboundBossEvent,
c_change_difficulty::ClientboundChangeDifficulty,
c_chunk_batch_finished::ClientboundChunkBatchFinished,
c_chunk_batch_start::ClientboundChunkBatchStart,
c_chunks_biomes::ClientboundChunksBiomes,
c_clear_titles::ClientboundClearTitles,
c_command_suggestions::ClientboundCommandSuggestions,
c_commands::ClientboundCommands,
c_container_close::ClientboundContainerClose,
c_container_set_content::ClientboundContainerSetContent,
c_container_set_data::ClientboundContainerSetData,
c_container_set_slot::ClientboundContainerSetSlot,
c_cookie_request::ClientboundCookieRequest,
c_cooldown::ClientboundCooldown,
c_custom_chat_completions::ClientboundCustomChatCompletions,
c_custom_payload::ClientboundCustomPayload,
c_damage_event::ClientboundDamageEvent,
c_debug_sample::ClientboundDebugSample,
c_delete_chat::ClientboundDeleteChat,
c_disconnect::ClientboundDisconnect,
c_disguised_chat::ClientboundDisguisedChat,
c_entity_event::ClientboundEntityEvent,
c_entity_position_sync::ClientboundEntityPositionSync,
c_explode::ClientboundExplode,
c_forget_level_chunk::ClientboundForgetLevelChunk,
c_game_event::ClientboundGameEvent,
c_horse_screen_open::ClientboundHorseScreenOpen,
c_hurt_animation::ClientboundHurtAnimation,
c_initialize_border::ClientboundInitializeBorder,
c_keep_alive::ClientboundKeepAlive,
c_level_chunk_with_light::ClientboundLevelChunkWithLight,
c_level_event::ClientboundLevelEvent,
c_level_particles::ClientboundLevelParticles,
c_light_update::ClientboundLightUpdate,
c_login::ClientboundLogin,
c_map_item_data::ClientboundMapItemData,
c_merchant_offers::ClientboundMerchantOffers,
c_move_entity_pos::ClientboundMoveEntityPos,
c_move_entity_pos_rot::ClientboundMoveEntityPosRot,
c_move_minecart::ClientboundMoveMinecart,
c_move_entity_rot::ClientboundMoveEntityRot,
c_move_vehicle::ClientboundMoveVehicle,
c_open_book::ClientboundOpenBook,
c_open_screen::ClientboundOpenScreen,
c_open_sign_editor::ClientboundOpenSignEditor,
c_ping::ClientboundPing,
c_pong_response::ClientboundPongResponse,
c_place_ghost_recipe::ClientboundPlaceGhostRecipe,
c_player_abilities::ClientboundPlayerAbilities,
c_player_chat::ClientboundPlayerChat,
c_player_combat_end::ClientboundPlayerCombatEnd,
c_player_combat_enter::ClientboundPlayerCombatEnter,
c_player_combat_kill::ClientboundPlayerCombatKill,
c_player_info_remove::ClientboundPlayerInfoRemove,
c_player_info_update::ClientboundPlayerInfoUpdate,
c_player_look_at::ClientboundPlayerLookAt,
c_player_position::ClientboundPlayerPosition,
c_player_rotation::ClientboundPlayerRotation,
c_recipe_book_add::ClientboundRecipeBookAdd,
c_recipe_book_remove::ClientboundRecipeBookRemove,
c_recipe_book_settings::ClientboundRecipeBookSettings,
c_remove_entities::ClientboundRemoveEntities,
c_remove_mob_effect::ClientboundRemoveMobEffect,
c_reset_score::ClientboundResetScore,
c_resource_pack_pop::ClientboundResourcePackPop,
c_resource_pack_push::ClientboundResourcePackPush,
c_respawn::ClientboundRespawn,
c_rotate_head::ClientboundRotateHead,
c_section_blocks_update::ClientboundSectionBlocksUpdate,
c_select_advancements_tab::ClientboundSelectAdvancementsTab,
c_server_data::ClientboundServerData,
c_set_action_bar_text::ClientboundSetActionBarText,
c_set_border_center::ClientboundSetBorderCenter,
c_set_border_lerp_size::ClientboundSetBorderLerpSize,
c_set_border_size::ClientboundSetBorderSize,
c_set_border_warning_delay::ClientboundSetBorderWarningDelay,
c_set_border_warning_distance::ClientboundSetBorderWarningDistance,
c_set_camera::ClientboundSetCamera,
c_set_chunk_cache_center::ClientboundSetChunkCacheCenter,
c_set_chunk_cache_radius::ClientboundSetChunkCacheRadius,
c_set_cursor_item::ClientboundSetCursorItem,
c_set_default_spawn_position::ClientboundSetDefaultSpawnPosition,
c_set_display_objective::ClientboundSetDisplayObjective,
c_set_entity_data::ClientboundSetEntityData,
c_set_entity_link::ClientboundSetEntityLink,
c_set_entity_motion::ClientboundSetEntityMotion,
c_set_equipment::ClientboundSetEquipment,
c_set_experience::ClientboundSetExperience,
c_set_health::ClientboundSetHealth,
c_set_held_slot::ClientboundSetHeldSlot,
c_set_objective::ClientboundSetObjective,
c_set_passengers::ClientboundSetPassengers,
c_set_player_inventory::ClientboundSetPlayerInventory,
c_set_player_team::ClientboundSetPlayerTeam,
c_set_score::ClientboundSetScore,
c_set_simulation_distance::ClientboundSetSimulationDistance,
c_set_subtitle_text::ClientboundSetSubtitleText,
c_set_time::ClientboundSetTime,
c_set_title_text::ClientboundSetTitleText,
c_set_titles_animation::ClientboundSetTitlesAnimation,
c_sound_entity::ClientboundSoundEntity,
c_sound::ClientboundSound,
c_start_configuration::ClientboundStartConfiguration,
c_stop_sound::ClientboundStopSound,
c_store_cookie::ClientboundStoreCookie,
c_system_chat::ClientboundSystemChat,
c_tab_list::ClientboundTabList,
c_tag_query::ClientboundTagQuery,
c_take_item_entity::ClientboundTakeItemEntity,
c_teleport_entity::ClientboundTeleportEntity,
c_ticking_state::ClientboundTickingState,
c_ticking_step::ClientboundTickingStep,
c_transfer::ClientboundTransfer,
c_update_advancements::ClientboundUpdateAdvancements,
c_update_attributes::ClientboundUpdateAttributes,
c_update_mob_effect::ClientboundUpdateMobEffect,
c_update_recipes::ClientboundUpdateRecipes,
c_update_tags::ClientboundUpdateTags,
c_projectile_power::ClientboundProjectilePower,
c_custom_report_details::ClientboundCustomReportDetails,
c_server_links::ClientboundServerLinks
damage_event,
game_event,
map_item_data,
tab_list,
tag_query,
take_item_entity,
add_entity,
add_experience_orb,
debug_sample,
delete_chat,
keep_alive,
level_chunk_with_light,
level_event,
level_particles,
merchant_offers,
recipe_book_add,
recipe_book_remove,
recipe_book_settings,
remove_entities,
remove_mob_effect,
reset_score,
resource_pack_pop,
resource_pack_push,
respawn,
section_blocks_update,
select_advancements_tab,
server_data,
server_links,
set_action_bar_text,
set_border_center,
set_border_lerp_size,
set_border_size,
set_border_warning_delay,
set_border_warning_distance,
set_camera,
set_chunk_cache_center,
set_chunk_cache_radius,
set_cursor_item,
set_default_spawn_position,
set_display_objective,
set_entity_data,
set_entity_link,
set_entity_motion,
set_equipment,
set_experience,
set_health,
set_held_slot,
set_objective,
set_passengers,
set_player_inventory,
set_player_team,
set_score,
set_simulation_distance,
set_subtitle_text,
set_time,
set_title_text,
set_titles_animation,
teleport_entity,
change_difficulty,
chunk_batch_finished,
chunk_batch_start,
chunks_biomes,
disconnect,
disguised_chat,
light_update,
ping,
ticking_state,
ticking_step,
block_changed_ack,
block_destruction,
block_entity_data,
block_event,
block_update,
clear_titles,
place_ghost_recipe,
player_abilities,
player_chat,
player_combat_end,
player_combat_enter,
player_combat_kill,
player_info_remove,
player_info_update,
player_look_at,
player_position,
player_rotation,
animate,
entity_event,
entity_position_sync,
initialize_border,
boss_event,
command_suggestions,
commands,
container_close,
container_set_content,
container_set_data,
container_set_slot,
cookie_request,
cooldown,
forget_level_chunk,
horse_screen_open,
login,
move_entity_pos,
move_entity_pos_rot,
move_entity_rot,
move_minecart_along_track,
move_vehicle,
pong_response,
rotate_head,
sound,
sound_entity,
open_book,
open_screen,
open_sign_editor,
update_advancements,
update_attributes,
update_mob_effect,
update_recipes,
update_tags,
projectile_power,
transfer,
start_configuration,
stop_sound,
store_cookie,
bundle_delimiter,
custom_chat_completions,
custom_payload,
custom_report_details,
hurt_animation,
award_stats,
explode,
system_chat,
],
Serverbound => [
paddle_boat,
accept_teleportation,
edit_book,
debug_sample_subscription,
keep_alive,
recipe_book_change_settings,
recipe_book_seen_recipe,
rename_item,
resource_pack,
seen_advancements,
select_trade,
set_beacon,
set_carried_item,
set_command_block,
set_command_minecart,
set_creative_mode_slot,
set_jigsaw_block,
set_structure_block,
teleport_to_entity,
change_difficulty,
chat,
chat_ack,
chat_command,
chat_command_signed,
chat_session_update,
chunk_batch_received,
jigsaw_generate,
pick_item_from_block,
pick_item_from_entity,
ping_request,
sign_update,
block_entity_tag_query,
client_command,
client_information,
client_tick_end,
place_recipe,
player_abilities,
player_action,
player_command,
player_input,
player_loaded,
entity_tag_query,
interact,
command_suggestion,
configuration_acknowledged,
container_button_click,
container_click,
container_close,
container_slot_state_changed,
cookie_response,
lock_difficulty,
move_player_pos,
move_player_pos_rot,
move_player_rot,
move_player_status_only,
move_vehicle,
pong,
use_item,
use_item_on,
bundle_item_selected,
custom_payload,
swing,
]
);

View file

@ -2,7 +2,7 @@ use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundGamePacket;
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
pub struct ServerboundSelectBundleItem {
pub struct ServerboundBundleItemSelected {
#[var]
pub slot_id: i32,
#[var]

View file

@ -1,7 +1,7 @@
use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundGamePacket;
use crate::common::ClientInformation;
use crate::common::client_information::ClientInformation;
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
pub struct ServerboundClientInformation {

View file

@ -2,4 +2,4 @@ use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundGamePacket;
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
pub struct ServerboundTickEnd {}
pub struct ServerboundClientTickEnd {}

View file

@ -2,7 +2,7 @@ use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundGamePacket;
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
pub struct ServerboundPickItem {
pub struct ServerboundPickItemFromBlock {
#[var]
pub slot: u32,
}

View file

@ -0,0 +1,9 @@
use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundGamePacket;
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
pub struct ServerboundPickItemFromEntity {
#[var]
pub id: u32,
pub include_data: bool,
}

View file

@ -0,0 +1,5 @@
use azalea_buf::AzBuf;
use azalea_protocol_macros::ServerboundGamePacket;
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
pub struct ServerboundPlayerLoaded;

View file

@ -1,9 +1,12 @@
// NOTE: This file is generated automatically by codegen/packet.py.
// Don't edit it directly!
use azalea_protocol_macros::declare_state_packets;
declare_state_packets!(
HandshakePacket,
Serverbound => [
s_client_intention::ServerboundClientIntention,
declare_state_packets!(HandshakePacket,
Clientbound => [
],
Clientbound => []
Serverbound => [
intention,
]
);

View file

@ -6,7 +6,7 @@ use azalea_protocol_macros::ServerboundHandshakePacket;
use crate::packets::ClientIntention;
#[derive(Hash, Clone, Debug, AzBuf, ServerboundHandshakePacket)]
pub struct ServerboundClientIntention {
pub struct ServerboundIntention {
#[var]
pub protocol_version: i32,
pub hostname: String,

View file

@ -1,20 +1,22 @@
// NOTE: This file is generated automatically by codegen/packet.py.
// Don't edit it directly!
use azalea_protocol_macros::declare_state_packets;
declare_state_packets!(
LoginPacket,
Serverbound => [
s_hello::ServerboundHello,
s_key::ServerboundKey,
s_custom_query_answer::ServerboundCustomQueryAnswer,
s_login_acknowledged::ServerboundLoginAcknowledged,
s_cookie_response::ServerboundCookieResponse,
],
declare_state_packets!(LoginPacket,
Clientbound => [
c_login_disconnect::ClientboundLoginDisconnect,
c_hello::ClientboundHello,
c_login_finished::ClientboundLoginFinished,
c_login_compression::ClientboundLoginCompression,
c_custom_query::ClientboundCustomQuery,
c_cookie_request::ClientboundCookieRequest,
hello,
cookie_request,
login_compression,
login_disconnect,
login_finished,
custom_query,
],
Serverbound => [
hello,
key,
cookie_response,
login_acknowledged,
custom_query_answer,
]
);

View file

@ -1,13 +1,15 @@
// NOTE: This file is generated automatically by codegen/packet.py.
// Don't edit it directly!
use azalea_protocol_macros::declare_state_packets;
declare_state_packets!(
StatusPacket,
Serverbound => [
s_status_request::ServerboundStatusRequest,
s_ping_request::ServerboundPingRequest,
],
declare_state_packets!(StatusPacket,
Clientbound => [
c_status_response::ClientboundStatusResponse,
c_pong_response::ClientboundPongResponse,
pong_response,
status_response,
],
Serverbound => [
ping_request,
status_request,
]
);

View file

@ -8,7 +8,7 @@ use std::{
};
use azalea_block::BlockState;
use azalea_buf::{BufReadError, AzaleaRead, AzaleaWrite};
use azalea_buf::{AzaleaRead, AzaleaWrite, BufReadError};
use azalea_core::position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
use nohash_hasher::IntMap;
use parking_lot::RwLock;

18
codegen/genpackets.py Executable file
View file

@ -0,0 +1,18 @@
import lib.code.version
import lib.code.packet
import lib.code.utils
import lib.download
import lib.extract
def generate():
version_id = lib.code.version.get_version_id()
packets_report = lib.extract.get_packets_report(version_id)
lib.code.packet.set_packets(packets_report)
lib.code.utils.fmt()
print('Done!')
if __name__ == '__main__':
generate()

View file

@ -9,179 +9,80 @@ import re
def make_packet_mod_rs_line(packet_id: int, packet_class_name: str):
return f' {padded_hex(packet_id)}: {to_snake_case(packet_class_name)}::{to_camel_case(packet_class_name)},'
MOJMAP_TO_AZALEA_STATE_NAME_MAPPING = {
# shorter name, i like it more
'configuration': 'config',
# in the files mojang calls the directory "game" so we do that too
'play': 'game'
}
AZALEA_TO_MOJMAP_STATE_NAME_MAPPING = {v: k for k, v in MOJMAP_TO_AZALEA_STATE_NAME_MAPPING.items()}
def fix_state(state: str):
return {'PLAY': 'game'}.get(state, state.lower())
def generate_packet(packets_report, packet_name, direction, state):
mojmap_state = AZALEA_TO_MOJMAP_STATE_NAME_MAPPING.get(state, state)
_packet_report = packets_report[mojmap_state][direction]['minecraft:' + packet_name]
code = []
uses = set()
def generate_packet(burger_packets, mappings: Mappings, target_packet_id, target_packet_direction, target_packet_state):
for packet in burger_packets.values():
if packet['id'] != target_packet_id:
continue
packet_derive_name = f'{to_camel_case(direction)}{to_camel_case(state)}Packet'
direction = packet['direction'].lower() # serverbound or clientbound
state = fix_state(packet['state'])
packet_struct_name = to_camel_case(f'{direction}_{packet_name}')
packet_module_name = f'{direction[0]}_{packet_name}'
if state != target_packet_state or direction != target_packet_direction:
continue
code.append(f'use azalea_buf::AzBuf;')
code.append(f'use azalea_protocol_macros::{packet_derive_name};')
code.append('')
code.append(
f'#[derive(Clone, Debug, AzBuf, {packet_derive_name})]')
code.append(
f'pub struct {packet_struct_name} {{')
code.append(' TODO')
code.append('}')
generated_packet_code = []
uses = set()
extra_code = []
print(code)
write_packet_file(state, packet_module_name, '\n'.join(code))
packet_derive_name = f'{to_camel_case(direction)}{to_camel_case(state)}Packet'
generated_packet_code.append(
f'#[derive(Clone, Debug, AzBuf, {packet_derive_name})]')
uses.add(f'azalea_protocol_macros::{packet_derive_name}')
uses.add(f'azalea_buf::AzBuf')
obfuscated_class_name = packet['class'].split('.')[0]
class_name = mappings.get_class(
obfuscated_class_name).split('.')[-1]
if '$' in class_name:
class_name, extra_part = class_name.split('$')
if class_name.endswith('Packet'):
class_name = class_name[:-
len('Packet')] + extra_part + 'Packet'
generated_packet_code.append(
f'pub struct {to_camel_case(class_name)} {{')
# call burger_instruction_to_code for each instruction
i = -1
instructions = packet.get('instructions', [])
while (i + 1) < len(instructions):
i += 1
if instructions[i]['operation'] == 'write':
skip = burger_instruction_to_code(
instructions, i, generated_packet_code, mappings, obfuscated_class_name, uses, extra_code)
if skip:
i += skip
else:
generated_packet_code.append(f'// TODO: {instructions[i]}')
generated_packet_code.append('}')
if uses:
# empty line before the `use` statements
generated_packet_code.insert(0, '')
for use in uses:
generated_packet_code.insert(0, f'use {use};')
for line in extra_code:
generated_packet_code.append(line)
print(generated_packet_code)
write_packet_file(state, to_snake_case(class_name),
'\n'.join(generated_packet_code))
print()
# this won't handle writing to the packets/{state}/mod.rs file since we'd need to know the full packet list
def set_packets(packets_report):
for mojmap_state in packets_report:
state = MOJMAP_TO_AZALEA_STATE_NAME_MAPPING.get(mojmap_state, mojmap_state)
mod_rs_dir = get_dir_location(
f'../azalea-protocol/src/packets/{state}/mod.rs')
with open(mod_rs_dir, 'r') as f:
mod_rs = f.read().splitlines()
pub_mod_line = f'pub mod {to_snake_case(class_name)};'
if pub_mod_line not in mod_rs:
mod_rs.insert(0, pub_mod_line)
packet_mod_rs_line = make_packet_mod_rs_line(
packet['id'], class_name)
serverbound_packets = packet_direction_report_to_packet_names(packets_report[mojmap_state]['serverbound'])
clientbound_packets = packet_direction_report_to_packet_names(packets_report[mojmap_state].get('clientbound', {}))
in_serverbound = False
in_clientbound = False
for i, line in enumerate(mod_rs):
if line.strip() == 'Serverbound => {':
in_serverbound = True
continue
elif line.strip() == 'Clientbound => {':
in_clientbound = True
continue
elif line.strip() in ('}', '},'):
if (in_serverbound and direction == 'serverbound') or (in_clientbound and direction == 'clientbound'):
mod_rs.insert(i, packet_mod_rs_line)
break
in_serverbound = in_clientbound = False
continue
code = []
code.append('// NOTE: This file is generated automatically by codegen/packet.py.')
code.append("// Don't edit it directly!")
code.append('')
code.append('use azalea_protocol_macros::declare_state_packets;')
code.append('')
code.append(f'declare_state_packets!({to_camel_case(state)}Packet,')
code.append(' Clientbound => [')
for packet_name in clientbound_packets:
code.append(f' {packet_name},')
code.append(' ],')
code.append(' Serverbound => [')
for packet_name in serverbound_packets:
code.append(f' {packet_name},')
code.append(' ]')
code.append(');')
code.append('')
if line.strip() == '' or line.strip().startswith('//') or (not in_serverbound and direction == 'serverbound') or (not in_clientbound and direction == 'clientbound'):
continue
line_packet_id_hex = line.strip().split(':')[0]
assert line_packet_id_hex.startswith('0x')
line_packet_id = int(line_packet_id_hex[2:], 16)
if line_packet_id > packet['id']:
mod_rs.insert(i, packet_mod_rs_line)
break
with open(mod_rs_dir, 'w') as f:
f.write('\n'.join(mod_rs))
def set_packets(packet_ids: list[int], packet_class_names: list[str], direction: str, state: str):
assert len(packet_ids) == len(packet_class_names)
# ids are repeated
assert len(packet_ids) == len(set(packet_ids))
# sort the packets by id
packet_ids, packet_class_names = [list(x) for x in zip(
*sorted(zip(packet_ids, packet_class_names), key=lambda pair: pair[0]))] # type: ignore
mod_rs_dir = get_dir_location(
f'../azalea-protocol/src/packets/{state}/mod.rs')
with open(mod_rs_dir, 'r') as f:
mod_rs = f.read().splitlines()
new_mod_rs = []
required_modules = []
ignore_lines = False
for line in mod_rs:
if line.strip() == 'Serverbound => {':
new_mod_rs.append(line)
if direction == 'serverbound':
ignore_lines = True
for packet_id, packet_class_name in zip(packet_ids, packet_class_names):
new_mod_rs.append(
make_packet_mod_rs_line(packet_id, packet_class_name)
)
required_modules.append(packet_class_name)
else:
ignore_lines = False
continue
elif line.strip() == 'Clientbound => {':
new_mod_rs.append(line)
if direction == 'clientbound':
ignore_lines = True
for packet_id, packet_class_name in zip(packet_ids, packet_class_names):
new_mod_rs.append(
make_packet_mod_rs_line(packet_id, packet_class_name)
)
required_modules.append(packet_class_name)
else:
ignore_lines = False
continue
elif line.strip() in ('}', '},'):
ignore_lines = False
elif line.strip().startswith('pub mod '):
continue
if not ignore_lines:
new_mod_rs.append(line)
# 0x00: c_status_response::ClientboundStatusResponsePacket,
if line.strip().startswith('0x'):
required_modules.append(
line.strip().split(':')[1].split('::')[0].strip())
for i, required_module in enumerate(required_modules):
if required_module not in mod_rs:
new_mod_rs.insert(i, f'pub mod {required_module};')
with open(mod_rs_dir, 'w') as f:
f.write('\n'.join(new_mod_rs))
with open(mod_rs_dir, 'w') as f:
f.write('\n'.join(code))
def packet_direction_report_to_packet_names(report):
name_to_id = {}
for resource_location, packet in report.items():
packet_id = packet['protocol_id']
name_to_id[resource_location.split(':')[-1]] = packet_id
names_sorted = [name for name in sorted(name_to_id.keys(), key=lambda item: item[1])]
return names_sorted
def get_packets(direction: str, state: str):
mod_rs_dir = get_dir_location(

View file

@ -166,8 +166,8 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst
return field_type_rs, is_var, uses, extra_code
def write_packet_file(state, packet_name_snake_case, code):
with open(get_dir_location(f'../azalea-protocol/src/packets/{state}/{packet_name_snake_case}.rs'), 'w') as f:
def write_packet_file(state, packet_module_name, code):
with open(get_dir_location(f'../azalea-protocol/src/packets/{state}/{packet_module_name}.rs'), 'w') as f:
f.write(code)

View file

@ -1,7 +1,7 @@
# Extracting data from the Minecraft jars
from typing import TYPE_CHECKING
from lib.download import get_mappings_for_version, get_server_jar, get_burger, get_client_jar, get_pixlyzer, get_yarn_data, get_fabric_api_versions, get_fabric_loader_versions
from lib.download import get_server_jar, get_burger, get_client_jar, get_pixlyzer, get_yarn_data, get_fabric_api_versions, get_fabric_loader_versions
from lib.utils import get_dir_location, to_camel_case, upper_first_letter
from zipfile import ZipFile
import subprocess
@ -23,17 +23,16 @@ def generate_data_from_server_jar(version_id: str):
def get_block_states_report(version_id: str):
generate_data_from_server_jar(version_id)
with open(get_dir_location(f'__cache__/generated-{version_id}/reports/blocks.json'), 'r') as f:
return json.load(f)
return get_report(version_id, 'blocks')
def get_registries_report(version_id: str):
return get_report(version_id, 'registries')
def get_packets_report(version_id: str):
return get_report(version_id, 'packets')
def get_report(version_id: str, name: str):
generate_data_from_server_jar(version_id)
with open(get_dir_location(f'__cache__/generated-{version_id}/reports/registries.json'), 'r') as f:
with open(get_dir_location(f'__cache__/generated-{version_id}/reports/{name}.json'), 'r') as f:
return json.load(f)
def get_registry_tags(version_id: str, name: str):
generate_data_from_server_jar(version_id)
tags_directory = get_dir_location(f'__cache__/generated-{version_id}/data/minecraft/tags/{name}')

View file

@ -5,18 +5,20 @@ import lib.download
import lib.extract
import sys
version_id = lib.code.version.get_version_id()
def generate():
version_id = lib.code.version.get_version_id()
mappings = lib.download.get_mappings_for_version(version_id)
burger_data = lib.extract.get_burger_data_for_version(version_id)
packets_report = lib.extract.get_packets_report(version_id)
burger_packets_data = burger_data[0]['packets']['packet']
packet_id, direction, state = int(sys.argv[1], 0), sys.argv[2], sys.argv[3]
print(
f'Generating code for packet id: {packet_id} with direction {direction} and state {state}')
lib.code.packet.generate_packet(burger_packets_data, mappings,
packet_id, direction, state)
packet_id, direction, state = sys.argv[1], sys.argv[2], sys.argv[3]
print(
f'Generating code for packet id: {packet_id} with direction {direction} and state {state}')
lib.code.packet.generate_packet(packets_report, packet_id, direction, state)
lib.code.packet.set_packets(packets_report)
lib.code.utils.fmt()
lib.code.utils.fmt()
print('Done!')
print('Done!')
if __name__ == '__main__':
generate()