use core::f64; use std::{any::Any, collections::HashMap, io::Cursor}; use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; use azalea_chat::FormattedText; use azalea_core::{position::GlobalPos, resource_location::ResourceLocation}; use azalea_registry::{ Attribute, Block, ConsumeEffectKind, DataComponentKind, Enchantment, EntityKind, HolderSet, Item, MobEffect, Potion, SoundEvent, TrimMaterial, TrimPattern, }; use simdnbt::owned::{Nbt, NbtCompound}; use uuid::Uuid; use crate::ItemSlot; pub trait DataComponent: Send + Sync + Any {} pub trait EncodableDataComponent: Send + Sync + Any { fn encode(&self, buf: &mut Vec) -> Result<(), std::io::Error>; // using the Clone trait makes it not be object-safe, so we have our own clone // function instead fn clone(&self) -> Box; // same deal here fn eq(&self, other: Box) -> bool; } impl EncodableDataComponent for T where T: DataComponent + Clone + McBufWritable + McBufReadable + PartialEq, { fn encode(&self, buf: &mut Vec) -> Result<(), std::io::Error> { self.write_into(buf) } fn clone(&self) -> Box { let cloned = self.clone(); Box::new(cloned) } fn eq(&self, other: Box) -> bool { let other_any: Box = other; if let Some(other) = other_any.downcast_ref::() { self == other } else { false } } } pub fn from_kind( kind: azalea_registry::DataComponentKind, buf: &mut Cursor<&[u8]>, ) -> Result, BufReadError> { // if this is causing a compile-time error, look at DataComponents.java in the // decompiled vanilla code to see how to implement new components // note that this match statement is updated by genitemcomponents.py Ok(match kind { DataComponentKind::CustomData => Box::new(CustomData::read_from(buf)?), DataComponentKind::MaxStackSize => Box::new(MaxStackSize::read_from(buf)?), DataComponentKind::MaxDamage => Box::new(MaxDamage::read_from(buf)?), DataComponentKind::Damage => Box::new(Damage::read_from(buf)?), DataComponentKind::Unbreakable => Box::new(Unbreakable::read_from(buf)?), DataComponentKind::CustomName => Box::new(CustomName::read_from(buf)?), DataComponentKind::ItemName => Box::new(ItemName::read_from(buf)?), DataComponentKind::Lore => Box::new(Lore::read_from(buf)?), DataComponentKind::Rarity => Box::new(Rarity::read_from(buf)?), DataComponentKind::Enchantments => Box::new(Enchantments::read_from(buf)?), DataComponentKind::CanPlaceOn => Box::new(CanPlaceOn::read_from(buf)?), DataComponentKind::CanBreak => Box::new(CanBreak::read_from(buf)?), DataComponentKind::AttributeModifiers => Box::new(AttributeModifiers::read_from(buf)?), DataComponentKind::CustomModelData => Box::new(CustomModelData::read_from(buf)?), DataComponentKind::HideAdditionalTooltip => { Box::new(HideAdditionalTooltip::read_from(buf)?) } DataComponentKind::HideTooltip => Box::new(HideTooltip::read_from(buf)?), DataComponentKind::RepairCost => Box::new(RepairCost::read_from(buf)?), DataComponentKind::CreativeSlotLock => Box::new(CreativeSlotLock::read_from(buf)?), DataComponentKind::EnchantmentGlintOverride => { Box::new(EnchantmentGlintOverride::read_from(buf)?) } DataComponentKind::IntangibleProjectile => Box::new(IntangibleProjectile::read_from(buf)?), DataComponentKind::Food => Box::new(Food::read_from(buf)?), DataComponentKind::Tool => Box::new(Tool::read_from(buf)?), DataComponentKind::StoredEnchantments => Box::new(StoredEnchantments::read_from(buf)?), DataComponentKind::DyedColor => Box::new(DyedColor::read_from(buf)?), DataComponentKind::MapColor => Box::new(MapColor::read_from(buf)?), DataComponentKind::MapId => Box::new(MapId::read_from(buf)?), DataComponentKind::MapDecorations => Box::new(MapDecorations::read_from(buf)?), DataComponentKind::MapPostProcessing => Box::new(MapPostProcessing::read_from(buf)?), DataComponentKind::ChargedProjectiles => Box::new(ChargedProjectiles::read_from(buf)?), DataComponentKind::BundleContents => Box::new(BundleContents::read_from(buf)?), DataComponentKind::PotionContents => Box::new(PotionContents::read_from(buf)?), DataComponentKind::SuspiciousStewEffects => { Box::new(SuspiciousStewEffects::read_from(buf)?) } DataComponentKind::WritableBookContent => Box::new(WritableBookContent::read_from(buf)?), DataComponentKind::WrittenBookContent => Box::new(WrittenBookContent::read_from(buf)?), DataComponentKind::Trim => Box::new(Trim::read_from(buf)?), DataComponentKind::DebugStickState => Box::new(DebugStickState::read_from(buf)?), DataComponentKind::EntityData => Box::new(EntityData::read_from(buf)?), DataComponentKind::BucketEntityData => Box::new(BucketEntityData::read_from(buf)?), DataComponentKind::BlockEntityData => Box::new(BlockEntityData::read_from(buf)?), DataComponentKind::Instrument => Box::new(Instrument::read_from(buf)?), DataComponentKind::OminousBottleAmplifier => { Box::new(OminousBottleAmplifier::read_from(buf)?) } DataComponentKind::Recipes => Box::new(Recipes::read_from(buf)?), DataComponentKind::LodestoneTracker => Box::new(LodestoneTracker::read_from(buf)?), DataComponentKind::FireworkExplosion => Box::new(FireworkExplosion::read_from(buf)?), DataComponentKind::Fireworks => Box::new(Fireworks::read_from(buf)?), DataComponentKind::Profile => Box::new(Profile::read_from(buf)?), DataComponentKind::NoteBlockSound => Box::new(NoteBlockSound::read_from(buf)?), DataComponentKind::BannerPatterns => Box::new(BannerPatterns::read_from(buf)?), DataComponentKind::BaseColor => Box::new(BaseColor::read_from(buf)?), DataComponentKind::PotDecorations => Box::new(PotDecorations::read_from(buf)?), DataComponentKind::Container => Box::new(Container::read_from(buf)?), DataComponentKind::BlockState => Box::new(BlockState::read_from(buf)?), DataComponentKind::Bees => Box::new(Bees::read_from(buf)?), DataComponentKind::Lock => Box::new(Lock::read_from(buf)?), DataComponentKind::ContainerLoot => Box::new(ContainerLoot::read_from(buf)?), DataComponentKind::JukeboxPlayable => Box::new(JukeboxPlayable::read_from(buf)?), DataComponentKind::Consumable => Box::new(Consumable::read_from(buf)?), DataComponentKind::UseRemainder => Box::new(UseRemainder::read_from(buf)?), DataComponentKind::UseCooldown => Box::new(UseCooldown::read_from(buf)?), DataComponentKind::Enchantable => Box::new(Enchantable::read_from(buf)?), DataComponentKind::Repairable => Box::new(Repairable::read_from(buf)?), DataComponentKind::ItemModel => Box::new(ItemModel::read_from(buf)?), DataComponentKind::DamageResistant => Box::new(DamageResistant::read_from(buf)?), DataComponentKind::Equippable => Box::new(Equippable::read_from(buf)?), DataComponentKind::Glider => Box::new(Glider::read_from(buf)?), DataComponentKind::TooltipStyle => Box::new(TooltipStyle::read_from(buf)?), DataComponentKind::DeathProtection => Box::new(DeathProtection::read_from(buf)?), }) } #[derive(Clone, PartialEq, McBuf)] pub struct CustomData { pub nbt: Nbt, } impl DataComponent for CustomData {} #[derive(Clone, PartialEq, McBuf)] pub struct MaxStackSize { #[var] pub count: i32, } impl DataComponent for MaxStackSize {} #[derive(Clone, PartialEq, McBuf)] pub struct MaxDamage { #[var] pub amount: i32, } impl DataComponent for MaxDamage {} #[derive(Clone, PartialEq, McBuf)] pub struct Damage { #[var] pub amount: i32, } impl DataComponent for Damage {} #[derive(Clone, PartialEq, McBuf)] pub struct Unbreakable { pub show_in_tooltip: bool, } impl DataComponent for Unbreakable {} impl Default for Unbreakable { fn default() -> Self { Self { show_in_tooltip: true, } } } #[derive(Clone, PartialEq, McBuf)] pub struct CustomName { pub name: FormattedText, } impl DataComponent for CustomName {} #[derive(Clone, PartialEq, McBuf)] pub struct ItemName { pub name: FormattedText, } impl DataComponent for ItemName {} #[derive(Clone, PartialEq, McBuf)] pub struct Lore { pub lines: Vec, // vanilla also has styled_lines here but it doesn't appear to be used for the protocol } impl DataComponent for Lore {} #[derive(Clone, PartialEq, Copy, McBuf)] pub enum Rarity { Common, Uncommon, Rare, Epic, } impl DataComponent for Rarity {} #[derive(Clone, PartialEq, McBuf)] pub struct Enchantments { #[var] pub levels: HashMap, pub show_in_tooltip: bool, } impl DataComponent for Enchantments {} #[derive(Clone, PartialEq, McBuf)] pub enum BlockStateValueMatcher { Exact { value: String, }, Range { min: Option, max: Option, }, } #[derive(Clone, PartialEq, McBuf)] pub struct BlockStatePropertyMatcher { pub name: String, pub value_matcher: BlockStateValueMatcher, } #[derive(Clone, PartialEq, McBuf)] pub struct BlockPredicate { pub blocks: Option>, pub properties: Option>, pub nbt: Option, } #[derive(Clone, PartialEq, McBuf)] pub struct AdventureModePredicate { pub predicates: Vec, pub show_in_tooltip: bool, } #[derive(Clone, PartialEq, McBuf)] pub struct CanPlaceOn { pub predicate: AdventureModePredicate, } impl DataComponent for CanPlaceOn {} #[derive(Clone, PartialEq, McBuf)] pub struct CanBreak { pub predicate: AdventureModePredicate, } impl DataComponent for CanBreak {} #[derive(Clone, Copy, PartialEq, McBuf)] pub enum EquipmentSlotGroup { Any, Mainhand, Offhand, Hand, Feet, Legs, Chest, Head, Armor, Body, } #[derive(Clone, Copy, PartialEq, McBuf)] pub enum AttributeModifierOperation { Addition, MultiplyBase, MultiplyTotal, } // this is duplicated in azalea-entity, BUT the one there has a different // protocol format (and we can't use it anyways because it would cause a // circular dependency) #[derive(Clone, PartialEq, McBuf)] pub struct AttributeModifier { pub uuid: Uuid, pub name: String, pub amount: f64, pub operation: AttributeModifierOperation, } #[derive(Clone, PartialEq, McBuf)] pub struct AttributeModifiersEntry { pub attribute: Attribute, pub modifier: AttributeModifier, pub slot: EquipmentSlotGroup, } #[derive(Clone, PartialEq, McBuf)] pub struct AttributeModifiers { pub modifiers: Vec, pub show_in_tooltip: bool, } impl DataComponent for AttributeModifiers {} #[derive(Clone, PartialEq, McBuf)] pub struct CustomModelData { #[var] pub value: i32, } impl DataComponent for CustomModelData {} #[derive(Clone, PartialEq, McBuf)] pub struct HideAdditionalTooltip; impl DataComponent for HideAdditionalTooltip {} #[derive(Clone, PartialEq, McBuf)] pub struct HideTooltip; impl DataComponent for HideTooltip {} #[derive(Clone, PartialEq, McBuf)] pub struct RepairCost { #[var] pub cost: u32, } impl DataComponent for RepairCost {} #[derive(Clone, PartialEq, McBuf)] pub struct CreativeSlotLock; impl DataComponent for CreativeSlotLock {} #[derive(Clone, PartialEq, McBuf)] pub struct EnchantmentGlintOverride { pub show_glint: bool, } impl DataComponent for EnchantmentGlintOverride {} #[derive(Clone, PartialEq, McBuf)] pub struct IntangibleProjectile; impl DataComponent for IntangibleProjectile {} #[derive(Clone, PartialEq, McBuf)] pub struct MobEffectDetails { #[var] pub amplifier: i32, #[var] pub duration: i32, pub ambient: bool, pub show_particles: bool, pub show_icon: bool, pub hidden_effect: Option>, } #[derive(Clone, PartialEq, McBuf)] pub struct MobEffectInstance { pub effect: MobEffect, pub details: MobEffectDetails, } #[derive(Clone, PartialEq, McBuf)] pub struct PossibleEffect { pub effect: MobEffectInstance, pub probability: f32, } #[derive(Clone, PartialEq, McBuf)] pub struct Food { #[var] pub nutrition: i32, pub saturation: f32, pub can_always_eat: bool, pub eat_seconds: f32, pub effects: Vec, } impl DataComponent for Food {} #[derive(Clone, PartialEq, McBuf)] pub struct ToolRule { pub blocks: HolderSet, pub speed: Option, pub correct_for_drops: Option, } #[derive(Clone, PartialEq, McBuf)] pub struct Tool { pub rules: Vec, pub default_mining_speed: f32, #[var] pub damage_per_block: i32, } impl DataComponent for Tool {} #[derive(Clone, PartialEq, McBuf)] pub struct StoredEnchantments { #[var] pub enchantments: HashMap, pub show_in_tooltip: bool, } impl DataComponent for StoredEnchantments {} #[derive(Clone, PartialEq, McBuf)] pub struct DyedColor { pub rgb: i32, pub show_in_tooltip: bool, } impl DataComponent for DyedColor {} #[derive(Clone, PartialEq, McBuf)] pub struct MapColor { pub color: i32, } impl DataComponent for MapColor {} #[derive(Clone, PartialEq, McBuf)] pub struct MapId { #[var] pub id: i32, } impl DataComponent for MapId {} #[derive(Clone, PartialEq, McBuf)] pub struct MapDecorations { pub decorations: NbtCompound, } impl DataComponent for MapDecorations {} #[derive(Clone, Copy, PartialEq, McBuf)] pub enum MapPostProcessing { Lock, Scale, } impl DataComponent for MapPostProcessing {} #[derive(Clone, PartialEq, McBuf)] pub struct ChargedProjectiles { pub items: Vec, } impl DataComponent for ChargedProjectiles {} #[derive(Clone, PartialEq, McBuf)] pub struct BundleContents { pub items: Vec, } impl DataComponent for BundleContents {} #[derive(Clone, PartialEq, McBuf)] pub struct PotionContents { pub potion: Option, pub custom_color: Option, pub custom_effects: Vec, } impl DataComponent for PotionContents {} #[derive(Clone, PartialEq, McBuf)] pub struct SuspiciousStewEffect { pub effect: MobEffect, #[var] pub duration: i32, } #[derive(Clone, PartialEq, McBuf)] pub struct SuspiciousStewEffects { pub effects: Vec, } impl DataComponent for SuspiciousStewEffects {} #[derive(Clone, PartialEq, McBuf)] pub struct WritableBookContent { pub pages: Vec, } impl DataComponent for WritableBookContent {} #[derive(Clone, PartialEq, McBuf)] pub struct WrittenBookContent { pub title: String, pub author: String, #[var] pub generation: i32, pub pages: Vec, pub resolved: bool, } impl DataComponent for WrittenBookContent {} #[derive(Clone, PartialEq, McBuf)] pub struct Trim { pub material: TrimMaterial, pub pattern: TrimPattern, pub show_in_tooltip: bool, } impl DataComponent for Trim {} #[derive(Clone, PartialEq, McBuf)] pub struct DebugStickState { pub properties: NbtCompound, } impl DataComponent for DebugStickState {} #[derive(Clone, PartialEq, McBuf)] pub struct EntityData { pub entity: NbtCompound, } impl DataComponent for EntityData {} #[derive(Clone, PartialEq, McBuf)] pub struct BucketEntityData { pub entity: NbtCompound, } impl DataComponent for BucketEntityData {} #[derive(Clone, PartialEq, McBuf)] pub struct BlockEntityData { pub entity: NbtCompound, } impl DataComponent for BlockEntityData {} #[derive(Clone, PartialEq, McBuf)] pub struct Instrument { pub instrument: azalea_registry::Instrument, } impl DataComponent for Instrument {} #[derive(Clone, PartialEq, McBuf)] pub struct OminousBottleAmplifier { #[var] pub amplifier: i32, } impl DataComponent for OminousBottleAmplifier {} #[derive(Clone, PartialEq, McBuf)] pub struct Recipes { pub recipes: Vec, } impl DataComponent for Recipes {} #[derive(Clone, PartialEq, McBuf)] pub struct LodestoneTracker { pub target: Option, pub tracked: bool, } impl DataComponent for LodestoneTracker {} #[derive(Clone, Copy, PartialEq, McBuf)] pub enum FireworkExplosionShape { SmallBall, LargeBall, Star, Creeper, Burst, } #[derive(Clone, PartialEq, McBuf)] pub struct FireworkExplosion { pub shape: FireworkExplosionShape, pub colors: Vec, pub fade_colors: Vec, pub has_trail: bool, pub has_twinkle: bool, } impl DataComponent for FireworkExplosion {} #[derive(Clone, PartialEq, McBuf)] pub struct Fireworks { #[var] pub flight_duration: i32, pub explosions: Vec, } impl DataComponent for Fireworks {} #[derive(Clone, PartialEq, McBuf)] pub struct GameProfileProperty { pub name: String, pub value: String, pub signature: Option, } #[derive(Clone, PartialEq, McBuf)] pub struct Profile { pub name: String, pub id: Option, pub properties: Vec, } impl DataComponent for Profile {} #[derive(Clone, PartialEq, McBuf)] pub struct NoteBlockSound { pub sound: ResourceLocation, } impl DataComponent for NoteBlockSound {} #[derive(Clone, PartialEq, McBuf)] pub struct BannerPattern { #[var] pub pattern: i32, #[var] pub color: i32, } #[derive(Clone, PartialEq, McBuf)] pub struct BannerPatterns { pub patterns: Vec, } impl DataComponent for BannerPatterns {} #[derive(Clone, Copy, PartialEq, McBuf)] pub enum DyeColor { White, Orange, Magenta, LightBlue, Yellow, Lime, Pink, Gray, LightGray, Cyan, Purple, Blue, Brown, Green, Red, Black, } #[derive(Clone, PartialEq, McBuf)] pub struct BaseColor { pub color: DyeColor, } impl DataComponent for BaseColor {} #[derive(Clone, PartialEq, McBuf)] pub struct PotDecorations { pub items: Vec, } impl DataComponent for PotDecorations {} #[derive(Clone, PartialEq, McBuf)] pub struct Container { pub items: Vec, } impl DataComponent for Container {} #[derive(Clone, PartialEq, McBuf)] pub struct BlockState { pub properties: HashMap, } impl DataComponent for BlockState {} #[derive(Clone, PartialEq, McBuf)] pub struct BeehiveOccupant { pub entity_data: NbtCompound, #[var] pub ticks_in_hive: i32, #[var] pub min_ticks_in_hive: i32, } #[derive(Clone, PartialEq, McBuf)] pub struct Bees { pub occupants: Vec, } impl DataComponent for Bees {} #[derive(Clone, PartialEq, McBuf)] pub struct Lock { pub key: String, } impl DataComponent for Lock {} #[derive(Clone, PartialEq, McBuf)] pub struct ContainerLoot { pub loot: NbtCompound, } impl DataComponent for ContainerLoot {} #[derive(Clone, PartialEq, McBuf)] pub struct JukeboxPlayable { pub song: azalea_registry::JukeboxSong, pub show_in_tooltip: bool, } impl DataComponent for JukeboxPlayable {} #[derive(Clone, PartialEq, McBuf)] pub struct Consumable { pub consume_seconds: f32, pub animation: ItemUseAnimation, pub sound: SoundEvent, pub has_consume_particles: bool, pub on_consuime_effects: Vec, } impl DataComponent for Consumable {} #[derive(Clone, Copy, PartialEq, McBuf)] pub enum ItemUseAnimation { None, Eat, Drink, Block, Bow, Spear, Crossbow, Spyglass, TootHorn, Brush, } #[derive(Clone, PartialEq, McBuf)] pub struct UseRemainder { pub convert_into: ItemSlot, } impl DataComponent for UseRemainder {} #[derive(Clone, PartialEq, McBuf)] pub struct UseCooldown { pub seconds: f32, pub cooldown_group: Option, } impl DataComponent for UseCooldown {} #[derive(Clone, PartialEq, McBuf)] pub struct Enchantable { #[var] pub value: u32, } impl DataComponent for Enchantable {} #[derive(Clone, PartialEq, McBuf)] pub struct Repairable { pub items: HolderSet, } impl DataComponent for Repairable {} #[derive(Clone, PartialEq, McBuf)] pub struct ItemModel { pub resource_location: ResourceLocation, } impl DataComponent for ItemModel {} #[derive(Clone, PartialEq, McBuf)] pub struct DamageResistant { // in the vanilla code this is // ``` // StreamCodec.composite( // TagKey.streamCodec(Registries.DAMAGE_TYPE), DamageResistant::types, DamageResistant::new // ); // ``` // i'm not entirely sure if this is meant to be a vec or something, i just made it a // resourcelocation for now pub types: ResourceLocation, } impl DataComponent for DamageResistant {} #[derive(Clone, PartialEq, McBuf)] pub struct Equippable { pub slot: EquipmentSlot, pub equip_sound: SoundEvent, pub model: Option, pub allowed_entities: HolderSet, } impl DataComponent for Equippable {} #[derive(Clone, Copy, Debug, PartialEq, McBuf)] pub enum EquipmentSlot { Mainhand, Offhand, Hand, Feet, Legs, Chest, Head, Armor, Body, } #[derive(Clone, PartialEq, McBuf)] pub struct Glider; impl DataComponent for Glider {} #[derive(Clone, PartialEq, McBuf)] pub struct TooltipStyle { pub resource_location: ResourceLocation, } impl DataComponent for TooltipStyle {} #[derive(Clone, PartialEq, McBuf)] pub struct DeathProtection { pub death_effects: Vec, } impl DataComponent for DeathProtection {}