diff options
| author | mat <git@matdoes.dev> | 2025-10-07 06:01:19 +0400 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-10-07 06:01:19 +0400 |
| commit | 1cf6d92f1a8be954f6885704c31f317b99b05972 (patch) | |
| tree | ab241a7b6fda815e777b914a8a9a153d23e81f06 | |
| parent | 06807ec3ea7df6e83eed51b38f9d5e3bea9e7045 (diff) | |
| download | azalea-drasl-1cf6d92f1a8be954f6885704c31f317b99b05972.tar.xz | |
update ResolvableProfile data component to 1.21.9
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | azalea-auth/src/game_profile.rs | 115 | ||||
| -rw-r--r-- | azalea-client/src/client.rs | 16 | ||||
| -rw-r--r-- | azalea-client/src/plugins/packet/config/events.rs | 4 | ||||
| -rw-r--r-- | azalea-client/tests/mine_block_rollback.rs | 1 | ||||
| -rw-r--r-- | azalea-client/tests/mine_block_timing.rs | 1 | ||||
| -rw-r--r-- | azalea-client/tests/mine_block_without_rollback.rs | 1 | ||||
| -rw-r--r-- | azalea-client/tests/packet_order_set_carried_item.rs | 3 | ||||
| -rw-r--r-- | azalea-entity/src/data.rs | 51 | ||||
| -rw-r--r-- | azalea-entity/src/metadata.rs | 7 | ||||
| -rw-r--r-- | azalea-inventory/Cargo.toml | 1 | ||||
| -rw-r--r-- | azalea-inventory/src/components/mod.rs (renamed from azalea-inventory/src/components.rs) | 23 | ||||
| -rw-r--r-- | azalea-inventory/src/components/profile.rs | 73 | ||||
| -rw-r--r-- | codegen/lib/code/data_components.py | 8 | ||||
| -rw-r--r-- | codegen/lib/code/entity.py | 5 |
15 files changed, 170 insertions, 140 deletions
@@ -436,6 +436,7 @@ dependencies = [ name = "azalea-inventory" version = "0.14.0+mc1.21.9" dependencies = [ + "azalea-auth", "azalea-buf", "azalea-chat", "azalea-core", diff --git a/azalea-auth/src/game_profile.rs b/azalea-auth/src/game_profile.rs index c944bcc4..4f5bccfd 100644 --- a/azalea-auth/src/game_profile.rs +++ b/azalea-auth/src/game_profile.rs @@ -4,14 +4,14 @@ use std::{ }; use azalea_buf::{ - AzaleaRead, AzaleaReadLimited, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError, + AzBuf, AzaleaRead, AzaleaReadLimited, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError, }; use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; use uuid::Uuid; /// Information about the player that's usually stored on Mojang's servers. -#[derive(Debug, Clone, Default, Eq, PartialEq)] +#[derive(Debug, Clone, Default, Eq, PartialEq, AzBuf)] pub struct GameProfile { /// The UUID of the player. /// @@ -27,26 +27,6 @@ pub struct GameProfile { /// This is an `Arc` to make it cheaper to clone. pub properties: Arc<GameProfileProperties>, } -impl AzaleaRead for GameProfile { - fn azalea_read(buf: &mut io::Cursor<&[u8]>) -> Result<Self, BufReadError> { - let uuid = Uuid::azalea_read(buf)?; - let name = String::azalea_read(buf)?; - let properties = GameProfileProperties::azalea_read(buf)?; - Ok(GameProfile { - uuid, - name, - properties: Arc::new(properties), - }) - } -} -impl AzaleaWrite for GameProfile { - fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { - self.uuid.azalea_write(buf)?; - self.name.azalea_write(buf)?; - self.properties.azalea_write(buf)?; - Ok(()) - } -} impl GameProfile { pub fn new(uuid: Uuid, name: String) -> Self { @@ -60,20 +40,10 @@ impl GameProfile { impl From<SerializableGameProfile> for GameProfile { fn from(value: SerializableGameProfile) -> Self { - let mut properties = IndexMap::new(); - for value in value.properties { - properties.insert( - value.name, - ProfilePropertyValue { - value: value.value, - signature: value.signature, - }, - ); - } Self { - uuid: value.id, - name: value.name, - properties: Arc::new(GameProfileProperties { map: properties }), + uuid: value.id.unwrap_or_default(), + name: value.name.unwrap_or_default(), + properties: Arc::new(value.properties.into()), } } } @@ -134,36 +104,81 @@ impl AzaleaWrite for ProfilePropertyValue { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SerializableGameProfile { - pub id: Uuid, - pub name: String, - pub properties: Vec<SerializableProfilePropertyValue>, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option<Uuid>, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option<String>, + #[serde(default)] + #[serde(skip_serializing_if = "SerializableProfileProperties::is_empty")] + pub properties: SerializableProfileProperties, } impl From<GameProfile> for SerializableGameProfile { fn from(value: GameProfile) -> Self { - let mut properties = Vec::new(); - for (key, value) in &value.properties.map { - properties.push(SerializableProfilePropertyValue { - name: key.clone(), - value: value.value.clone(), - signature: value.signature.clone(), - }); - } Self { - id: value.uuid, - name: value.name, - properties, + id: Some(value.uuid), + name: Some(value.name), + properties: (*value.properties).clone().into(), } } } +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(transparent)] +pub struct SerializableProfileProperties { + pub list: Vec<SerializableProfilePropertyValue>, +} +impl SerializableProfileProperties { + pub fn is_empty(&self) -> bool { + self.list.is_empty() + } +} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SerializableProfilePropertyValue { pub name: String, pub value: String, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] pub signature: Option<String>, } +impl From<GameProfileProperties> for SerializableProfileProperties { + fn from(value: GameProfileProperties) -> Self { + let mut list = Vec::new(); + for (name, entry) in value.map { + list.push(SerializableProfilePropertyValue { + name, + value: entry.value, + signature: entry.signature, + }); + } + Self { list } + } +} +impl From<SerializableProfileProperties> for GameProfileProperties { + fn from(value: SerializableProfileProperties) -> Self { + let mut map = IndexMap::new(); + for entry in value.list { + map.insert( + entry.name, + ProfilePropertyValue { + value: entry.value, + signature: entry.signature, + }, + ); + } + Self { map } + } +} +impl Serialize for GameProfile { + fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + let serializable = SerializableGameProfile::from(self.clone()); + serializable.serialize(serializer) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index bb827838..cf07f8b2 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -261,12 +261,13 @@ impl Client { /// return it. /// /// - /// If the component can't be cloned, try [`Self::map_component`] instead. - /// If it isn't guaranteed to be present, use [`Self::get_component`] or - /// [`Self::map_get_component`]. + /// If the component can't be cloned, try [`Self::query_self`] instead. + /// If it isn't guaranteed to be present, you can use + /// [`Self::get_component`] or [`Self::query_self`]. /// - /// You may also use [`Self::ecs`] and [`Self::query`] directly if you need - /// more control over when the ECS is locked. + /// + /// You may also use [`Self::ecs`] directly if you need more control over + /// when the ECS is locked. /// /// # Panics /// @@ -285,9 +286,10 @@ impl Client { /// Get a component from this client, or `None` if it doesn't exist. /// - /// If the component can't be cloned, try [`Self::map_component`] instead. + /// If the component can't be cloned, consider using [`Self::query_self`] + /// with `Option<&T>` instead. /// - /// You may also have to use [`Self::with_query`] directly. + /// You may also have to use [`Self::query_self`] directly. pub fn get_component<T: Component + Clone>(&self) -> Option<T> { self.query_self::<Option<&T>, _>(|t| t.cloned()) } diff --git a/azalea-client/src/plugins/packet/config/events.rs b/azalea-client/src/plugins/packet/config/events.rs index be5cfdb1..92df8d74 100644 --- a/azalea-client/src/plugins/packet/config/events.rs +++ b/azalea-client/src/plugins/packet/config/events.rs @@ -54,10 +54,10 @@ pub fn handle_outgoing_packets_observer( /// A Bevy trigger that's sent when our client receives a [`ClientboundPing`] /// packet in the config state. /// -/// Also see [`PingEvent`]. +/// Also see [`GamePingEvent`]. /// /// [`ClientboundPing`]: azalea_protocol::packets::config::ClientboundPing -/// [`PingEvent`]: crate::packet::game::PingEvent +/// [`GamePingEvent`]: crate::packet::game::GamePingEvent #[derive(Event, Debug, Clone)] pub struct ConfigPingEvent { pub entity: Entity, diff --git a/azalea-client/tests/mine_block_rollback.rs b/azalea-client/tests/mine_block_rollback.rs index 67a66169..44ad629f 100644 --- a/azalea-client/tests/mine_block_rollback.rs +++ b/azalea-client/tests/mine_block_rollback.rs @@ -30,6 +30,7 @@ fn test_mine_block_rollback() { simulation.write_message(StartMiningBlockEvent { entity: simulation.entity, position: pos, + force: true, }); simulation.tick(); assert_eq!(simulation.get_block_state(pos), Some(Block::Air.into())); diff --git a/azalea-client/tests/mine_block_timing.rs b/azalea-client/tests/mine_block_timing.rs index 1cbd2f61..6548b28a 100644 --- a/azalea-client/tests/mine_block_timing.rs +++ b/azalea-client/tests/mine_block_timing.rs @@ -57,6 +57,7 @@ fn test_mine_block_timing() { simulation.write_message(StartMiningBlockEvent { entity: simulation.entity, position: pos, + force: false, }); sent_packets.clear(); simulation.tick(); diff --git a/azalea-client/tests/mine_block_without_rollback.rs b/azalea-client/tests/mine_block_without_rollback.rs index 16a371e5..a5a437a0 100644 --- a/azalea-client/tests/mine_block_without_rollback.rs +++ b/azalea-client/tests/mine_block_without_rollback.rs @@ -29,6 +29,7 @@ fn test_mine_block_without_rollback() { simulation.write_message(StartMiningBlockEvent { entity: simulation.entity, position: pos, + force: true, }); simulation.tick(); assert_eq!(simulation.get_block_state(pos), Some(Block::Air.into())); diff --git a/azalea-client/tests/packet_order_set_carried_item.rs b/azalea-client/tests/packet_order_set_carried_item.rs index 0506ad8e..a357dec0 100644 --- a/azalea-client/tests/packet_order_set_carried_item.rs +++ b/azalea-client/tests/packet_order_set_carried_item.rs @@ -55,13 +55,14 @@ fn test_packet_order_set_carried_item() { simulation.tick(); simulation.tick(); - simulation.write_message(SetSelectedHotbarSlotEvent { + simulation.trigger(SetSelectedHotbarSlotEvent { entity: simulation.entity, slot: 1, }); simulation.write_message(StartMiningBlockEvent { entity: simulation.entity, position: pos, + force: false, }); sent_packets.clear(); diff --git a/azalea-entity/src/data.rs b/azalea-entity/src/data.rs index 84a5b153..65267c4a 100644 --- a/azalea-entity/src/data.rs +++ b/azalea-entity/src/data.rs @@ -2,15 +2,13 @@ use std::io::{self, Cursor, Write}; -use azalea_auth::game_profile::{GameProfile, GameProfileProperties}; use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError}; use azalea_chat::FormattedText; use azalea_core::{ direction::Direction, position::{BlockPos, GlobalPos, Vec3f32}, - resource_location::ResourceLocation, }; -use azalea_inventory::ItemStack; +use azalea_inventory::{ItemStack, components}; use bevy_ecs::component::Component; use derive_more::Deref; use enum_as_inner::EnumAsInner; @@ -97,7 +95,7 @@ pub enum EntityDataValue { WeatheringCopperState(WeatheringCopperStateKind), Vector3(Vec3f32), Quaternion(Quaternion), - ResolvableProfile(ResolvableProfile), + ResolvableProfile(components::Profile), } #[derive(Clone, Debug, PartialEq)] @@ -111,51 +109,6 @@ pub struct Quaternion { pub w: f32, } -#[derive(Clone, Debug, AzBuf, Default, PartialEq)] -pub struct ResolvableProfile { - pub unpack: Box<PartialOrFullProfile>, - pub skin_patch: Box<PlayerSkinPatch>, -} - -#[derive(Clone, Debug, AzBuf, PartialEq)] -pub enum PartialOrFullProfile { - Partial(PartialProfile), - Full(GameProfile), -} -impl Default for PartialOrFullProfile { - fn default() -> Self { - Self::Partial(PartialProfile::default()) - } -} - -#[derive(Clone, Debug, AzBuf, Default, PartialEq)] -pub struct PartialProfile { - #[limit(16)] - pub name: Option<String>, - pub id: Option<Uuid>, - pub properties: GameProfileProperties, -} - -#[derive(Clone, Debug, AzBuf, Default, PartialEq)] -pub struct PlayerSkinPatch { - pub body: Option<ResourceTexture>, - pub cape: Option<ResourceTexture>, - pub elytra: Option<ResourceTexture>, - pub model: Option<PlayerModelType>, -} - -#[derive(Clone, Debug, Copy, AzBuf, Default, PartialEq)] -pub enum PlayerModelType { - #[default] - Wide, - Slim, -} - -#[derive(Clone, Debug, AzBuf, PartialEq)] -pub struct ResourceTexture { - pub id: ResourceLocation, -} - // mojang just calls this ArmadilloState but i added "Kind" since otherwise it // collides with a name in metadata.rs #[derive(Clone, Debug, Copy, Default, AzBuf, PartialEq)] diff --git a/azalea-entity/src/metadata.rs b/azalea-entity/src/metadata.rs index 56455bb7..68b8b78c 100644 --- a/azalea-entity/src/metadata.rs +++ b/azalea-entity/src/metadata.rs @@ -8,7 +8,7 @@ use azalea_core::{ direction::Direction, position::{BlockPos, Vec3f32}, }; -use azalea_inventory::ItemStack; +use azalea_inventory::{ItemStack, components}; use azalea_registry::DataRegistry; use bevy_ecs::{bundle::Bundle, component::Component}; use derive_more::{Deref, DerefMut}; @@ -17,8 +17,7 @@ use uuid::Uuid; use super::{ ArmadilloStateKind, CopperGolemStateKind, EntityDataItem, EntityDataValue, OptionalUnsignedInt, - Pose, Quaternion, ResolvableProfile, Rotations, SnifferStateKind, VillagerData, - WeatheringCopperStateKind, + Pose, Quaternion, Rotations, SnifferStateKind, VillagerData, WeatheringCopperStateKind, }; use crate::particle::Particle; @@ -6054,7 +6053,7 @@ pub struct MannequinPlayerMainHand(pub u8); #[derive(Component, Deref, DerefMut, Clone, PartialEq)] pub struct MannequinPlayerModeCustomisation(pub u8); #[derive(Component, Deref, DerefMut, Clone, PartialEq)] -pub struct Profile(pub ResolvableProfile); +pub struct Profile(pub components::Profile); #[derive(Component, Deref, DerefMut, Clone, PartialEq)] pub struct Immovable(pub bool); #[derive(Component, Deref, DerefMut, Clone, PartialEq)] diff --git a/azalea-inventory/Cargo.toml b/azalea-inventory/Cargo.toml index d10aa787..8fb1d625 100644 --- a/azalea-inventory/Cargo.toml +++ b/azalea-inventory/Cargo.toml @@ -7,6 +7,7 @@ license.workspace = true repository.workspace = true [dependencies] +azalea-auth.workspace = true azalea-buf.workspace = true azalea-chat = { workspace = true, features = ["azalea-buf"] } azalea-core.workspace = true diff --git a/azalea-inventory/src/components.rs b/azalea-inventory/src/components/mod.rs index b820afc9..5661547a 100644 --- a/azalea-inventory/src/components.rs +++ b/azalea-inventory/src/components/mod.rs @@ -1,3 +1,5 @@ +mod profile; + use core::f64; use std::{ any::Any, @@ -21,10 +23,10 @@ use azalea_registry::{ self as registry, Attribute, Block, DamageKind, DataComponentKind, Enchantment, EntityKind, Holder, HolderSet, Item, MobEffect, Potion, SoundEvent, TrimMaterial, TrimPattern, }; +pub use profile::*; use serde::{Serialize, ser::SerializeMap}; use simdnbt::owned::{Nbt, NbtCompound}; use tracing::trace; -use uuid::Uuid; use crate::{ItemStack, item::consume_effect::ConsumeEffect}; @@ -835,25 +837,6 @@ impl Default for Fireworks { } #[derive(Clone, PartialEq, AzBuf, Debug, Serialize)] -pub struct GameProfileProperty { - pub name: String, - pub value: String, - #[serde(skip_serializing_if = "is_default")] - pub signature: Option<String>, -} - -#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)] -pub struct Profile { - #[serde(skip_serializing_if = "is_default")] - pub name: Option<String>, - #[serde(skip_serializing_if = "is_default")] - #[serde(serialize_with = "azalea_core::codec_utils::uuid")] - pub id: Option<Uuid>, - #[serde(skip_serializing_if = "is_default")] - pub properties: Vec<GameProfileProperty>, -} - -#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)] #[serde(transparent)] pub struct NoteBlockSound { pub sound: ResourceLocation, diff --git a/azalea-inventory/src/components/profile.rs b/azalea-inventory/src/components/profile.rs new file mode 100644 index 00000000..9966bc8f --- /dev/null +++ b/azalea-inventory/src/components/profile.rs @@ -0,0 +1,73 @@ +use azalea_auth::game_profile::{ + GameProfile, GameProfileProperties, SerializableProfileProperties, +}; +use azalea_buf::AzBuf; +use azalea_core::{codec_utils::*, resource_location::ResourceLocation}; +use serde::{Serialize, Serializer}; +use uuid::Uuid; + +#[derive(Clone, Debug, AzBuf, Default, PartialEq, Serialize)] +#[doc(alias = "ResolvableProfile")] +pub struct Profile { + #[serde(flatten)] + pub unpack: Box<PartialOrFullProfile>, + #[serde(flatten)] + pub skin_patch: Box<PlayerSkinPatch>, +} + +#[derive(Clone, Debug, AzBuf, PartialEq, Serialize)] +#[serde(untagged)] +pub enum PartialOrFullProfile { + Partial(PartialProfile), + Full(GameProfile), +} +impl Default for PartialOrFullProfile { + fn default() -> Self { + Self::Partial(PartialProfile::default()) + } +} + +#[derive(Clone, Debug, AzBuf, Default, PartialEq, Serialize)] +pub struct PartialProfile { + #[limit(16)] + #[serde(skip_serializing_if = "is_default")] + pub name: Option<String>, + #[serde(skip_serializing_if = "is_default")] + pub id: Option<Uuid>, + #[serde(serialize_with = "serialize_properties")] + pub properties: GameProfileProperties, +} +fn serialize_properties<S: Serializer>( + properties: &GameProfileProperties, + serializer: S, +) -> Result<S::Ok, S::Error> { + let serializable = SerializableProfileProperties::from(properties.clone()); + serializable.serialize(serializer) +} + +#[derive(Clone, Debug, AzBuf, Default, PartialEq, Serialize)] +pub struct PlayerSkinPatch { + #[serde(rename = "texture")] + #[serde(skip_serializing_if = "is_default")] + pub body: Option<ResourceTexture>, + #[serde(skip_serializing_if = "is_default")] + pub cape: Option<ResourceTexture>, + #[serde(skip_serializing_if = "is_default")] + pub elytra: Option<ResourceTexture>, + #[serde(skip_serializing_if = "is_default")] + pub model: Option<PlayerModelType>, +} + +#[derive(Clone, Debug, Copy, AzBuf, Default, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum PlayerModelType { + #[default] + Wide, + Slim, +} + +#[derive(Clone, Debug, AzBuf, PartialEq, Serialize)] +#[serde(transparent)] +pub struct ResourceTexture { + pub id: ResourceLocation, +} diff --git a/codegen/lib/code/data_components.py b/codegen/lib/code/data_components.py index b1444860..89796a91 100644 --- a/codegen/lib/code/data_components.py +++ b/codegen/lib/code/data_components.py @@ -4,7 +4,7 @@ import lib.extract import lib.utils -DATA_COMPONENTS_DIR = "azalea-inventory/src/components.rs" +DATA_COMPONENTS_DIR = "azalea-inventory/src/components/mod.rs" DEFAULT_DATA_COMPONENTS_DIR = "azalea-inventory/src/default_components/generated.rs" @@ -322,7 +322,7 @@ use crate::{ entity_id = python_value["id"] elif isinstance(python_value, str): entity_id = python_value - + if entity_id and entity_id.startswith("minecraft:"): entity_name = entity_id[10:] # Remove "minecraft:" prefix entity_name_camel = lib.utils.to_camel_case(entity_name) @@ -512,7 +512,7 @@ use crate::{ # Special handling for EntityData to use EntityData structure # Keep rust_value as "value" so it gets processed correctly field_type = "EntityKind" - + def transform_value_fn(rust_value: str): return f"{component_struct_name} {{ kind: {rust_value}, data: NbtCompound::new() }}" @@ -623,7 +623,7 @@ use crate::{ def get_enum_and_struct_fields(): """ Returns a map like map like `{ "MaxStackSize": { "count": i32 }, "Rarity": [ "common", ... ], ... }` - with an entry for each struct in components.rs. + with an entry for each struct in components/mod.rs. """ with open(DATA_COMPONENTS_DIR, "r") as f: diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py index 1c2a0d48..18a7a04b 100644 --- a/codegen/lib/code/entity.py +++ b/codegen/lib/code/entity.py @@ -113,7 +113,7 @@ use azalea_core::{ direction::Direction, position::{BlockPos, Vec3f32}, }; -use azalea_inventory::ItemStack; +use azalea_inventory::{ItemStack, components}; use azalea_registry::DataRegistry; use bevy_ecs::{bundle::Bundle, component::Component}; use derive_more::{Deref, DerefMut}; @@ -122,8 +122,7 @@ use uuid::Uuid; use super::{ ArmadilloStateKind, CopperGolemStateKind, EntityDataItem, EntityDataValue, OptionalUnsignedInt, - Pose, Quaternion, ResolvableProfile, Rotations, SnifferStateKind, VillagerData, - WeatheringCopperStateKind, + Pose, Quaternion, Rotations, SnifferStateKind, VillagerData, WeatheringCopperStateKind, }; use crate::particle::Particle; |
