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