feat: 1.21.7-1.21.11 support

Its works, but block state ids are currently not mapped, meaning that when using the current default world gen the client mostly will disconnect due to a not found block state id, vanilla version compatible worlds should work
This commit is contained in:
Alexander Medvedev 2026-01-25 23:08:28 +01:00
parent 232bf29d07
commit 186ad2edea
174 changed files with 842 additions and 495 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,96 @@
{
"FLAGS": 0,
"AIR": 1,
"CUSTOM_NAME": 2,
"NAME_VISIBLE": 3,
"SILENT": 4,
"NO_GRAVITY": 5,
"POSE": 6,
"FROZEN_TICKS": 7,
"LIVING_FLAGS": 8,
"HEALTH": 9,
"POTION_SWIRLS": 10,
"POTION_SWIRLS_AMBIENT": 11,
"STUCK_ARROW_COUNT": 12,
"STINGER_COUNT": 13,
"SLEEPING_POSITION": 14,
"MOB_FLAGS": 15,
"ITEM_STACK": 8,
"ROTATION": 9,
"FUSE": 8,
"EXPLOSION_RADIUS": 9,
"FUSE_SPEED": 16,
"IGNITED": 18,
"CHARGED": 19,
"ARMOR_STAND_FLAGS": 15,
"TRACKER_HEAD_ROTATION": 16,
"TRACKER_BODY_ROTATION": 17,
"TRACKER_LEFT_ARM_ROTATION": 18,
"TRACKER_RIGHT_ARM_ROTATION": 19,
"TRACKER_LEFT_LEG_ROTATION": 20,
"TRACKER_RIGHT_LEG_ROTATION": 21,
"BLOCK_STATE": 8,
"START_INTERPOLATION": 8,
"INTERPOLATION_DURATION": 9,
"TELEPORT_DURATION": 10,
"TRANSLATION": 11,
"SCALE": 12,
"LEFT_ROTATION": 13,
"RIGHT_ROTATION": 14,
"BILLBOARD": 15,
"BRIGHTNESS": 16,
"VIEW_RANGE": 17,
"SHADOW_RADIUS": 18,
"SHADOW_STRENGTH": 19,
"WIDTH": 20,
"HEIGHT": 21,
"GLOW_COLOR_OVERRIDE": 22,
"TEXT": 23,
"LINE_WIDTH": 24,
"BACKGROUND": 25,
"TEXT_OPACITY": 26,
"TEXT_DISPLAY_FLAGS": 27,
"ITEM_DISPLAY": 24,
"PLAYER_MODE_CUSTOMIZATION_ID": 17,
"MAIN_ARM_ID": 18,
"LEFT_PADDLE_MOVING": 11,
"RIGHT_PADDLE_MOVING": 12,
"BUBBLE_WOBBLE_TICKS": 13,
"VILLAGER_DATA": 18,
"ANGER_END_TIME": 21,
"VARIANT": 20,
"BABY": 16,
"ZOMBIE_TYPE": 17,
"CONVERTING_IN_WATER": 18,
"VEX_FLAGS": 16,
"SHEARED": 16,
"PUFF_STATE": 17,
"FOX_FLAGS": 18,
"CAT_VARIANT": 19,
"COLLAR_COLOR": 20,
"TAMEABLE_FLAGS": 17,
"OWNER_UUID": 18,
"BEE_FLAGS": 17,
"ANGER": 16,
"ATTACHED_FACE": 16,
"PEEK_AMOUNT": 17,
"CONVERTING": 19,
"SNOW_GOLEM_FLAGS": 16,
"IRON_GOLEM_FLAGS": 16,
"SLIME_SIZE": 16,
"PANDA_FLAGS": 22,
"MAIN_GENE": 20,
"HIDDEN_GENE": 21,
"EATING_TICKS": 19,
"SNEEZE_PROGRESS": 18,
"STRENGTH": 19,
"HORSE_FLAGS": 17,
"CARRIED_BLOCK": 16,
"ANGRY": 17,
"PROVOKED": 18,
"SPIKES_RETRACTED": 16,
"BEAM_TARGET_ID": 17,
"PHASE_TYPE": 16,
"BEAM_TARGET": 8,
"SHOW_BOTTOM": 9
}

View File

