1use std::fmt::{self, Debug, Formatter};
4
5use steel_utils::{Downcast as _, DowncastType, DowncastTypeKey, ErasedType};
6
7use super::components::{
8 ArmorTrim, AttackRange, BannerPatternLayers, Bees, BlockEntityData, BlockItemStateProperties,
9 BlocksAttacks, BundleContents, ChargedProjectiles, Consumable, CustomData, CustomModelData,
10 DamageResistant, DamageTypeComponent, DeathProtection, DebugStickState, DyedItemColor,
11 Enchantable, EntityData, Equippable, FireworkExplosion, Fireworks, FoodProperties,
12 InstrumentComponent, ItemAttributeModifiers, ItemContainerContents, ItemEnchantments, ItemLore,
13 JukeboxPlayable, KineticWeapon, LodestoneTracker, MapDecorations, MapId, MapItemColor,
14 MapPostProcessing, OminousBottleAmplifier, PaintingVariantComponent, PiercingWeapon,
15 PotDecorations, PotionContents, ProvidesBannerPatterns, ProvidesTrimMaterial, Rarity, Recipes,
16 Repairable, SeededContainerLoot, SulfurCubeContent, SuspiciousStewEffects, SwingAnimation,
17 Tool, TooltipDisplay, UseCooldown, UseEffects, UseRemainder, Weapon, WritableBookContent,
18 WrittenBookContent,
19};
20use crate::cat_sound_variant::CatSoundVariant;
21use crate::cat_variant::CatVariant;
22use crate::chicken_sound_variant::ChickenSoundVariant;
23use crate::chicken_variant::ChickenVariant;
24use crate::cow_sound_variant::CowSoundVariant;
25use crate::cow_variant::CowVariant;
26use crate::frog_variant::FrogVariant;
27use crate::item_predicate::{AdventureModePredicate, LockCode};
28use crate::pig_sound_variant::PigSoundVariant;
29use crate::pig_variant::PigVariant;
30use crate::resolvable_profile::ResolvableProfile;
31use crate::villager_type::VillagerType;
32use crate::wolf_sound_variant::WolfSoundVariant;
33use crate::wolf_variant::WolfVariant;
34use crate::zombie_nautilus_variant::ZombieNautilusVariant;
35use crate::{
36 AxolotlVariant, DyeColor, FoxVariant, HorseVariant, LlamaVariant, MooshroomVariant,
37 ParrotVariant, RabbitVariant, RegistryReference, SalmonVariant, TropicalFishPattern,
38};
39
40pub trait Component: ErasedType + Debug + Send + Sync + 'static {
48 #[doc(hidden)]
49 fn clone_component(&self) -> Box<dyn Component>;
50
51 #[doc(hidden)]
52 fn component_eq(&self, other: &dyn Component) -> bool;
53}
54
55impl<T> Component for T
56where
57 T: DowncastType + Clone + Debug + PartialEq + Send + Sync,
58{
59 fn clone_component(&self) -> Box<dyn Component> {
60 Box::new(self.clone())
61 }
62
63 fn component_eq(&self, other: &dyn Component) -> bool {
64 other.downcast_ref::<T>() == Some(self)
65 }
66}
67
68pub struct ComponentData {
73 value: Box<dyn Component>,
74}
75
76impl ComponentData {
77 #[must_use]
79 pub fn new(value: impl Component) -> Self {
80 Self {
81 value: Box::new(value),
82 }
83 }
84
85 #[must_use]
87 pub fn downcast_ref<T: DowncastType>(&self) -> Option<&T> {
88 self.value.downcast_ref::<T>()
89 }
90
91 #[must_use]
93 pub fn type_key(&self) -> DowncastTypeKey {
94 self.value.downcast_type_key()
95 }
96}
97
98impl Clone for ComponentData {
99 fn clone(&self) -> Self {
100 Self {
101 value: self.value.clone_component(),
102 }
103 }
104}
105
106impl Debug for ComponentData {
107 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
108 formatter
109 .debug_tuple("ComponentData")
110 .field(&self.value)
111 .finish()
112 }
113}
114
115impl PartialEq for ComponentData {
116 fn eq(&self, other: &Self) -> bool {
117 self.value.component_eq(other.value.as_ref())
118 }
119}
120
121macro_rules! impl_component_downcast_type {
122 ($type:ty, $key:literal) => {
123 unsafe impl DowncastType for $type {
126 const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new($key);
127 }
128 };
129}
130
131impl_component_downcast_type!(DamageTypeComponent, "steel:item_component/damage_type");
132impl_component_downcast_type!(
133 AdventureModePredicate,
134 "steel:item_component/adventure_mode_predicate"
135);
136impl_component_downcast_type!(LockCode, "steel:item_component/lock");
137impl_component_downcast_type!(CustomData, "steel:item_component/custom_data");
138impl_component_downcast_type!(CustomModelData, "steel:item_component/custom_model_data");
139impl_component_downcast_type!(DyeColor, "steel:dye_color");
140impl_component_downcast_type!(FoxVariant, "steel:fox_variant");
141impl_component_downcast_type!(SalmonVariant, "steel:salmon_variant");
142impl_component_downcast_type!(ParrotVariant, "steel:parrot_variant");
143impl_component_downcast_type!(TropicalFishPattern, "steel:tropical_fish_pattern");
144impl_component_downcast_type!(MooshroomVariant, "steel:mooshroom_variant");
145impl_component_downcast_type!(RabbitVariant, "steel:rabbit_variant");
146impl_component_downcast_type!(HorseVariant, "steel:horse_variant");
147impl_component_downcast_type!(LlamaVariant, "steel:llama_variant");
148impl_component_downcast_type!(AxolotlVariant, "steel:axolotl_variant");
149impl_component_downcast_type!(DyedItemColor, "steel:item_component/dyed_item_color");
150impl_component_downcast_type!(MapItemColor, "steel:item_component/map_item_color");
151impl_component_downcast_type!(MapId, "steel:item_component/map_id");
152impl_component_downcast_type!(FoodProperties, "steel:item_component/food");
153impl_component_downcast_type!(
154 SuspiciousStewEffects,
155 "steel:item_component/suspicious_stew_effects"
156);
157impl_component_downcast_type!(
158 WritableBookContent,
159 "steel:item_component/writable_book_content"
160);
161impl_component_downcast_type!(
162 WrittenBookContent,
163 "steel:item_component/written_book_content"
164);
165impl_component_downcast_type!(DebugStickState, "steel:item_component/debug_stick_state");
166impl_component_downcast_type!(Bees, "steel:item_component/bees");
167impl_component_downcast_type!(EntityData, "steel:item_component/entity_data");
168impl_component_downcast_type!(BlockEntityData, "steel:item_component/block_entity_data");
169impl_component_downcast_type!(KineticWeapon, "steel:item_component/kinetic_weapon");
170impl_component_downcast_type!(LodestoneTracker, "steel:item_component/lodestone_tracker");
171impl_component_downcast_type!(MapDecorations, "steel:item_component/map_decorations");
172impl_component_downcast_type!(FireworkExplosion, "steel:item_component/firework_explosion");
173impl_component_downcast_type!(Fireworks, "steel:item_component/fireworks");
174impl_component_downcast_type!(BlockItemStateProperties, "steel:item_component/block_state");
175impl_component_downcast_type!(BlocksAttacks, "steel:item_component/blocks_attacks");
176impl_component_downcast_type!(Consumable, "steel:item_component/consumable");
177impl_component_downcast_type!(DeathProtection, "steel:item_component/death_protection");
178impl_component_downcast_type!(ResolvableProfile, "steel:item_component/profile");
179impl_component_downcast_type!(SeededContainerLoot, "steel:item_component/container_loot");
180impl_component_downcast_type!(
181 OminousBottleAmplifier,
182 "steel:item_component/ominous_bottle_amplifier"
183);
184impl_component_downcast_type!(Enchantable, "steel:item_component/enchantable");
185impl_component_downcast_type!(InstrumentComponent, "steel:item_component/instrument");
186impl_component_downcast_type!(ArmorTrim, "steel:item_component/trim");
187impl_component_downcast_type!(Recipes, "steel:item_component/recipes");
188impl_component_downcast_type!(PotDecorations, "steel:item_component/pot_decorations");
189impl_component_downcast_type!(PotionContents, "steel:item_component/potion_contents");
190impl_component_downcast_type!(UseRemainder, "steel:item_component/use_remainder");
191impl_component_downcast_type!(
192 ChargedProjectiles,
193 "steel:item_component/charged_projectiles"
194);
195impl_component_downcast_type!(BundleContents, "steel:item_component/bundle_contents");
196impl_component_downcast_type!(ItemContainerContents, "steel:item_component/container");
197impl_component_downcast_type!(
198 SulfurCubeContent,
199 "steel:item_component/sulfur_cube_content"
200);
201impl_component_downcast_type!(BannerPatternLayers, "steel:item_component/banner_patterns");
202impl_component_downcast_type!(
203 PaintingVariantComponent,
204 "steel:item_component/painting_variant"
205);
206impl_component_downcast_type!(
207 ProvidesTrimMaterial,
208 "steel:item_component/provides_trim_material"
209);
210impl_component_downcast_type!(JukeboxPlayable, "steel:item_component/jukebox_playable");
211impl_component_downcast_type!(
212 ProvidesBannerPatterns,
213 "steel:item_component/provides_banner_patterns"
214);
215impl_component_downcast_type!(DamageResistant, "steel:item_component/damage_resistant");
216impl_component_downcast_type!(Repairable, "steel:item_component/repairable");
217impl_component_downcast_type!(Tool, "steel:item_component/tool");
218impl_component_downcast_type!(Weapon, "steel:item_component/weapon");
219impl_component_downcast_type!(AttackRange, "steel:item_component/attack_range");
220impl_component_downcast_type!(UseCooldown, "steel:item_component/use_cooldown");
221impl_component_downcast_type!(UseEffects, "steel:item_component/use_effects");
222impl_component_downcast_type!(ItemLore, "steel:item_component/lore");
223impl_component_downcast_type!(Rarity, "steel:item_component/rarity");
224impl_component_downcast_type!(TooltipDisplay, "steel:item_component/tooltip_display");
225impl_component_downcast_type!(SwingAnimation, "steel:item_component/swing_animation");
226impl_component_downcast_type!(
227 MapPostProcessing,
228 "steel:item_component/map_post_processing"
229);
230impl_component_downcast_type!(PiercingWeapon, "steel:item_component/piercing_weapon");
231impl_component_downcast_type!(Equippable, "steel:item_component/equippable");
232impl_component_downcast_type!(
233 ItemAttributeModifiers,
234 "steel:item_component/attribute_modifiers"
235);
236impl_component_downcast_type!(ItemEnchantments, "steel:item_component/enchantments");
237impl_component_downcast_type!(
238 RegistryReference<VillagerType>,
239 "steel:item_component/villager_variant"
240);
241impl_component_downcast_type!(
242 RegistryReference<WolfVariant>,
243 "steel:item_component/wolf_variant"
244);
245impl_component_downcast_type!(
246 RegistryReference<WolfSoundVariant>,
247 "steel:item_component/wolf_sound_variant"
248);
249impl_component_downcast_type!(
250 RegistryReference<PigVariant>,
251 "steel:item_component/pig_variant"
252);
253impl_component_downcast_type!(
254 RegistryReference<PigSoundVariant>,
255 "steel:item_component/pig_sound_variant"
256);
257impl_component_downcast_type!(
258 RegistryReference<CowVariant>,
259 "steel:item_component/cow_variant"
260);
261impl_component_downcast_type!(
262 RegistryReference<CowSoundVariant>,
263 "steel:item_component/cow_sound_variant"
264);
265impl_component_downcast_type!(
266 RegistryReference<ChickenVariant>,
267 "steel:item_component/chicken_variant"
268);
269impl_component_downcast_type!(
270 RegistryReference<ChickenSoundVariant>,
271 "steel:item_component/chicken_sound_variant"
272);
273impl_component_downcast_type!(
274 RegistryReference<ZombieNautilusVariant>,
275 "steel:item_component/zombie_nautilus_variant"
276);
277impl_component_downcast_type!(
278 RegistryReference<FrogVariant>,
279 "steel:item_component/frog_variant"
280);
281impl_component_downcast_type!(
282 RegistryReference<CatVariant>,
283 "steel:item_component/cat_variant"
284);
285impl_component_downcast_type!(
286 RegistryReference<CatSoundVariant>,
287 "steel:item_component/cat_sound_variant"
288);
289
290#[cfg(test)]
291mod tests {
292 use super::ComponentData;
293
294 #[test]
295 fn typed_values_downcast_by_deterministic_key() {
296 let value = ComponentData::new(17_i32);
297
298 assert_eq!(value.downcast_ref::<i32>(), Some(&17));
299 assert_eq!(value.downcast_ref::<bool>(), None);
300 }
301
302 #[test]
303 fn equality_requires_the_same_concrete_type() {
304 assert_eq!(ComponentData::new(17_i32), ComponentData::new(17_i32));
305 assert_ne!(ComponentData::new(17_i32), ComponentData::new(17.0_f32));
306 }
307}