@ -1,8 +1,7 @@
use std::{collections::BTreeMap, fs};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
use std::{collections::BTreeMap, fs};
#[derive(Deserialize)]
pub struct Packets {
@ -12,20 +11,62 @@ pub struct Packets {
}
pub(crate) fn build() -> TokenStream {
// 1. Track the JSON assets for rebuilds
println!("cargo:rerun-if-changed=../assets/packet/1_21_7_packets.json");
println!("cargo:rerun-if-changed=../assets/packet/1_21_11_packets.json");
let packets: Packets =
serde_json::from_str(&fs::read_to_string("../assets/packet/1_21_11_packets.json").unwrap())
.expect("Failed to parse packets.json");
// 2. Parse the protocol files
let packets_7: Packets = serde_json::from_str(
&fs::read_to_string("../assets/packet/1_21_7_packets.json").expect("1.21.7 file missing"),
)
.unwrap();
let version = packets.version;
let serverbound_consts = parse_packets(packets.serverbound);
let clientbound_consts = parse_packets(packets.clientbound);
let packets_11: Packets = serde_json::from_str(
&fs::read_to_string("../assets/packet/1_21_11_packets.json").expect("1.21.11 file missing"),
)
.unwrap();
let latest_version = packets_11.version;
// 3. Generate mapped constants for both directions
let serverbound_consts = generate_mapped_consts(&packets_11, &packets_7, true);
let clientbound_consts = generate_mapped_consts(&packets_11, &packets_7, false);
quote!(
/// The current Minecraft protocol version.
pub const CURRENT_MC_PROTOCOL: u32 = #version;
use pumpkin_util::version::MinecraftVersion;
pub const CURRENT_MC_PROTOCOL: u32 = #latest_version;
pub struct PacketId {
pub latest_id: i32,
pub v1_21_7_id: i32,
}
impl PacketId {
/// Converts the latest packet ID to the ID used in the requested version.
/// Returns -1 if the packet does not exist in that version.
pub fn to_id(&self, version: MinecraftVersion) -> i32 {
match version {
MinecraftVersion::V_1_21_11 => self.latest_id,
MinecraftVersion::V_1_21_7 => self.v1_21_7_id,
// Default to latest for unrecognized/unmapped versions
_ => self.latest_id,
}
}
}
impl PartialEq<i32> for PacketId {
fn eq(&self, other: &i32) -> bool {
self.latest_id == *other
}
}
impl PartialEq<PacketId> for i32 {
fn eq(&self, other: &PacketId) -> bool {
*self == other.latest_id
}
}
// We place the constants directly into these modules
pub mod serverbound {
#serverbound_consts
}
@ -36,22 +77,39 @@ pub(crate) fn build() -> TokenStream {
)
}
pub(crate) fn parse_packets(phases: BTreeMap<String, BTreeMap<String, i32>>) -> TokenStream {
let mut consts = TokenStream::new();
fn generate_mapped_consts(latest: &Packets, v7: &Packets, is_serverbound: bool) -> TokenStream {
let mut output = TokenStream::new();
let latest_phases = if is_serverbound {
&latest.serverbound
} else {
&latest.clientbound
};
let v7_phases = if is_serverbound {
&v7.serverbound
} else {
&v7.clientbound
};
for (phase_name, packets) in phases {
for (packet_name, packet_id) in packets {
let sanitized_name = packet_name
.replace("/", "_")
.replace("-", "_")
.to_uppercase();
for (phase, packets) in latest_phases {
for (name, id_11) in packets {
let sanitized = name.replace("/", "_").replace("-", "_").to_uppercase();
let const_name = format_ident!("{}_{}", phase.to_uppercase(), sanitized);
let const_name = format_ident!("{}_{}", phase_name.to_uppercase(), sanitized_name);
// Check if the packet exists in 1.21.7 to get the alternate ID
let id_7 = v7_phases
.get(phase)
.and_then(|p| p.get(name))
.cloned()
.unwrap_or(-1);
consts.extend(quote! {
pub const #const_name: i32 = #packet_id;
// Since serverbound/clientbound are modules, we reference the PacketId in the parent scope
output.extend(quote! {
pub const #const_name: super::PacketId = super::PacketId {
latest_id: #id_11,
v1_21_7_id: #id_7,
};
});
}
}
consts
output
}

View File

@ -86,6 +86,7 @@ pub(crate) fn build() -> TokenStream {
impl Registry {
pub fn get_synced(version: MinecraftVersion) -> Vec<Self> {
let static_regs = match version {
MinecraftVersion::V_1_21_7 => REGISTRIES_1_21_9,
MinecraftVersion::V_1_21_9 => REGISTRIES_1_21_9,
_ => REGISTRIES_1_21_11,
};

View File

@ -205,6 +205,8 @@ pub(crate) fn build() -> TokenStream {
});
match_get_map
.push(quote! { MinecraftVersion::V_1_21_9 => tags_1_21_9::get_map(tag_category) });
match_get_map
.push(quote! { MinecraftVersion::V_1_21_7 => tags_1_21_9::get_map(tag_category) });
}
}

View File

@ -1,33 +1,67 @@
use std::fs;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::{collections::BTreeMap, fs};
pub(crate) fn build() -> TokenStream {
println!("cargo:rerun-if-changed=../assets/tracked_data.json");
// 1. Track files
println!("cargo:rerun-if-changed=../assets/tracked_data/1_21_7_tracked_data.json");
println!("cargo:rerun-if-changed=../assets/tracked_data/1_21_11_tracked_data.json");
let mut handlers: Vec<(String, u8)> =
serde_json::from_str::<std::collections::BTreeMap<String, u8>>(
&fs::read_to_string("../assets/tracked_data.json").unwrap(),
)
.expect("Failed to parse tracked_data.json")
.into_iter()
.collect();
let data_7: BTreeMap<String, u8> = serde_json::from_str(
&fs::read_to_string("../assets/tracked_data/1_21_7_tracked_data.json")
.expect("1.21.7 data missing"),
)
.unwrap();
handlers.sort_by_key(|&(_, id)| id);
let data_11: BTreeMap<String, u8> = serde_json::from_str(
&fs::read_to_string("../assets/tracked_data/1_21_11_tracked_data.json")
.expect("1.21.11 data missing"),
)
.unwrap();
let constants = handlers.iter().map(|(name, id)| {
let mut constants = TokenStream::new();
for (name, id_11) in &data_11 {
let ident = format_ident!("DATA_{}", name.to_uppercase());
quote! {
pub const #ident: u8 = #id;
}
});
let id_7 = data_7.get(name).cloned().unwrap_or(255); // 255 as an 'Invalid' marker
constants.extend(quote! {
pub const #ident: TrackedId = TrackedId {
latest: #id_11,
v1_21_7: #id_7,
};
});
}
quote! {
use pumpkin_util::version::MinecraftVersion;
#[derive(Copy, Clone, Debug)]
pub struct TrackedId {
pub latest: u8,
pub v1_21_7: u8,
}
impl TrackedId {
pub fn get(&self, version: &MinecraftVersion) -> u8 {
match version {
MinecraftVersion::V_1_21_7 => self.v1_21_7,
_ => self.latest,
}
}
}
impl From<TrackedId> for u8 {
fn from(id: TrackedId) -> u8 {
id.latest
}
}
pub struct TrackedData;
impl TrackedData {
#(#constants)*
#constants
}
}
}

View File

@ -167,6 +167,23 @@ pub fn packet(args: TokenStream, item: TokenStream) -> TokenStream {
.into()
}
#[proc_macro_attribute]
pub fn java_packet(args: TokenStream, item: TokenStream) -> TokenStream {
let packet_id_expr = parse_macro_input!(args as Expr);
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
quote! {
#ast
impl #impl_generics crate::packet::MultiVersionJavaPacket for #name #ty_generics #where_clause {
const PACKET_ID: pumpkin_data::packet::PacketId = #packet_id_expr;
}
}
.into()
}
#[proc_macro_attribute]
pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream {
let input_item = item.clone();

View File

@ -1,11 +1,56 @@
use pumpkin_util::math::vector3::Vector3;
use crate::VarInt;
use crate::{
VarInt,
ser::{NetworkWriteExt, WritingError},
};
use serde::{Serialize, ser::Serializer};
#[derive(Clone, Copy)]
pub struct Velocity(pub Vector3<f64>);
impl Velocity {
pub fn write<W: std::io::Write>(&self, writer: &mut W) -> Result<(), WritingError> {
let velocity = self.0;
let d = clamp_value(velocity.x);
let e = clamp_value(velocity.y);
let f = clamp_value(velocity.z);
let g = abs_max(d, abs_max(e, f));
if g < MIN_VELOCITY_MAGNITUDE {
return writer.write_slice(&[0u8]);
}
let l = g.ceil() as i64;
let bl = l > 3;
// The header byte: bits 0-1 are scale, bit 2 is the extension flag
let m = if bl { (l & 3) | 4 } else { l };
// Pack the 15-bit quantized components into a 64-bit long
// n (x): bits 3-17 | o (y): bits 18-32 | p (z): bits 33-47
let n = to_long(d / l as f64) << 3;
let o = to_long(e / l as f64) << 18;
let p = to_long(f / l as f64) << 33;
let packed_data: i64 = m | n | o | p;
writer
.write_all(&(packed_data as u16).to_le_bytes())
.unwrap(); // Write low 16 bits
writer
.write_all(&((packed_data >> 16) as i32).to_be_bytes())
.unwrap(); // Write next 32 bits
if bl {
let scale_tail = VarInt((l >> 2) as i32);
writer.write_var_int(&scale_tail)?;
}
Ok(())
}
}
const MAX_VELOCITY_CLAMP: f64 = 1.7179869183E10;
const MIN_VELOCITY_MAGNITUDE: f64 = 3.051944088384301E-5;
const MAX_15_BIT_VALUE: f64 = 32766.0;
@ -28,47 +73,7 @@ fn to_long(value: f64) -> i64 {
impl Serialize for Velocity {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut buf = Vec::new();
let velocity = self.0;
let d = clamp_value(velocity.x);
let e = clamp_value(velocity.y);
let f = clamp_value(velocity.z);
let g = abs_max(d, abs_max(e, f));
if g < MIN_VELOCITY_MAGNITUDE {
buf.push(0u8);
return serializer.serialize_bytes(&buf);
}
// l is the scale factor
let l = g.ceil() as i64;
// bl is true if the scale factor is > 3 and needs VarInt extension
let bl = l > 3;
// m is the first byte of the packed data (low 3 bits of l + 4 if bl is true)
let m = if bl { l & 3 | 4 } else { l };
// Quantize and shift the velocity components (15 bits each)
let n: i64 = to_long(d / l as f64) << 3; // X shifted 3
let o: i64 = to_long(e / l as f64) << 18; // Y shifted 18
let p: i64 = to_long(f / l as f64) << 33; // Z shifted 33
// q is the packed 48-bit value (m + X + Y + Z)
let q: i64 = m | n | o | p;
// 1. Write first byte (low 8 bits)
buf.push(q as u8);
// 2. Write second byte (bits 8-15)
buf.push((q >> 8) as u8);
// 3. Write remaining 4 bytes (bits 16-47) as a Big Endian i32 (Java's writeInt)
buf.extend_from_slice(&((q >> 16) as i32).to_be_bytes());
// 4. Write VarInt for scale factor tail if needed
if bl {
VarInt::encode(&VarInt((l >> 2) as i32), &mut buf).unwrap();
}
self.write(&mut buf).unwrap();
serializer.serialize_bytes(&buf)
}
}

View File

@ -1,12 +1,12 @@
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use pumpkin_data::packet::clientbound::CONFIG_RESOURCE_PACK_PUSH;
#[derive(Serialize)]
#[packet(CONFIG_RESOURCE_PACK_PUSH)]
#[java_packet(CONFIG_RESOURCE_PACK_PUSH)]
pub struct CConfigAddResourcePack<'a> {
#[serde(with = "uuid::serde::compact")]
pub uuid: &'a uuid::Uuid,

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::CONFIG_DISCONNECT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Deserialize;
#[derive(serde::Serialize, Deserialize)]
#[packet(CONFIG_DISCONNECT)]
#[java_packet(CONFIG_DISCONNECT)]
pub struct CConfigDisconnect<'a> {
pub reason: &'a str,
}

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::CONFIG_COOKIE_REQUEST;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
#[derive(serde::Serialize)]
#[packet(CONFIG_COOKIE_REQUEST)]
#[java_packet(CONFIG_COOKIE_REQUEST)]
/// Requests a cookie that was previously stored.
pub struct CCookieRequest<'a> {
pub key: &'a ResourceLocation,

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::CONFIG_FINISH_CONFIGURATION;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(CONFIG_FINISH_CONFIGURATION)]
#[java_packet(CONFIG_FINISH_CONFIGURATION)]
pub struct CFinishConfig;

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::CONFIG_SELECT_KNOWN_PACKS;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::KnownPack;
#[derive(Serialize)]
#[packet(CONFIG_SELECT_KNOWN_PACKS)]
#[java_packet(CONFIG_SELECT_KNOWN_PACKS)]
pub struct CKnownPacks<'a> {
pub known_packs: &'a [KnownPack<'a>],
}

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::CONFIG_CUSTOM_PAYLOAD;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ser::network_serialize_no_prefix;
#[derive(Serialize)]
#[packet(CONFIG_CUSTOM_PAYLOAD)]
#[java_packet(CONFIG_CUSTOM_PAYLOAD)]
pub struct CPluginMessage<'a> {
pub channel: &'a str,
#[serde(serialize_with = "network_serialize_no_prefix")]

View File

@ -1,11 +1,11 @@
use crate::ser::network_serialize_no_prefix;
use pumpkin_data::packet::clientbound::CONFIG_REGISTRY_DATA;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
#[derive(Serialize)]
#[packet(CONFIG_REGISTRY_DATA)]
#[java_packet(CONFIG_REGISTRY_DATA)]
pub struct CRegistryData<'a> {
pub registry_id: &'a ResourceLocation,
pub entries: &'a [RegistryEntry],

View File

@ -1,10 +1,10 @@
use crate::Link;
use pumpkin_data::packet::clientbound::CONFIG_SERVER_LINKS;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(CONFIG_SERVER_LINKS)]
#[java_packet(CONFIG_SERVER_LINKS)]
pub struct CConfigServerLinks<'a> {
pub links: &'a [Link<'a>],
}

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::CONFIG_STORE_COOKIE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
#[derive(serde::Serialize)]
#[packet(CONFIG_STORE_COOKIE)]
#[java_packet(CONFIG_STORE_COOKIE)]
/// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian (vanilla) client only accepts cookies of up to 5 KiB in size.
pub struct CStoreCookie<'a> {

View File

@ -1,10 +1,10 @@
use crate::VarInt;
use pumpkin_data::packet::clientbound::CONFIG_TRANSFER;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(CONFIG_TRANSFER)]
#[java_packet(CONFIG_TRANSFER)]
pub struct CTransfer<'a> {
pub host: &'a str,
pub port: &'a VarInt,

View File

@ -7,11 +7,11 @@ use pumpkin_data::{
packet::clientbound::CONFIG_UPDATE_TAGS,
tag::{RegistryKey, get_registry_key_tags},
};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
use pumpkin_util::version::MinecraftVersion;
#[packet(CONFIG_UPDATE_TAGS)]
#[java_packet(CONFIG_UPDATE_TAGS)]
pub struct CUpdateTags<'a> {
pub tags: &'a [pumpkin_data::tag::RegistryKey],
}

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::LOGIN_COOKIE_REQUEST;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
@ -8,7 +8,7 @@ use serde::Serialize;
/// This occurs during the login phase, allowing the server to identify
/// returning players or retrieve session data stored during a previous visit.
#[derive(Serialize)]
#[packet(LOGIN_COOKIE_REQUEST)]
#[java_packet(LOGIN_COOKIE_REQUEST)]
pub struct CLoginCookieRequest<'a> {
/// The unique identifier of the cookie being requested.
pub key: &'a ResourceLocation,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::LOGIN_HELLO;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
/// Sent by the server to initiate the encryption handshake.
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
/// verification token, allowing the client to generate a shared secret
/// for secure communication.
#[derive(Serialize, Deserialize)]
#[packet(LOGIN_HELLO)]
#[java_packet(LOGIN_HELLO)]
pub struct CEncryptionRequest<'a> {
/// The server's ID string. In modern Minecraft, this is usually
/// an empty string unless the server is using legacy authentication.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::LOGIN_LOGIN_DISCONNECT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
/// Sent by the server to reject a login attempt or kick a player during the login phase
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
/// This is used for reasons such as the server being full, the player being banned,
/// or version mismatches. After this packet is sent, the connection is closed.
#[derive(Serialize, Deserialize)]
#[packet(LOGIN_LOGIN_DISCONNECT)]
#[java_packet(LOGIN_LOGIN_DISCONNECT)]
pub struct CLoginDisconnect {
/// A JSON-encoded chat component explaining why the player was disconnected.
pub json_reason: String,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::LOGIN_LOGIN_FINISHED;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::Property;
@ -9,7 +9,7 @@ use crate::Property;
/// This packet provides the client with its official UUID and username as
/// recognized by the server, along with any associated skin or cape properties.
#[derive(Serialize)]
#[packet(LOGIN_LOGIN_FINISHED)]
#[java_packet(LOGIN_LOGIN_FINISHED)]
pub struct CLoginSuccess<'a> {
/// The unique identifier assigned to the player.
pub uuid: &'a uuid::Uuid,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::LOGIN_CUSTOM_QUERY;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::{VarInt, ser::network_serialize_no_prefix};
@ -9,7 +9,7 @@ use crate::{VarInt, ser::network_serialize_no_prefix};
/// This is used by server software (like proxies or anti-cheats) to request
/// information from a client-side mod before the player officially joins.
#[derive(Serialize)]
#[packet(LOGIN_CUSTOM_QUERY)]
#[java_packet(LOGIN_CUSTOM_QUERY)]
pub struct CLoginPluginRequest<'a> {
/// A unique ID for this request. The client must include this same ID
/// in its response so the server can match them up.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::LOGIN_LOGIN_COMPRESSION;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::VarInt;
@ -9,7 +9,7 @@ use crate::VarInt;
/// Once this packet is sent, both the server and the client must compress any
/// packet with a size equal to or greater than the specified threshold.
#[derive(Serialize, Deserialize)]
#[packet(LOGIN_LOGIN_COMPRESSION)]
#[java_packet(LOGIN_LOGIN_COMPRESSION)]
pub struct CSetCompression {
/// The packet size threshold (in bytes) at which compression is applied.
///

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_CHANGED_ACK;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::VarInt;
@ -9,7 +9,7 @@ use crate::VarInt;
/// This packet is critical for preventing "ghost blocks" and synchronization issues.
/// It tells the client that the server has processed all actions up to a specific point.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_BLOCK_CHANGED_ACK)]
#[java_packet(PLAY_BLOCK_CHANGED_ACK)]
pub struct CAcknowledgeBlockChange {
/// The ID of the last sequence processed by the server.
///

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_SET_ACTION_BAR_TEXT;
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
/// Updates the text displayed above the player's hotbar (the Action Bar).
@ -10,7 +10,7 @@ use serde::Serialize;
/// non-critical status information like "Now entering: Wilderness" or
/// mana/stamina counters.
#[derive(Serialize)]
#[packet(PLAY_SET_ACTION_BAR_TEXT)]
#[java_packet(PLAY_SET_ACTION_BAR_TEXT)]
pub struct CActionBar<'a> {
/// The text component to be displayed.
pub action_bar: &'a TextComponent,

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_DESTRUCTION;
use pumpkin_util::math::position::BlockPos;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -11,7 +11,7 @@ use crate::VarInt;
/// This packet controls the overlay of cracks that appear on a block when
/// it is being mined. It is often used to show other players' mining progress.
#[derive(Serialize)]
#[packet(PLAY_BLOCK_DESTRUCTION)]
#[java_packet(PLAY_BLOCK_DESTRUCTION)]
pub struct CSetBlockDestroyStage {
/// A unique ID for this destruction instance. Usually the miner's Entity ID.
/// If multiple entities mine the same block, they must use different IDs.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_ENTITY_DATA;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::position::BlockPos;
use serde::Serialize;
@ -10,7 +10,7 @@ use crate::{VarInt, ser::network_serialize_no_prefix};
/// This packet is sent by the server when a block entity's state changes
/// (like text on a sign) or when the block entity is loaded into the client's view.
#[derive(Serialize)]
#[packet(PLAY_BLOCK_ENTITY_DATA)]
#[java_packet(PLAY_BLOCK_ENTITY_DATA)]
pub struct CBlockEntityData {
/// The world coordinates of the block entity.
pub location: BlockPos,

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_EVENT;
use pumpkin_util::math::position::BlockPos;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -11,7 +11,7 @@ use crate::VarInt;
/// This is used for simple block interactions that don't necessarily change
/// NBT data, such as chests opening/closing, pistons extending, or note blocks playing.
#[derive(Serialize)]
#[packet(PLAY_BLOCK_EVENT)]
#[java_packet(PLAY_BLOCK_EVENT)]
pub struct CBlockEvent {
/// The coordinates where the event occurs.
pub location: BlockPos,

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_UPDATE;
use pumpkin_util::math::position::BlockPos;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -11,7 +11,7 @@ use crate::VarInt;
/// This is the most common way to sync world changes to the client, such as
/// when a player places a block, a fluid flows, or a redstone component toggles.
#[derive(Serialize)]
#[packet(PLAY_BLOCK_UPDATE)]
#[java_packet(PLAY_BLOCK_UPDATE)]
pub struct CBlockUpdate {
/// The world coordinates of the block being updated.
pub location: BlockPos,

View File

@ -4,14 +4,14 @@ use crate::java::client::play::BosseventAction;
use crate::ser::NetworkWriteExt;
use crate::{ClientPacket, WritingError};
use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::version::MinecraftVersion;
/// Updates the "Boss Bar" displayed at the top of the player's screen.
///
/// This packet is used to manage health bars for entities like the Ender Dragon
/// or Wither, as well as custom progress bars for server events or raids.
#[packet(PLAY_BOSS_EVENT)]
#[java_packet(PLAY_BOSS_EVENT)]
pub struct CBossEvent<'a> {
/// A unique identifier for this specific boss bar instance.
pub uuid: &'a uuid::Uuid,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_SET_CHUNK_CACHE_CENTER;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -10,7 +10,7 @@ use crate::VarInt;
/// focal point for loading and unloading chunks. It is typically sent when
/// a player moves across a chunk boundary.
#[derive(Serialize)]
#[packet(PLAY_SET_CHUNK_CACHE_CENTER)]
#[java_packet(PLAY_SET_CHUNK_CACHE_CENTER)]
pub struct CCenterChunk {
/// The X coordinate of the center chunk.
pub chunk_x: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_CHANGE_DIFFICULTY;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
/// Notifies the client of a change in the world's difficulty level or lock status.
@ -8,7 +8,7 @@ use serde::Serialize;
/// and client-side behavior (though actual game logic like mob damage is
/// primarily handled by the server).
#[derive(Serialize)]
#[packet(PLAY_CHANGE_DIFFICULTY)]
#[java_packet(PLAY_CHANGE_DIFFICULTY)]
pub struct CChangeDifficulty {
/// The current difficulty level of the world.
///

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_CHUNK_BATCH_FINISHED;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::codec::var_int::VarInt;
@ -10,7 +10,7 @@ use crate::codec::var_int::VarInt;
/// allows the client to acknowledge the receipt of a group of chunks, helping
/// the server regulate the flow of data and prevent network congestion.
#[derive(Serialize)]
#[packet(PLAY_CHUNK_BATCH_FINISHED)]
#[java_packet(PLAY_CHUNK_BATCH_FINISHED)]
pub struct CChunkBatchEnd {
/// The number of chunks sent in the batch that just finished.
pub batch_size: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_CHUNK_BATCH_START;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
/// Signals the beginning of a new batch of chunk data packets.
@ -9,5 +9,5 @@ use serde::Serialize;
/// a `Start` and `End` packet to manage client-side backpressure and
/// network throughput.
#[derive(Serialize)]
#[packet(PLAY_CHUNK_BATCH_START)]
#[java_packet(PLAY_CHUNK_BATCH_START)]
pub struct CChunkBatchStart;

View File

@ -2,7 +2,7 @@ use crate::WritingError;
use crate::codec::bit_set::BitSet;
use crate::{ClientPacket, VarInt, ser::NetworkWriteExt};
use pumpkin_data::packet::clientbound::PLAY_LEVEL_CHUNK_WITH_LIGHT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_nbt::END_ID;
use pumpkin_util::math::position::get_local_cord;
use pumpkin_util::version::MinecraftVersion;
@ -15,7 +15,7 @@ use std::io::Write;
/// This includes heightmaps, the actual block and biome data (organized into sections),
/// block entities (like signs or chests), and the light level information for both
/// sky and block light.
#[packet(PLAY_LEVEL_CHUNK_WITH_LIGHT)]
#[java_packet(PLAY_LEVEL_CHUNK_WITH_LIGHT)]
pub struct CChunkData<'a>(pub &'a ChunkData);
impl ClientPacket for CChunkData<'_> {

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_CLEAR_TITLES;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
/// Removes any currently displayed Title or Subtitle from the player's screen.
@ -7,7 +7,7 @@ use serde::Serialize;
/// This packet is used to immediately hide titles that are currently in their
/// "stay" or "fade-out" phases.
#[derive(Serialize)]
#[packet(PLAY_CLEAR_TITLES)]
#[java_packet(PLAY_CLEAR_TITLES)]
pub struct CClearTitle {
/// If true, the client also resets the title timings (fade-in, stay, fade-out)
/// to their default values (10, 70, 20 ticks).

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_CONTAINER_CLOSE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -10,7 +10,7 @@ use crate::VarInt;
/// if the player moves too far away from a chest or if an NPC's trade window
/// is invalidated.
#[derive(Serialize)]
#[packet(PLAY_CONTAINER_CLOSE)]
#[java_packet(PLAY_CONTAINER_CLOSE)]
pub struct CCloseContainer {
/// The ID of the container window to close.
///

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_PLAYER_COMBAT_KILL;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::text::TextComponent;
use serde::Serialize;
@ -10,7 +10,7 @@ use crate::VarInt;
/// This packet is responsible for triggering the death screen on the client
/// and displaying the death message in the chat for the deceased player.
#[derive(Serialize)]
#[packet(PLAY_PLAYER_COMBAT_KILL)]
#[java_packet(PLAY_PLAYER_COMBAT_KILL)]
pub struct CCombatDeath<'a> {
/// The Entity ID of the player who died.
pub player_id: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_COMMAND_SUGGESTIONS;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::text::TextComponent;
use serde::Serialize;
@ -11,7 +11,7 @@ use crate::VarInt;
/// appearing as a scrollable list of options while the player is typing
/// in the chat bar.
#[derive(Serialize)]
#[packet(PLAY_COMMAND_SUGGESTIONS)]
#[java_packet(PLAY_COMMAND_SUGGESTIONS)]
pub struct CCommandSuggestions {
/// The unique ID of the request this response is for.
/// This must match the ID sent by the client in the request packet.

View File

@ -1,7 +1,7 @@
use std::io::Write;
use pumpkin_data::packet::clientbound::PLAY_COMMANDS;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::version::MinecraftVersion;
use crate::{ClientPacket, VarInt, WritingError, ser::NetworkWriteExt};
@ -11,7 +11,7 @@ use crate::{ClientPacket, VarInt, WritingError, ser::NetworkWriteExt};
/// Minecraft uses the "Brigadier" command system. This packet informs the client
/// which commands exist, their arguments, and how they branch, allowing the
/// client to highlight syntax errors in red before the command is even sent.
#[packet(PLAY_COMMANDS)]
#[java_packet(PLAY_COMMANDS)]
pub struct CCommands<'a> {
/// A flat list of all nodes in the command graph.
/// Nodes reference each other by their index in this array.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_COOKIE_REQUEST;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
@ -9,7 +9,7 @@ use serde::Serialize;
/// small amounts of persistent data on the client side that can be retrieved
/// even across different server instances or sub-servers in a network.
#[derive(Serialize)]
#[packet(PLAY_COOKIE_REQUEST)]
#[java_packet(PLAY_COOKIE_REQUEST)]
pub struct CPlayCookieRequest<'a> {
/// The unique identifier (namespace:path) of the cookie to retrieve.
pub key: &'a ResourceLocation,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_DAMAGE_EVENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
@ -12,7 +12,7 @@ use crate::VarInt;
/// with specific details about the damage source to ensure the visual feedback
/// matches the cause.
#[derive(Serialize)]
#[packet(PLAY_DAMAGE_EVENT)]
#[java_packet(PLAY_DAMAGE_EVENT)]
pub struct CDamageEvent {
/// The Entity ID of the entity taking damage.
pub entity_id: VarInt,

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
/// Forces the client to disconnect from the server while in the "Play" state.
@ -10,7 +10,7 @@ use serde::Serialize;
/// disconnection screen. It is used for kicks, server shutdowns, or when
/// a player is banned.
#[derive(Serialize)]
#[packet(PLAY_DISCONNECT)]
#[java_packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect<'a> {
/// The message shown to the player explaining why they were disconnected.
/// This supports full JSON formatting (colors, bold, links, etc.).

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_DISGUISED_CHAT;
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -12,7 +12,7 @@ use crate::VarInt;
/// this packet bypasses the player-to-player chat signing requirements while
/// still allowing the client to format the message using the standard chat registry.
#[derive(Serialize)]
#[packet(PLAY_DISGUISED_CHAT)]
#[java_packet(PLAY_DISGUISED_CHAT)]
pub struct CDisguisedChatMessage<'a> {
/// The raw content of the message.
pub message: &'a TextComponent,

View File

@ -1,7 +1,7 @@
use pumpkin_data::{
packet::clientbound::PLAY_SET_DISPLAY_OBJECTIVE, scoreboard::ScoreboardDisplaySlot,
};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -12,7 +12,7 @@ use crate::VarInt;
/// an objective is created and populated with scores, this packet "maps"
/// that objective to a visual location like the sidebar or the player list.
#[derive(Serialize)]
#[packet(PLAY_SET_DISPLAY_OBJECTIVE)]
#[java_packet(PLAY_SET_DISPLAY_OBJECTIVE)]
pub struct CDisplayObjective {
/// The display slot/position for the objective.
pub position: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_ANIMATE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -9,7 +9,7 @@ use crate::VarInt;
/// This is primarily used for player-driven animations like swinging an arm
/// or showing damage, but it can apply to other entities as well.
#[derive(Serialize)]
#[packet(PLAY_ANIMATE)]
#[java_packet(PLAY_ANIMATE)]
pub struct CEntityAnimation {
/// The Entity ID of the entity performing the animation.
pub entity_id: VarInt,

View File

@ -1,8 +1,14 @@
use pumpkin_data::{meta_data_type::MetaDataType, packet::clientbound::PLAY_SET_ENTITY_DATA};
use pumpkin_macros::packet;
use pumpkin_data::{
meta_data_type::MetaDataType, packet::clientbound::PLAY_SET_ENTITY_DATA,
tracked_data::TrackedId,
};
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::{VarInt, ser::network_serialize_no_prefix};
use crate::{
VarInt,
ser::{NetworkWriteExt, WritingError, network_serialize_no_prefix, serializer},
};
/// Updates the "Data Tracker" values for an entity.
///
@ -10,7 +16,7 @@ use crate::{VarInt, ser::network_serialize_no_prefix};
/// don't require a full packet to update, such as whether an entity is on fire,
/// crouching, glowing, or the custom name displayed above its head.
#[derive(Serialize)]
#[packet(PLAY_SET_ENTITY_DATA)]
#[java_packet(PLAY_SET_ENTITY_DATA)]
pub struct CSetEntityMetadata {
/// The Entity ID of the entity whose metadata is being updated.
pub entity_id: VarInt,
@ -29,19 +35,43 @@ impl CSetEntityMetadata {
}
}
#[derive(Serialize, Clone)]
pub struct Metadata<T> {
index: u8,
index: TrackedId,
r#type: VarInt,
value: T,
}
impl<T> Metadata<T> {
pub fn new(index: u8, r#type: MetaDataType, value: T) -> Self {
pub fn new(index: TrackedId, r#type: MetaDataType, value: T) -> Self {
Self {
index,
r#type: VarInt(r#type as i32),
value,
}
}
pub fn write<W: std::io::Write>(
&self,
mut writer: W,
version: &pumpkin_util::version::MinecraftVersion,
) -> Result<(), WritingError>
where
T: Serialize,
{
let resolved_index = self.index.get(version);
if resolved_index == 255 {
return Ok(());
}
writer.write_u8(resolved_index)?;
self.r#type.encode(&mut writer)?;
let mut serializer = serializer::Serializer::new(&mut writer);
self.value
.serialize(&mut serializer)
.map_err(|e| WritingError::Serde(e.to_string()))?;
Ok(())
}
}

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_ENTITY_POSITION_SYNC;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
@ -13,7 +13,7 @@ use crate::VarInt;
///
/// Note: This packet must NOT be used for the player receiving the packet or
/// any entity the player is currently riding.
#[packet(PLAY_ENTITY_POSITION_SYNC)]
#[java_packet(PLAY_ENTITY_POSITION_SYNC)]
#[derive(Serialize)]
pub struct CEntityPositionSync {
/// The Entity ID of the entity being moved.

View File

@ -1,5 +1,5 @@
use pumpkin_data::{packet::clientbound::PLAY_SOUND_ENTITY, sound::SoundCategory};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::{IdOr, SoundEvent, VarInt};
@ -10,7 +10,7 @@ use crate::{IdOr, SoundEvent, VarInt};
/// through the world. The client handles the panning and attenuation
/// (volume drop-off) based on the distance between the player and the entity.
#[derive(Serialize)]
#[packet(PLAY_SOUND_ENTITY)]
#[java_packet(PLAY_SOUND_ENTITY)]
pub struct CEntitySoundEffect {
/// The sound to play. Can be a hardcoded ID or a custom SoundEvent
/// (Resource Location).

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_ENTITY_EVENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
/// Sends a status update for a specific entity.
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
/// and logical state triggers, such as tool breaking, totem usage,
/// or sheep shearing.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_ENTITY_EVENT)]
#[java_packet(PLAY_ENTITY_EVENT)]
pub struct CEntityStatus {
/// The Entity ID of the entity affected by the status change.
pub entity_id: i32,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_MOTION;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
@ -10,7 +10,7 @@ use crate::{VarInt, codec::velocity::Velocity};
/// This packet informs the client of a sudden change in an entity's movement,
/// such as knockback from an attack, explosions, or being launched by a piston.
#[derive(Serialize)]
#[packet(PLAY_SET_ENTITY_MOTION)]
#[java_packet(PLAY_SET_ENTITY_MOTION)]
pub struct CEntityVelocity {
/// The Entity ID of the entity whose velocity is being set
pub entity_id: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_EXPLODE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
@ -11,7 +11,7 @@ use crate::{IdOr, SoundEvent, codec::var_int::VarInt};
/// effects of an explosion in a single call. It triggers the explosion particles,
/// plays the sound at the source, and applies knockback to the player.
#[derive(Serialize)]
#[packet(PLAY_EXPLODE)]
#[java_packet(PLAY_EXPLODE)]
pub struct CExplosion {
/// The center coordinates of the explosion.
pub center: Vector3<f64>,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_GAME_EVENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
/// Updates the game state or triggers specific environmental changes.
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
/// context-specific transitions, such as changing the weather,
/// altering the player's gamemode, or displaying the credits.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_GAME_EVENT)]
#[java_packet(PLAY_GAME_EVENT)]
pub struct CGameEvent {
/// The ID of the event type.
pub event: u8,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_ROTATE_HEAD;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::VarInt;
@ -11,7 +11,7 @@ use crate::VarInt;
/// required to make an entity (like a player or a mob) look in a
/// specific direction without necessarily turning its entire body.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_ROTATE_HEAD)]
#[java_packet(PLAY_ROTATE_HEAD)]
pub struct CHeadRot {
/// The Entity ID of the entity whose head is rotating.
pub entity_id: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_HURT_ANIMATION;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::VarInt;
@ -10,7 +10,7 @@ use crate::VarInt;
/// camera shake or model tilt. It is typically sent immediately after
/// an entity's health is reduced.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_HURT_ANIMATION)]
#[java_packet(PLAY_HURT_ANIMATION)]
pub struct CHurtAnimation {
/// The Entity ID of the entity that was hurt.
pub entity_id: VarInt,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_INITIALIZE_BORDER;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::{VarInt, codec::var_long::VarLong};
@ -10,7 +10,7 @@ use crate::{VarInt, codec::var_long::VarLong};
/// It synchronizes the current position, size, and all warning parameters
/// to ensure the client-side visual barrier matches the server's authority.
#[derive(Serialize)]
#[packet(PLAY_INITIALIZE_BORDER)]
#[java_packet(PLAY_INITIALIZE_BORDER)]
pub struct CInitializeWorldBorder {
/// The X coordinate of the center of the world border.
pub x: f64,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_KEEP_ALIVE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
/// Maintains the connection and measures latency (ping) between client and server.
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
/// a response within a timeout period (usually 30 seconds), it will disconnect
/// the player with a "Timed Out" message.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_KEEP_ALIVE)]
#[java_packet(PLAY_KEEP_ALIVE)]
pub struct CKeepAlive {
/// A unique random identifier for this specific keep-alive request.
/// Used to match the server's request with the client's response.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_LEVEL_EVENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::position::BlockPos;
use serde::{Deserialize, Serialize};
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
/// block breaking particles, firework explosions, or ambient sounds
/// like doors opening and portals humming.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_LEVEL_EVENT)]
#[java_packet(PLAY_LEVEL_EVENT)]
pub struct CLevelEvent {
/// The ID of the event to trigger.
/// Event IDs are generally divided into Sound Events (1000s) and

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_LOGIN;
use pumpkin_util::{math::position::BlockPos, resource_location::ResourceLocation};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -13,7 +13,7 @@ use crate::VarInt;
/// initializes the player's world view, dimension settings, and local game
/// rules. Once received, the client begins rendering the world.
#[derive(Serialize)]
#[packet(PLAY_LOGIN)]
#[java_packet(PLAY_LOGIN)]
pub struct CLogin<'a> {
/// The unique ID assigned to the player for the current session.
pub entity_id: i32,

View File

@ -4,7 +4,7 @@ use pumpkin_util::math::{
vector3::{self, Vector3},
};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Serialize, ser::SerializeTuple};
use crate::codec::{var_int::VarInt, var_long::VarLong};
@ -14,7 +14,7 @@ use crate::codec::{var_int::VarInt, var_long::VarLong};
/// This packet is much more efficient than sending multiple individual
/// `CBlockUpdate` packets when many changes occur in the same area
/// (e.g., explosions, structure generation, or large-scale terraforming).
#[packet(PLAY_SECTION_BLOCKS_UPDATE)]
#[java_packet(PLAY_SECTION_BLOCKS_UPDATE)]
pub struct CMultiBlockUpdate {
/// The coordinates of the chunk section being updated.
/// Calculated as (block_coord >> 4).

View File

@ -1,7 +1,7 @@
use pumpkin_data::packet::clientbound::PLAY_OPEN_SCREEN;
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -13,7 +13,7 @@ use crate::VarInt;
/// `sync_id` which must be used in all subsequent "Set Slot" or "Click Slot"
/// packets to ensure the server and client are talking about the same window.
#[derive(Serialize)]
#[packet(PLAY_OPEN_SCREEN)]
#[java_packet(PLAY_OPEN_SCREEN)]
pub struct COpenScreen<'a> {
/// A unique identifier for the current window session.
/// Typically increments by 1 for every new window opened.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_OPEN_SIGN_EDITOR;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::position::BlockPos;
use serde::Serialize;
@ -9,7 +9,7 @@ use serde::Serialize;
/// sign editing interface. This usually happens immediately after a
/// player places a sign or interacts with an existing one (if allowed).
#[derive(Serialize)]
#[packet(PLAY_OPEN_SIGN_EDITOR)]
#[java_packet(PLAY_OPEN_SIGN_EDITOR)]
pub struct COpenSignEditor {
/// The world coordinates of the sign block to be edited.
pub location: BlockPos,

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_LEVEL_PARTICLES;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
@ -12,7 +12,7 @@ use crate::{VarInt, ser::network_serialize_no_prefix};
/// carry extra data for complex particles like redstone dust (color) or
/// block/item breaking (textures).
#[derive(Serialize)]
#[packet(PLAY_LEVEL_PARTICLES)]
#[java_packet(PLAY_LEVEL_PARTICLES)]
pub struct CParticle<'a> {
/// If true, the particle renders even if the client's "Particles"
/// setting is set to "Minimal".

View File

@ -1,10 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_PONG_RESPONSE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
/// Responds to a client-initiated ping request to synchronize game state.
#[derive(Serialize, Deserialize)]
#[packet(PLAY_PONG_RESPONSE)]
#[java_packet(PLAY_PONG_RESPONSE)]
pub struct CPingResponse {
/// The unique identifier sent by the client in the initial Ping packet.
/// The server must return this exact value.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_PLAYER_ABILITIES;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
/// Updates the player's movement and interaction abilities.
@ -8,7 +8,7 @@ use serde::Serialize;
/// and sets the movement speeds. While the client applies these visuals,
/// the server must still validate these states to prevent cheating.
#[derive(Serialize)]
#[packet(PLAY_PLAYER_ABILITIES)]
#[java_packet(PLAY_PLAYER_ABILITIES)]
pub struct CPlayerAbilities {
/// A bitmask of player states.
/// Bit 0 (0x01): Invulnerable (Creative mode)

View File

@ -1,7 +1,7 @@
use std::io::Write;
use pumpkin_data::packet::clientbound::PLAY_PLAYER_CHAT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
use crate::{
@ -14,7 +14,7 @@ use crate::{
///
/// This packet is the backbone of the modern secure chat system. It includes
/// tracking indices, digital signatures, and context for reporting.
#[packet(PLAY_PLAYER_CHAT)]
#[java_packet(PLAY_PLAYER_CHAT)]
pub struct CPlayerChatMessage {
/// Incremental index for messages sent TO this specific client.
/// Starts at 0 on login; client disconnects if the sequence is broken.

View File

@ -2,7 +2,7 @@ use std::io::Write;
use bitflags::bitflags;
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_UPDATE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::version::MinecraftVersion;
use crate::{ClientPacket, Property, WritingError, ser::NetworkWriteExt};
@ -40,7 +40,7 @@ bitflags! {
/// This packet replaces the legacy "Player Info" packet with a more efficient
/// bitmask-driven approach. Instead of sending full data every time, the
/// server only sends the fields specified in the `actions` bitmask.
#[packet(PLAY_PLAYER_INFO_UPDATE)]
#[java_packet(PLAY_PLAYER_INFO_UPDATE)]
pub struct CPlayerInfoUpdate<'a> {
/// The bitmask (PlayerInfoFlags) determining which data follows.
pub actions: u8,

View File

@ -1,7 +1,7 @@
use std::io::Write;
use pumpkin_data::packet::clientbound::PLAY_PLAYER_POSITION;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::{math::vector3::Vector3, version::MinecraftVersion};
use crate::{
@ -14,7 +14,7 @@ use crate::{
/// Commonly known as the "Teleport Packet," this is sent by the server to
/// force a change in the player's location. The client must respond with a
/// `Teleport Confirm` packet matching the `teleport_id`.
#[packet(PLAY_PLAYER_POSITION)]
#[java_packet(PLAY_PLAYER_POSITION)]
pub struct CPlayerPosition {
/// A unique ID for this teleport. The client must echo this back
/// to confirm the teleport was processed.

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_REMOVE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::{Serialize, ser::SerializeSeq};
/// Sent by the server to remove one or more players from the client's player list (tab list).
@ -7,7 +7,7 @@ use serde::{Serialize, ser::SerializeSeq};
/// This packet is typically used when a player leaves the server or becomes invisible
/// to the recipient (e.g., moving out of tracking range).
#[derive(Serialize)]
#[packet(PLAY_PLAYER_INFO_REMOVE)]
#[java_packet(PLAY_PLAYER_INFO_REMOVE)]
pub struct CRemovePlayerInfo<'a> {
/// A list of UUIDs corresponding to the players that should be removed.
///

View File

@ -1,15 +1,19 @@
use serde::Serialize;
use std::io::Write;
use pumpkin_data::packet::clientbound::PLAY_SET_DEFAULT_SPAWN_POSITION;
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
use pumpkin_macros::java_packet;
use pumpkin_util::{math::position::BlockPos, version::MinecraftVersion};
use crate::{
ClientPacket,
ser::{NetworkWriteExt, WritingError},
};
/// Sent by the server to set the client's default spawn point and compass target.
///
/// This packet updates where the player will respawn upon death (if no bed or anchor is set)
/// and dictates the coordinates that a compass will point toward.
#[derive(Serialize)]
#[packet(PLAY_SET_DEFAULT_SPAWN_POSITION)]
#[java_packet(PLAY_SET_DEFAULT_SPAWN_POSITION)]
pub struct CPlayerSpawnPosition {
/// The namespaced ID of the dimension (e.g., "minecraft:overworld").
/// Required for the client to determine if the spawn point is in their current world.
@ -32,3 +36,25 @@ impl CPlayerSpawnPosition {
}
}
}
impl ClientPacket for CPlayerSpawnPosition {
fn write_packet_data(
&self,
write: impl Write,
version: &MinecraftVersion,
) -> Result<(), WritingError> {
let mut write = write;
if *version >= MinecraftVersion::V_1_21_9 {
write.write_string(&self.dimension_name)?;
}
write.write_block_pos(&self.location)?;
write.write_f32_be(self.yaw)?;
if *version >= MinecraftVersion::V_1_21_9 {
write.write_f32_be(self.pitch)?;
}
Ok(())
}
}

View File

@ -1,5 +1,5 @@
use pumpkin_data::packet::clientbound::PLAY_REMOVE_ENTITIES;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
@ -9,7 +9,7 @@ use crate::VarInt;
/// This is typically sent when an entity leaves the player's tracking range,
/// is killed, or is otherwise removed from the world.
#[derive(Serialize)]
#[packet(PLAY_REMOVE_ENTITIES)]
#[java_packet(PLAY_REMOVE_ENTITIES)]
pub struct CRemoveEntities<'a> {
/// A list of entity IDs to be removed.
pub entity_ids: &'a [VarInt],

View File

@ -1,10 +1,10 @@
use crate::codec::var_int::VarInt;
use pumpkin_data::packet::clientbound::PLAY_REMOVE_MOB_EFFECT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_REMOVE_MOB_EFFECT)]
#[java_packet(PLAY_REMOVE_MOB_EFFECT)]
pub struct CRemoveMobEffect {
pub entity_id: VarInt,
pub effect_id: VarInt,

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_RESET_SCORE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_RESET_SCORE)]
#[java_packet(PLAY_RESET_SCORE)]
pub struct CResetScore {
pub entity_name: String,
pub objective_name: Option<String>,

View File

@ -1,12 +1,12 @@
use pumpkin_data::packet::clientbound::PLAY_RESPAWN;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::{math::position::BlockPos, resource_location::ResourceLocation};
use serde::{Deserialize, Serialize};
use crate::VarInt;
#[derive(Serialize, Deserialize)]
#[packet(PLAY_RESPAWN)]
#[java_packet(PLAY_RESPAWN)]
pub struct CRespawn {
pub dimension_type: VarInt,
pub dimension_name: ResourceLocation,

View File

@ -1,10 +1,10 @@
use crate::Link;
use pumpkin_data::packet::clientbound::PLAY_SERVER_LINKS;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SERVER_LINKS)]
#[java_packet(PLAY_SERVER_LINKS)]
pub struct CPlayServerLinks<'a> {
pub links: &'a [Link<'a>],
}

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_CENTER;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_BORDER_CENTER)]
#[java_packet(PLAY_SET_BORDER_CENTER)]
pub struct CSetBorderCenter {
pub x: f64,
pub z: f64,

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_LERP_SIZE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::codec::var_long::VarLong;
#[derive(Serialize)]
#[packet(PLAY_SET_BORDER_LERP_SIZE)]
#[java_packet(PLAY_SET_BORDER_LERP_SIZE)]
pub struct CSetBorderLerpSize {
pub old_diameter: f64,
pub new_diameter: f64,

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_SIZE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_BORDER_SIZE)]
#[java_packet(PLAY_SET_BORDER_SIZE)]
pub struct CSetBorderSize {
pub diameter: f64,
}

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DELAY;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize)]
#[packet(PLAY_SET_BORDER_WARNING_DELAY)]
#[java_packet(PLAY_SET_BORDER_WARNING_DELAY)]
pub struct CSetBorderWarningDelay {
pub warning_time: VarInt,
}

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DISTANCE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize)]
#[packet(PLAY_SET_BORDER_WARNING_DISTANCE)]
#[java_packet(PLAY_SET_BORDER_WARNING_DISTANCE)]
pub struct CSetBorderWarningDistance {
pub warning_blocks: VarInt,
}

View File

@ -2,11 +2,11 @@ use crate::VarInt;
use crate::codec::item_stack_seralizer::ItemStackSerializer;
use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_CONTENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_CONTAINER_SET_CONTENT)]
#[java_packet(PLAY_CONTAINER_SET_CONTENT)]
pub struct CSetContainerContent<'a> {
pub window_id: VarInt,
pub state_id: VarInt,

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_DATA;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize)]
#[packet(PLAY_CONTAINER_SET_DATA)]
#[java_packet(PLAY_CONTAINER_SET_DATA)]
pub struct CSetContainerProperty {
pub window_id: VarInt,
pub property: i16,

View File

@ -2,11 +2,11 @@ use crate::VarInt;
use crate::codec::item_stack_seralizer::ItemStackSerializer;
use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_SLOT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_CONTAINER_SET_SLOT)]
#[java_packet(PLAY_CONTAINER_SET_SLOT)]
pub struct CSetContainerSlot<'a> {
pub window_id: i8,
pub state_id: VarInt,

View File

@ -1,11 +1,11 @@
use crate::codec::item_stack_seralizer::ItemStackSerializer;
use pumpkin_data::packet::clientbound::PLAY_SET_CURSOR_ITEM;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_CURSOR_ITEM)]
#[java_packet(PLAY_SET_CURSOR_ITEM)]
pub struct CSetCursorItem<'a> {
pub stack: &'a ItemStackSerializer<'a>,
}

View File

@ -5,7 +5,7 @@ use crate::{
ser::{NetworkWriteExt, serializer::Serializer},
};
use pumpkin_data::packet::clientbound::PLAY_SET_EQUIPMENT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::version::MinecraftVersion;
use serde::Serialize;
@ -14,7 +14,7 @@ use crate::{
codec::{item_stack_seralizer::ItemStackSerializer, var_int::VarInt},
};
#[packet(PLAY_SET_EQUIPMENT)]
#[java_packet(PLAY_SET_EQUIPMENT)]
pub struct CSetEquipment {
pub entity_id: VarInt,
pub equipment: Vec<(i8, ItemStackSerializer<'static>)>,

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_EXPERIENCE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize)]
#[packet(PLAY_SET_EXPERIENCE)]
#[java_packet(PLAY_SET_EXPERIENCE)]
pub struct CSetExperience {
pub progress: f32,
pub total_experience: VarInt,

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_HEALTH;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize)]
#[packet(PLAY_SET_HEALTH)]
#[java_packet(PLAY_SET_HEALTH)]
pub struct CSetHealth {
pub health: f32,
pub food: VarInt,

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_SET_HELD_SLOT;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_HELD_SLOT)]
#[java_packet(PLAY_SET_HELD_SLOT)]
pub struct CSetSelectedSlot {
pub slot: i8,
}

View File

@ -2,11 +2,11 @@ use crate::VarInt;
use crate::codec::item_stack_seralizer::ItemStackSerializer;
use pumpkin_data::packet::clientbound::PLAY_SET_PLAYER_INVENTORY;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_PLAYER_INVENTORY)]
#[java_packet(PLAY_SET_PLAYER_INVENTORY)]
pub struct CSetPlayerInventory<'a> {
pub slot: VarInt,
pub item: &'a ItemStackSerializer<'a>,

View File

@ -1,9 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_SET_TIME;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_TIME)]
#[java_packet(PLAY_SET_TIME)]
pub struct CUpdateTime {
pub world_age: i64,
pub time_of_day: i64,

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_TITLE_TEXT;
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_TITLE_TEXT)]
#[java_packet(PLAY_SET_TITLE_TEXT)]
pub struct CTitleText<'a> {
pub title: &'a TextComponent,
}

View File

@ -1,10 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_SET_TITLES_ANIMATION;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_TITLES_ANIMATION)]
#[java_packet(PLAY_SET_TITLES_ANIMATION)]
pub struct CTitleAnimation {
pub fade_in_ticks: i32,
pub stay_ticks: i32,

View File

@ -1,12 +1,12 @@
use pumpkin_data::{packet::clientbound::PLAY_SOUND, sound::SoundCategory};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
use crate::{IdOr, SoundEvent, VarInt};
#[derive(Serialize)]
#[packet(PLAY_SOUND)]
#[java_packet(PLAY_SOUND)]
pub struct CSoundEffect {
pub sound_event: IdOr<SoundEvent>,
pub sound_category: VarInt,

View File

@ -1,15 +1,18 @@
use std::io::Write;
use pumpkin_data::packet::clientbound::PLAY_ADD_ENTITY;
use pumpkin_macros::packet;
use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
use pumpkin_macros::java_packet;
use pumpkin_util::{math::vector3::Vector3, version::MinecraftVersion};
use crate::{VarInt, codec::velocity::Velocity};
use crate::{
ClientPacket, VarInt,
codec::velocity::Velocity,
ser::{NetworkWriteExt, WritingError},
};
#[derive(Serialize)]
#[packet(PLAY_ADD_ENTITY)]
#[java_packet(PLAY_ADD_ENTITY)]
pub struct CSpawnEntity {
pub entity_id: VarInt,
#[serde(with = "uuid::serde::compact")]
pub entity_uuid: uuid::Uuid,
pub r#type: VarInt,
pub position: Vector3<f64>,
@ -46,3 +49,39 @@ impl CSpawnEntity {
}
}
}
impl ClientPacket for CSpawnEntity {
fn write_packet_data(
&self,
write: impl Write,
version: &MinecraftVersion,
) -> Result<(), WritingError> {
let mut write = write;
write.write_var_int(&self.entity_id)?;
write.write_uuid(&self.entity_uuid)?;
write.write_var_int(&self.r#type)?;
write.write_f64_be(self.position.x)?;
write.write_f64_be(self.position.y)?;
write.write_f64_be(self.position.z)?;
// Angles
if version >= &MinecraftVersion::V_1_21_9 {
self.velocity.write(&mut write)?;
}
write.write_u8(self.pitch)?;
write.write_u8(self.yaw)?;
write.write_u8(self.head_yaw)?;
write.write_var_int(&self.data)?;
if version <= &MinecraftVersion::V_1_21_7 {
write.write_i16_be(self.velocity.0.x as i16)?;
write.write_i16_be(self.velocity.0.y as i16)?;
write.write_i16_be(self.velocity.0.z as i16)?;
}
Ok(())
}
}

View File

@ -4,11 +4,11 @@ use crate::codec::var_int::VarInt;
use crate::ser::NetworkWriteExt;
use crate::{ClientPacket, WritingError};
use pumpkin_data::{packet::clientbound::PLAY_STOP_SOUND, sound::SoundCategory};
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
use pumpkin_util::version::MinecraftVersion;
#[packet(PLAY_STOP_SOUND)]
#[java_packet(PLAY_STOP_SOUND)]
pub struct CStopSound {
pub sound_id: Option<ResourceLocation>,
pub category: Option<SoundCategory>,

View File

@ -1,12 +1,12 @@
use pumpkin_data::packet::clientbound::PLAY_STORE_COOKIE;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
/// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian client only accepts cookies of up to 5 kiB in size.
#[derive(Serialize)]
#[packet(PLAY_STORE_COOKIE)]
#[java_packet(PLAY_STORE_COOKIE)]
pub struct CStoreCookie<'a> {
pub key: &'a ResourceLocation,
pub payload: &'a [u8], // 5120,

View File

@ -1,11 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_SUBTITLE_TEXT;
use pumpkin_util::text::TextComponent;
use pumpkin_macros::packet;
use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_SET_SUBTITLE_TEXT)]
#[java_packet(PLAY_SET_SUBTITLE_TEXT)]
pub struct CSubtitle<'a> {
pub subtitle: &'a TextComponent,
}

Some files were not shown because too many files have changed in this diff Show More