Skip to main content

steel_registry/
lib.rs

1#![feature(const_trait_impl, const_cmp, derive_const)]
2
3use crate::game_events::GameEventRegistry;
4use crate::world_clock::WorldClockRegistry;
5use crate::{
6    attribute::AttributeRegistry,
7    banner_pattern::BannerPatternRegistry,
8    biome::BiomeRegistry,
9    block_entity_type::BlockEntityTypeRegistry,
10    blocks::BlockRegistry,
11    carver::ConfiguredCarverRegistry,
12    cat_sound_variant::CatSoundVariantRegistry,
13    cat_variant::CatVariantRegistry,
14    chat_type::ChatTypeRegistry,
15    chicken_sound_variant::ChickenSoundVariantRegistry,
16    chicken_variant::ChickenVariantRegistry,
17    cow_sound_variant::CowSoundVariantRegistry,
18    cow_variant::CowVariantRegistry,
19    damage_type::DamageTypeRegistry,
20    data_components::{DataComponentRegistry, vanilla_components},
21    dialog::DialogRegistry,
22    dimension_type::DimensionTypeRegistry,
23    enchantment::EnchantmentRegistry,
24    entity_data::{EntityDataSerializerRegistry, register_vanilla_entity_data_serializers},
25    entity_type::EntityTypeRegistry,
26    feature::{
27        ConfiguredFeatureKind, ConfiguredFeatureRef, ConfiguredFeatureRegistry, PlacedFeatureData,
28        PlacedFeatureRef, PlacedFeatureRegistry,
29    },
30    fluid::FluidRegistry,
31    frog_variant::FrogVariantRegistry,
32    game_rules::GameRuleRegistry,
33    instrument::InstrumentRegistry,
34    items::ItemRegistry,
35    jukebox_song::JukeboxSongRegistry,
36    loot_table::LootTableRegistry,
37    menu_type::MenuTypeRegistry,
38    mob_effect::MobEffectRegistry,
39    painting_variant::PaintingVariantRegistry,
40    particle_type::ParticleTypeRegistry,
41    pig_sound_variant::PigSoundVariantRegistry,
42    pig_variant::PigVariantRegistry,
43    poi::PoiTypeRegistry,
44    recipe::RecipeRegistry,
45    sound_event::SoundEventRegistry,
46    structure::StructureRegistry,
47    structure_processor::StructureProcessorListRegistry,
48    timeline::TimelineRegistry,
49    trim_material::TrimMaterialRegistry,
50    trim_pattern::TrimPatternRegistry,
51    villager_profession::VillagerProfessionRegistry,
52    villager_type::VillagerTypeRegistry,
53    wolf_sound_variant::WolfSoundVariantRegistry,
54    wolf_variant::WolfVariantRegistry,
55    zombie_nautilus_variant::ZombieNautilusVariantRegistry,
56};
57use std::{fmt::Debug, ops::Deref, sync::OnceLock};
58use steel_utils::Identifier;
59pub mod attribute;
60pub mod banner_pattern;
61pub mod biome;
62pub mod block_entity_type;
63pub mod blocks;
64pub mod carver;
65pub mod cat_sound_variant;
66pub mod cat_variant;
67pub mod chat_type;
68pub mod chicken_sound_variant;
69pub mod chicken_variant;
70pub mod cow_sound_variant;
71pub mod cow_variant;
72pub mod damage_type;
73pub mod data_components;
74pub mod dialog;
75pub mod dimension_type;
76pub mod enchantment;
77pub mod entity_data;
78pub mod entity_type;
79pub mod feature;
80pub mod fluid;
81pub mod frog_variant;
82pub mod game_events;
83pub mod game_rules;
84pub mod instrument;
85pub mod item_stack;
86pub mod items;
87pub mod jukebox_song;
88pub mod loot_table;
89mod macros;
90pub mod menu_type;
91pub mod mob_effect;
92pub mod painting_variant;
93pub mod particle_type;
94pub mod pig_sound_variant;
95pub mod pig_variant;
96pub mod poi;
97pub mod recipe;
98pub mod sound_event;
99pub mod structure;
100pub mod structure_processor;
101pub mod structure_set;
102pub mod template_pool;
103pub mod timeline;
104pub mod trim_material;
105pub mod trim_pattern;
106pub mod villager_profession;
107pub mod villager_type;
108pub mod wolf_sound_variant;
109pub mod wolf_variant;
110pub mod world_clock;
111pub mod zombie_nautilus_variant;
112
113#[expect(warnings)]
114#[rustfmt::skip]
115#[path = "generated/vanilla_attributes.rs"]
116pub mod vanilla_attributes;
117
118#[expect(warnings)]
119#[rustfmt::skip]
120#[path = "generated/vanilla_blocks.rs"]
121pub mod vanilla_blocks;
122
123#[expect(warnings)]
124#[rustfmt::skip]
125#[path = "generated/vanilla_block_tags.rs"]
126pub mod vanilla_block_tags;
127
128#[expect(warnings)]
129#[rustfmt::skip]
130#[path = "generated/vanilla_banner_patterns.rs"]
131pub mod vanilla_banner_patterns;
132
133#[expect(warnings)]
134#[rustfmt::skip]
135#[path = "generated/vanilla_items.rs"]
136pub mod vanilla_items;
137
138#[expect(warnings)]
139#[rustfmt::skip]
140#[path = "generated/vanilla_item_tags.rs"]
141pub mod vanilla_item_tags;
142
143#[expect(warnings)]
144#[rustfmt::skip]
145#[path = "generated/vanilla_biomes.rs"]
146pub mod vanilla_biomes;
147
148#[expect(warnings)]
149#[rustfmt::skip]
150#[path = "generated/vanilla_biome_tags.rs"]
151pub mod vanilla_biome_tags;
152
153#[expect(warnings)]
154#[rustfmt::skip]
155#[path = "generated/vanilla_chat_types.rs"]
156pub mod vanilla_chat_types;
157
158#[expect(warnings)]
159#[rustfmt::skip]
160#[path = "generated/vanilla_trim_patterns.rs"]
161pub mod vanilla_trim_patterns;
162
163#[expect(warnings)]
164#[rustfmt::skip]
165#[path = "generated/vanilla_trim_materials.rs"]
166pub mod vanilla_trim_materials;
167
168#[expect(warnings)]
169#[rustfmt::skip]
170#[path = "generated/vanilla_wolf_variants.rs"]
171pub mod vanilla_wolf_variants;
172
173#[expect(warnings)]
174#[rustfmt::skip]
175#[path = "generated/vanilla_wolf_sound_variants.rs"]
176pub mod vanilla_wolf_sound_variants;
177
178#[expect(warnings)]
179#[rustfmt::skip]
180#[path = "generated/vanilla_pig_variants.rs"]
181pub mod vanilla_pig_variants;
182
183#[expect(warnings)]
184#[rustfmt::skip]
185#[path = "generated/vanilla_pig_sound_variants.rs"]
186pub mod vanilla_pig_sound_variants;
187
188#[allow(warnings)]
189#[rustfmt::skip]
190#[path = "generated/vanilla_chicken_sound_variants.rs"]
191pub mod vanilla_chicken_sound_variants;
192
193#[allow(warnings)]
194#[rustfmt::skip]
195#[path = "generated/vanilla_cat_sound_variants.rs"]
196pub mod vanilla_cat_sound_variants;
197
198#[allow(warnings)]
199#[rustfmt::skip]
200#[path = "generated/vanilla_cow_sound_variants.rs"]
201pub mod vanilla_cow_sound_variants;
202
203#[allow(warnings)]
204#[rustfmt::skip]
205#[path = "generated/vanilla_frog_variants.rs"]
206pub mod vanilla_frog_variants;
207
208#[expect(warnings)]
209#[rustfmt::skip]
210#[path = "generated/vanilla_cat_variants.rs"]
211pub mod vanilla_cat_variants;
212
213#[expect(warnings)]
214#[rustfmt::skip]
215#[path = "generated/vanilla_cow_variants.rs"]
216pub mod vanilla_cow_variants;
217
218#[expect(warnings)]
219#[rustfmt::skip]
220#[path = "generated/vanilla_chicken_variants.rs"]
221pub mod vanilla_chicken_variants;
222
223#[expect(warnings)]
224#[rustfmt::skip]
225#[path = "generated/vanilla_painting_variants.rs"]
226pub mod vanilla_painting_variants;
227
228#[expect(warnings)]
229#[rustfmt::skip]
230#[path = "generated/vanilla_particle_types.rs"]
231pub mod vanilla_particle_types;
232
233#[expect(warnings)]
234#[rustfmt::skip]
235#[path = "generated/vanilla_villager_types.rs"]
236pub mod vanilla_villager_types;
237
238#[expect(warnings)]
239#[rustfmt::skip]
240#[path = "generated/vanilla_villager_professions.rs"]
241pub mod vanilla_villager_professions;
242
243#[expect(warnings)]
244#[rustfmt::skip]
245#[path = "generated/vanilla_dimension_types.rs"]
246pub mod vanilla_dimension_types;
247
248#[expect(warnings)]
249#[rustfmt::skip]
250#[path = "generated/vanilla_damage_types.rs"]
251pub mod vanilla_damage_types;
252
253#[expect(warnings)]
254#[rustfmt::skip]
255#[path = "generated/vanilla_damage_type_tags.rs"]
256pub mod vanilla_damage_type_tags;
257
258#[expect(warnings)]
259#[rustfmt::skip]
260#[path = "generated/vanilla_jukebox_songs.rs"]
261pub mod vanilla_jukebox_songs;
262
263#[expect(warnings)]
264#[rustfmt::skip]
265#[path = "generated/vanilla_instruments.rs"]
266pub mod vanilla_instruments;
267
268#[expect(warnings)]
269#[rustfmt::skip]
270#[path = "generated/vanilla_dialogs.rs"]
271pub mod vanilla_dialogs;
272
273#[expect(warnings)]
274#[rustfmt::skip]
275#[path = "generated/vanilla_dialog_tags.rs"]
276pub mod vanilla_dialog_tags;
277
278#[expect(warnings)]
279#[rustfmt::skip]
280#[path = "generated/vanilla_menu_types.rs"]
281pub mod vanilla_menu_types;
282
283#[expect(warnings)]
284#[rustfmt::skip]
285#[path = "generated/vanilla_mob_effects.rs"]
286pub mod vanilla_mob_effects;
287
288#[expect(warnings)]
289#[rustfmt::skip]
290#[path = "generated/vanilla_zombie_nautilus_variants.rs"]
291pub mod vanilla_zombie_nautilus_variants;
292
293#[expect(warnings)]
294#[rustfmt::skip]
295#[path = "generated/vanilla_timelines.rs"]
296pub mod vanilla_timelines;
297
298#[expect(warnings)]
299#[rustfmt::skip]
300#[path = "generated/vanilla_timeline_tags.rs"]
301pub mod vanilla_timeline_tags;
302
303#[expect(warnings)]
304#[rustfmt::skip]
305#[path = "generated/vanilla_recipes.rs"]
306pub mod vanilla_recipes;
307
308#[expect(warnings)]
309#[rustfmt::skip]
310#[path = "generated/vanilla_entities.rs"]
311pub mod vanilla_entities;
312
313#[expect(warnings)]
314#[rustfmt::skip]
315#[path = "generated/vanilla_entity_data.rs"]
316pub mod vanilla_entity_data;
317
318#[expect(warnings)]
319#[rustfmt::skip]
320#[path = "generated/vanilla_fluids.rs"]
321pub mod vanilla_fluids;
322
323#[expect(warnings)]
324#[rustfmt::skip]
325#[path = "generated/vanilla_poi_types.rs"]
326pub mod vanilla_poi_types;
327
328#[expect(warnings)]
329#[rustfmt::skip]
330#[path = "generated/vanilla_banner_pattern_tags.rs"]
331pub mod vanilla_banner_pattern_tags;
332
333#[expect(warnings)]
334#[rustfmt::skip]
335#[path = "generated/vanilla_entity_type_tags.rs"]
336pub mod vanilla_entity_type_tags;
337
338#[expect(warnings)]
339#[rustfmt::skip]
340#[path = "generated/vanilla_enchantment_tags.rs"]
341pub mod vanilla_enchantment_tags;
342#[expect(warnings)]
343#[rustfmt::skip]
344#[path = "generated/vanilla_enchantments.rs"]
345pub mod vanilla_enchantments;
346
347#[allow(warnings)]
348#[rustfmt::skip]
349#[path = "generated/vanilla_instrument_tags.rs"]
350pub mod vanilla_instrument_tags;
351
352#[expect(warnings)]
353#[rustfmt::skip]
354#[path = "generated/vanilla_painting_variant_tags.rs"]
355pub mod vanilla_painting_variant_tags;
356
357#[expect(warnings)]
358#[rustfmt::skip]
359#[path = "generated/vanilla_poi_type_tags.rs"]
360pub mod vanilla_poi_type_tags;
361
362#[expect(warnings)]
363#[rustfmt::skip]
364#[path = "generated/vanilla_fluid_tags.rs"]
365pub mod vanilla_fluid_tags;
366
367#[expect(warnings)]
368#[rustfmt::skip]
369#[path = "generated/vanilla_loot_tables.rs"]
370pub mod vanilla_loot_tables;
371
372#[expect(warnings)]
373#[rustfmt::skip]
374#[path = "generated/vanilla_block_entity_types.rs"]
375pub mod vanilla_block_entity_types;
376
377#[expect(warnings)]
378#[rustfmt::skip]
379#[path = "generated/vanilla_game_rules.rs"]
380pub mod vanilla_game_rules;
381
382#[expect(warnings)]
383#[rustfmt::skip]
384#[path = "generated/vanilla_game_events.rs"]
385pub mod vanilla_game_events;
386
387#[expect(warnings)]
388#[rustfmt::skip]
389#[path = "generated/vanilla_level_events.rs"]
390pub mod level_events;
391
392#[expect(warnings)]
393#[rustfmt::skip]
394#[path = "generated/vanilla_sound_events.rs"]
395pub mod sound_events;
396
397#[expect(warnings)]
398#[rustfmt::skip]
399#[path = "generated/vanilla_sound_types.rs"]
400pub mod sound_types;
401
402#[expect(warnings)]
403#[rustfmt::skip]
404#[path = "generated/vanilla_structures.rs"]
405pub mod vanilla_structures;
406
407#[expect(warnings)]
408#[rustfmt::skip]
409#[path = "generated/vanilla_structure_tags.rs"]
410pub mod vanilla_structure_tags;
411
412#[expect(warnings)]
413#[rustfmt::skip]
414#[path = "generated/vanilla_structure_sets.rs"]
415pub mod vanilla_structure_sets;
416
417#[expect(warnings)]
418#[rustfmt::skip]
419#[path = "generated/vanilla_structure_processors.rs"]
420pub mod vanilla_structure_processors;
421
422#[rustfmt::skip]
423#[path = "generated/vanilla_template_pools.rs"]
424pub mod vanilla_template_pools;
425
426#[allow(warnings)]
427#[rustfmt::skip]
428#[path = "generated/vanilla_packets.rs"]
429pub mod packets;
430
431#[allow(warnings)]
432#[rustfmt::skip]
433#[path = "generated/vanilla_world_clocks.rs"]
434pub mod vanilla_world_clocks;
435pub mod shared_structs;
436
437#[expect(warnings)]
438#[rustfmt::skip]
439#[path = "generated/vanilla_configured_carvers.rs"]
440pub mod vanilla_configured_carvers;
441
442#[expect(warnings)]
443#[rustfmt::skip]
444#[path = "generated/vanilla_configured_features.rs"]
445pub mod vanilla_configured_features;
446
447#[expect(warnings)]
448#[rustfmt::skip]
449#[path = "generated/vanilla_placed_features.rs"]
450pub mod vanilla_placed_features;
451
452pub struct RegistryLock(OnceLock<Registry>);
453
454impl RegistryLock {
455    #[expect(clippy::result_large_err)]
456    pub fn init(&self, value: Registry) -> Result<(), Registry> {
457        self.0.set(value)
458    }
459
460    #[cfg(test)]
461    pub(crate) fn get_or_init(&self, f: impl FnOnce() -> Registry) -> &Registry {
462        self.0.get_or_init(f)
463    }
464}
465
466impl Deref for RegistryLock {
467    type Target = Registry;
468
469    fn deref(&self) -> &Self::Target {
470        self.0.get().expect("Registry not init")
471    }
472}
473
474pub static REGISTRY: RegistryLock = RegistryLock(OnceLock::new());
475
476#[cfg(any(test, feature = "test-utils"))]
477pub mod test_support {
478    use std::sync::Once;
479
480    use crate::{REGISTRY, Registry};
481
482    static INIT_REGISTRY: Once = Once::new();
483
484    /// Initializes the global registry with frozen vanilla data for tests.
485    pub fn init_test_registry() {
486        INIT_REGISTRY.call_once(|| {
487            let mut registry = Registry::new_vanilla();
488            registry.freeze();
489            let _ = REGISTRY.init(registry);
490        });
491    }
492}
493
494/// Trait for types stored in a registry, allowing self-lookup of their numeric ID.
495pub trait RegistryEntry: 'static {
496    fn key(&self) -> &Identifier;
497    fn try_id(&self) -> Option<usize>;
498
499    /// # Panics
500    /// Panics if the entry is not registered.
501    fn id(&self) -> usize {
502        self.try_id().expect("entry not found in registry")
503    }
504}
505
506/// Generic trait for registries with a typed entry.
507///
508/// `Entry` is the concrete type (e.g. `Block`); all lookups return `&'static Entry`
509/// to enforce cheap pointer copies and prevent expensive clones.
510pub trait RegistryExt {
511    type Entry: RegistryEntry;
512
513    fn freeze(&mut self);
514    fn by_id(&self, id: usize) -> Option<&'static Self::Entry>;
515    fn by_key(&self, key: &Identifier) -> Option<&'static Self::Entry>;
516    fn id_from_key(&self, key: &Identifier) -> Option<usize>;
517    fn len(&self) -> usize;
518    fn is_empty(&self) -> bool;
519}
520
521/// Trait for registries that support tagging entries.
522pub trait TaggedRegistryExt: RegistryExt {
523    fn register_tag(&mut self, tag: Identifier, keys: &[&'static str]);
524    fn modify_tag(&mut self, tag: &Identifier, f: impl FnOnce(Vec<Identifier>) -> Vec<Identifier>);
525    fn is_in_tag(&self, entry: &'static Self::Entry, tag: &Identifier) -> bool;
526    fn get_tag(&self, tag: &Identifier) -> Option<Vec<&'static Self::Entry>>;
527    fn iter_tag(&self, tag: &Identifier) -> impl Iterator<Item = &'static Self::Entry> + '_;
528    fn tag_keys(&self) -> impl Iterator<Item = &Identifier> + '_;
529}
530
531pub const BLOCKS_REGISTRY: Identifier = Identifier::vanilla_static("block");
532pub const ITEMS_REGISTRY: Identifier = Identifier::vanilla_static("item");
533pub const BIOMES_REGISTRY: Identifier = Identifier::vanilla_static("worldgen/biome");
534pub const CHAT_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("chat_type");
535pub const TRIM_PATTERN_REGISTRY: Identifier = Identifier::vanilla_static("trim_pattern");
536pub const TRIM_MATERIAL_REGISTRY: Identifier = Identifier::vanilla_static("trim_material");
537pub const WOLF_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("wolf_variant");
538pub const WOLF_SOUND_VARIANT_REGISTRY: Identifier =
539    Identifier::vanilla_static("wolf_sound_variant");
540pub const PIG_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("pig_variant");
541pub const PIG_SOUND_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("pig_sound_variant");
542pub const CHICKEN_SOUND_VARIANT_REGISTRY: Identifier =
543    Identifier::vanilla_static("chicken_sound_variant");
544pub const CAT_SOUND_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cat_sound_variant");
545pub const COW_SOUND_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cow_sound_variant");
546pub const FROG_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("frog_variant");
547pub const CAT_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cat_variant");
548pub const COW_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cow_variant");
549pub const CHICKEN_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("chicken_variant");
550pub const PAINTING_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("painting_variant");
551pub const PARTICLE_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("particle_type");
552pub const VILLAGER_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("villager_type");
553pub const VILLAGER_PROFESSION_REGISTRY: Identifier =
554    Identifier::vanilla_static("villager_profession");
555pub const DIMENSION_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("dimension_type");
556pub const DAMAGE_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("damage_type");
557pub const BANNER_PATTERN_REGISTRY: Identifier = Identifier::vanilla_static("banner_pattern");
558pub const ENCHANTMENT_REGISTRY: Identifier = Identifier::vanilla_static("enchantment");
559pub const JUKEBOX_SONG_REGISTRY: Identifier = Identifier::vanilla_static("jukebox_song");
560pub const INSTRUMENT_REGISTRY: Identifier = Identifier::vanilla_static("instrument");
561pub const DIALOG_REGISTRY: Identifier = Identifier::vanilla_static("dialog");
562pub const MENU_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("menu");
563pub const MOB_EFFECT_REGISTRY: Identifier = Identifier::vanilla_static("mob_effect");
564pub const ZOMBIE_NAUTILUS_VARIANT_REGISTRY: Identifier =
565    Identifier::vanilla_static("zombie_nautilus_variant");
566pub const TIMELINE_REGISTRY: Identifier = Identifier::vanilla_static("timeline");
567pub const LOOT_TABLE_REGISTRY: Identifier = Identifier::vanilla_static("loot_table");
568pub const BLOCK_ENTITY_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("block_entity_type");
569pub const FLUID_REGISTRY: Identifier = Identifier::vanilla_static("fluid");
570pub const ENTITY_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("entity_type");
571pub const SOUND_EVENT_REGISTRY: Identifier = Identifier::vanilla_static("sound_event");
572pub const POI_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("point_of_interest_type");
573pub const WORLD_CLOCK_REGISTRY: Identifier = Identifier::vanilla_static("world_clock");
574pub const CONFIGURED_CARVER_REGISTRY: Identifier =
575    Identifier::vanilla_static("worldgen/configured_carver");
576pub const CONFIGURED_FEATURE_REGISTRY: Identifier =
577    Identifier::vanilla_static("worldgen/configured_feature");
578pub const PLACED_FEATURE_REGISTRY: Identifier =
579    Identifier::vanilla_static("worldgen/placed_feature");
580pub const STRUCTURE_REGISTRY: Identifier = Identifier::vanilla_static("worldgen/structure");
581pub const STRUCTURE_PROCESSOR_LIST_REGISTRY: Identifier =
582    Identifier::vanilla_static("worldgen/processor_list");
583
584pub struct Registry {
585    pub attributes: AttributeRegistry,
586    pub blocks: BlockRegistry,
587    pub items: ItemRegistry,
588    pub data_components: DataComponentRegistry,
589    pub entity_data_serializers: EntityDataSerializerRegistry,
590    pub biomes: BiomeRegistry,
591    pub chat_types: ChatTypeRegistry,
592    pub trim_patterns: TrimPatternRegistry,
593    pub trim_materials: TrimMaterialRegistry,
594    pub wolf_variants: WolfVariantRegistry,
595    pub wolf_sound_variants: WolfSoundVariantRegistry,
596    pub pig_sound_variants: PigSoundVariantRegistry,
597    pub chicken_sound_variants: ChickenSoundVariantRegistry,
598    pub cat_sound_variants: CatSoundVariantRegistry,
599    pub cow_sound_variants: CowSoundVariantRegistry,
600    pub pig_variants: PigVariantRegistry,
601    pub frog_variants: FrogVariantRegistry,
602    pub cat_variants: CatVariantRegistry,
603    pub cow_variants: CowVariantRegistry,
604    pub chicken_variants: ChickenVariantRegistry,
605    pub painting_variants: PaintingVariantRegistry,
606    pub particle_types: ParticleTypeRegistry,
607    pub villager_types: VillagerTypeRegistry,
608    pub villager_professions: VillagerProfessionRegistry,
609    pub dimension_types: DimensionTypeRegistry,
610    pub damage_types: DamageTypeRegistry,
611    pub banner_patterns: BannerPatternRegistry,
612    pub jukebox_songs: JukeboxSongRegistry,
613    pub instruments: InstrumentRegistry,
614    pub dialogs: DialogRegistry,
615    pub menu_types: MenuTypeRegistry,
616    pub mob_effects: MobEffectRegistry,
617    pub zombie_nautilus_variants: ZombieNautilusVariantRegistry,
618    pub timelines: TimelineRegistry,
619    pub recipes: RecipeRegistry,
620    pub entity_types: EntityTypeRegistry,
621    pub loot_tables: LootTableRegistry,
622    pub block_entity_types: BlockEntityTypeRegistry,
623    pub game_rules: GameRuleRegistry,
624    pub game_events: GameEventRegistry,
625    pub sound_events: SoundEventRegistry,
626    pub fluids: FluidRegistry,
627    pub poi_types: PoiTypeRegistry,
628    pub enchantments: EnchantmentRegistry,
629    pub world_clocks: WorldClockRegistry,
630    pub configured_carvers: ConfiguredCarverRegistry,
631    pub configured_features: ConfiguredFeatureRegistry,
632    pub placed_features: PlacedFeatureRegistry,
633    pub structures: StructureRegistry,
634    pub structure_processors: StructureProcessorListRegistry,
635}
636
637impl Debug for Registry {
638    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
639        f.write_str("Registry {")
640            .and_then(|_| f.write_fmt(format_args!("Blocks Loaded: {}", self.blocks.len())))
641            .and_then(|_| f.write_str("}"))
642    }
643}
644
645impl Registry {
646    #[must_use]
647    pub fn new_vanilla() -> Self {
648        let mut registry = Self::new_empty();
649
650        vanilla_attributes::register_attributes(&mut registry.attributes);
651
652        vanilla_blocks::register_blocks(&mut registry.blocks);
653        vanilla_block_tags::BlockTag::register_block_tags(&mut registry.blocks);
654
655        vanilla_components::register_vanilla_data_components(&mut registry.data_components);
656
657        register_vanilla_entity_data_serializers(&mut registry.entity_data_serializers);
658
659        vanilla_items::register_items(&mut registry.items);
660        vanilla_item_tags::ItemTag::register_item_tags(&mut registry.items);
661
662        vanilla_biomes::register_biomes(&mut registry.biomes);
663        vanilla_biome_tags::BiomeTag::register_biome_tags(&mut registry.biomes);
664        vanilla_chat_types::register_chat_types(&mut registry.chat_types);
665        vanilla_trim_patterns::register_trim_patterns(&mut registry.trim_patterns);
666        vanilla_trim_materials::register_trim_materials(&mut registry.trim_materials);
667        vanilla_wolf_variants::register_wolf_variants(&mut registry.wolf_variants);
668        vanilla_wolf_sound_variants::register_wolf_sound_variants(
669            &mut registry.wolf_sound_variants,
670        );
671        vanilla_pig_variants::register_pig_variants(&mut registry.pig_variants);
672        vanilla_pig_sound_variants::register_pig_sound_variants(&mut registry.pig_sound_variants);
673        vanilla_chicken_sound_variants::register_chicken_sound_variants(
674            &mut registry.chicken_sound_variants,
675        );
676        vanilla_cat_sound_variants::register_cat_sound_variants(&mut registry.cat_sound_variants);
677        vanilla_cow_sound_variants::register_cow_sound_variants(&mut registry.cow_sound_variants);
678        vanilla_frog_variants::register_frog_variants(&mut registry.frog_variants);
679        vanilla_cat_variants::register_cat_variants(&mut registry.cat_variants);
680        vanilla_cow_variants::register_cow_variants(&mut registry.cow_variants);
681        vanilla_chicken_variants::register_chicken_variants(&mut registry.chicken_variants);
682        vanilla_painting_variants::register_painting_variants(&mut registry.painting_variants);
683        vanilla_particle_types::register_particle_types(&mut registry.particle_types);
684        vanilla_villager_types::register_villager_types(&mut registry.villager_types);
685        vanilla_villager_professions::register_villager_professions(
686            &mut registry.villager_professions,
687        );
688        vanilla_painting_variant_tags::PaintingVariantTag::register_painting_variant_tags(
689            &mut registry.painting_variants,
690        );
691        vanilla_dimension_types::register_dimension_types(&mut registry.dimension_types);
692        vanilla_damage_types::register_damage_types(&mut registry.damage_types);
693        vanilla_damage_type_tags::DamageTypeTag::register_damage_type_tags(
694            &mut registry.damage_types,
695        );
696        vanilla_banner_patterns::register_banner_patterns(&mut registry.banner_patterns);
697        vanilla_banner_pattern_tags::BannerPatternTag::register_banner_pattern_tags(
698            &mut registry.banner_patterns,
699        );
700        vanilla_jukebox_songs::register_jukebox_songs(&mut registry.jukebox_songs);
701        vanilla_instruments::register_instruments(&mut registry.instruments);
702        vanilla_instrument_tags::InstrumentTag::register_instrument_tags(&mut registry.instruments);
703        vanilla_dialogs::register_dialogs(&mut registry.dialogs);
704        vanilla_dialog_tags::DialogTag::register_dialog_tags(&mut registry.dialogs);
705        vanilla_menu_types::register_menu_types(&mut registry.menu_types);
706        vanilla_mob_effects::register_mob_effects(&mut registry.mob_effects);
707        vanilla_zombie_nautilus_variants::register_zombie_nautilus_variants(
708            &mut registry.zombie_nautilus_variants,
709        );
710        vanilla_timelines::register_timelines(&mut registry.timelines);
711        vanilla_timeline_tags::TimelineTag::register_timeline_tags(&mut registry.timelines);
712        vanilla_recipes::register_recipes(&mut registry.recipes);
713        vanilla_entities::register_entity_types(&mut registry.entity_types);
714        vanilla_entity_type_tags::EntityTypeTag::register_entity_type_tags(
715            &mut registry.entity_types,
716        );
717        vanilla_loot_tables::register_loot_tables(&mut registry.loot_tables);
718        vanilla_block_entity_types::register_block_entity_types(&mut registry.block_entity_types);
719        vanilla_game_rules::register_game_rules(&mut registry.game_rules);
720        vanilla_game_events::register_game_events(&mut registry.game_events);
721        sound_events::register_sound_events(&mut registry.sound_events);
722
723        vanilla_fluids::register_fluids(&mut registry.fluids);
724        vanilla_fluid_tags::FluidTag::register_fluid_tags(&mut registry.fluids);
725
726        vanilla_poi_types::register_poi_types(&mut registry.poi_types);
727        vanilla_poi_type_tags::PoiTag::register_poi_tags(&mut registry.poi_types);
728
729        vanilla_enchantments::register_enchantments(&mut registry.enchantments);
730        vanilla_enchantment_tags::EnchantmentTag::register_enchantment_tags(
731            &mut registry.enchantments,
732        );
733
734        vanilla_world_clocks::register_world_clocks(&mut registry.world_clocks);
735        vanilla_structures::register_structures(&mut registry.structures);
736        vanilla_structure_tags::StructureTag::register_structure_tags(&mut registry.structures);
737        vanilla_structure_processors::register_structure_processor_lists(
738            &mut registry.structure_processors,
739        );
740
741        vanilla_configured_carvers::register_configured_carvers(&mut registry.configured_carvers);
742        vanilla_configured_features::register_configured_features(
743            &mut registry.configured_features,
744        );
745        vanilla_placed_features::register_placed_features(&mut registry.placed_features);
746
747        registry
748    }
749
750    pub fn freeze(&mut self) {
751        self.validate_references();
752
753        self.attributes.freeze();
754        self.blocks.freeze();
755        self.data_components.freeze();
756        self.entity_data_serializers.freeze();
757        self.items.freeze();
758        self.biomes.freeze();
759        self.chat_types.freeze();
760        self.trim_patterns.freeze();
761        self.trim_materials.freeze();
762        self.wolf_variants.freeze();
763        self.wolf_sound_variants.freeze();
764        self.pig_variants.freeze();
765        self.pig_sound_variants.freeze();
766        self.chicken_sound_variants.freeze();
767        self.cat_sound_variants.freeze();
768        self.cow_sound_variants.freeze();
769        self.frog_variants.freeze();
770        self.cat_variants.freeze();
771        self.cow_variants.freeze();
772        self.chicken_variants.freeze();
773        self.painting_variants.freeze();
774        self.particle_types.freeze();
775        self.villager_types.freeze();
776        self.villager_professions.freeze();
777        self.dimension_types.freeze();
778        self.damage_types.freeze();
779        self.banner_patterns.freeze();
780        self.jukebox_songs.freeze();
781        self.instruments.freeze();
782        self.dialogs.freeze();
783        self.menu_types.freeze();
784        self.mob_effects.freeze();
785        self.zombie_nautilus_variants.freeze();
786        self.timelines.freeze();
787        self.recipes.freeze();
788        self.entity_types.freeze();
789        self.loot_tables.freeze();
790        self.block_entity_types.freeze();
791        self.game_rules.freeze();
792        self.game_events.freeze();
793        self.sound_events.freeze();
794        self.fluids.freeze();
795        self.poi_types.freeze();
796        self.enchantments.freeze();
797        self.world_clocks.freeze();
798        self.configured_carvers.freeze();
799        self.configured_features.freeze();
800        self.placed_features.freeze();
801        self.structures.freeze();
802        self.structure_processors.freeze();
803    }
804
805    fn validate_references(&self) {
806        for (_, biome) in self.biomes.iter() {
807            for carver_key in &biome.carvers {
808                assert!(
809                    self.configured_carvers.by_key(carver_key).is_some(),
810                    "biome {} references unknown configured carver {}",
811                    biome.key,
812                    carver_key
813                );
814            }
815
816            for feature_stage in &biome.features {
817                for placed_feature_key in feature_stage {
818                    assert!(
819                        self.placed_features.by_key(placed_feature_key).is_some(),
820                        "biome {} references unknown placed feature {}",
821                        biome.key,
822                        placed_feature_key
823                    );
824                }
825            }
826        }
827
828        for (_, placed_feature) in self.placed_features.iter() {
829            self.validate_placed_feature_data(&placed_feature.data);
830        }
831
832        for (_, configured_feature) in self.configured_features.iter() {
833            self.validate_configured_feature_kind(&configured_feature.kind);
834        }
835
836        if !self.placed_features.is_empty() {
837            for pool in vanilla_template_pools::vanilla_template_pools() {
838                for (element, _) in &pool.elements {
839                    self.validate_template_pool_feature_refs(element);
840                }
841            }
842        }
843    }
844
845    fn validate_placed_feature_ref(&self, feature: &PlacedFeatureRef) {
846        match feature {
847            PlacedFeatureRef::Reference(feature) => {
848                let key = &feature.key;
849                assert!(
850                    self.placed_features.by_key(key).is_some(),
851                    "unknown placed feature reference {key}"
852                );
853            }
854            PlacedFeatureRef::Inline(data) => self.validate_placed_feature_data(data),
855        }
856    }
857
858    fn validate_placed_feature_data(&self, feature: &PlacedFeatureData) {
859        self.validate_configured_feature_ref(&feature.feature);
860    }
861
862    fn validate_configured_feature_ref(&self, feature: &ConfiguredFeatureRef) {
863        match feature {
864            ConfiguredFeatureRef::Reference(feature) => {
865                let key = &feature.key;
866                assert!(
867                    self.configured_features.by_key(key).is_some(),
868                    "unknown configured feature reference {key}"
869                );
870            }
871            ConfiguredFeatureRef::Inline(kind) => self.validate_configured_feature_kind(kind),
872        }
873    }
874
875    fn validate_configured_feature_kind(&self, kind: &ConfiguredFeatureKind) {
876        match kind {
877            ConfiguredFeatureKind::RandomBooleanSelector(config) => {
878                self.validate_placed_feature_ref(&config.feature_true);
879                self.validate_placed_feature_ref(&config.feature_false);
880            }
881            ConfiguredFeatureKind::RandomSelector(config) => {
882                for feature in &config.features {
883                    self.validate_placed_feature_ref(&feature.feature);
884                }
885                self.validate_placed_feature_ref(&config.default);
886            }
887            ConfiguredFeatureKind::RootSystem(config) => {
888                self.validate_placed_feature_ref(&config.feature);
889            }
890            ConfiguredFeatureKind::Fossil(config) => {
891                assert!(
892                    self.structure_processors
893                        .by_key(&config.fossil_processors)
894                        .is_some(),
895                    "fossil configured feature references unknown processor list {}",
896                    config.fossil_processors
897                );
898                assert!(
899                    self.structure_processors
900                        .by_key(&config.overlay_processors)
901                        .is_some(),
902                    "fossil configured feature references unknown processor list {}",
903                    config.overlay_processors
904                );
905            }
906            ConfiguredFeatureKind::SimpleRandomSelector(config) => {
907                for feature in &config.features {
908                    self.validate_placed_feature_ref(feature);
909                }
910            }
911            ConfiguredFeatureKind::VegetationPatch(config)
912            | ConfiguredFeatureKind::WaterloggedVegetationPatch(config) => {
913                self.validate_placed_feature_ref(&config.vegetation_feature);
914            }
915            _ => {}
916        }
917    }
918
919    fn validate_template_pool_feature_refs(&self, element: &template_pool::PoolElement) {
920        match element {
921            template_pool::PoolElement::Feature { feature, .. } => {
922                assert!(
923                    self.placed_features.by_key(feature).is_some(),
924                    "template pool references unknown placed feature {feature}"
925                );
926            }
927            template_pool::PoolElement::List { elements, .. } => {
928                for element in elements {
929                    self.validate_template_pool_feature_refs(element);
930                }
931            }
932            template_pool::PoolElement::Single { .. }
933            | template_pool::PoolElement::LegacySingle { .. }
934            | template_pool::PoolElement::Empty => {}
935        }
936    }
937
938    #[must_use]
939    pub fn new_empty() -> Self {
940        Self {
941            attributes: AttributeRegistry::new(),
942            blocks: BlockRegistry::new(),
943            data_components: DataComponentRegistry::new(),
944            entity_data_serializers: EntityDataSerializerRegistry::new(),
945            items: ItemRegistry::new(),
946            biomes: BiomeRegistry::new(),
947            chat_types: ChatTypeRegistry::new(),
948            trim_patterns: TrimPatternRegistry::new(),
949            trim_materials: TrimMaterialRegistry::new(),
950            wolf_variants: WolfVariantRegistry::new(),
951            wolf_sound_variants: WolfSoundVariantRegistry::new(),
952            pig_variants: PigVariantRegistry::new(),
953            pig_sound_variants: PigSoundVariantRegistry::new(),
954            chicken_sound_variants: ChickenSoundVariantRegistry::new(),
955            cat_sound_variants: CatSoundVariantRegistry::new(),
956            cow_sound_variants: CowSoundVariantRegistry::new(),
957            frog_variants: FrogVariantRegistry::new(),
958            cat_variants: CatVariantRegistry::new(),
959            cow_variants: CowVariantRegistry::new(),
960            chicken_variants: ChickenVariantRegistry::new(),
961            painting_variants: PaintingVariantRegistry::new(),
962            particle_types: ParticleTypeRegistry::new(),
963            villager_types: VillagerTypeRegistry::new(),
964            villager_professions: VillagerProfessionRegistry::new(),
965            dimension_types: DimensionTypeRegistry::new(),
966            damage_types: DamageTypeRegistry::new(),
967            banner_patterns: BannerPatternRegistry::new(),
968            jukebox_songs: JukeboxSongRegistry::new(),
969            instruments: InstrumentRegistry::new(),
970            dialogs: DialogRegistry::new(),
971            menu_types: MenuTypeRegistry::new(),
972            mob_effects: MobEffectRegistry::new(),
973            zombie_nautilus_variants: ZombieNautilusVariantRegistry::new(),
974            timelines: TimelineRegistry::new(),
975            recipes: RecipeRegistry::new(),
976            entity_types: EntityTypeRegistry::new(),
977            loot_tables: LootTableRegistry::new(),
978            block_entity_types: BlockEntityTypeRegistry::new(),
979            game_rules: GameRuleRegistry::new(),
980            game_events: GameEventRegistry::new(),
981            sound_events: SoundEventRegistry::new(),
982            fluids: FluidRegistry::new(),
983            world_clocks: WorldClockRegistry::new(),
984            poi_types: PoiTypeRegistry::new(),
985            enchantments: EnchantmentRegistry::new(),
986            configured_carvers: ConfiguredCarverRegistry::new(),
987            configured_features: ConfiguredFeatureRegistry::new(),
988            placed_features: PlacedFeatureRegistry::new(),
989            structures: StructureRegistry::new(),
990            structure_processors: StructureProcessorListRegistry::new(),
991        }
992    }
993}
994
995#[cfg(test)]
996mod tests {
997    use std::sync::OnceLock;
998
999    use rustc_hash::FxHashMap;
1000    use steel_utils::Identifier;
1001
1002    use crate::biome::{Biome, BiomeEffects, GrassColorModifier, TemperatureModifier};
1003
1004    use super::{Registry, RegistryExt};
1005
1006    fn biome_with_refs(carvers: Vec<Identifier>, features: Vec<Vec<Identifier>>) -> &'static Biome {
1007        Box::leak(Box::new(Biome {
1008            key: Identifier::new_static("test", "missing_carver_biome"),
1009            has_precipitation: false,
1010            temperature: 0.5,
1011            downfall: 0.0,
1012            temperature_modifier: TemperatureModifier::None,
1013            effects: BiomeEffects {
1014                fog_color: 0,
1015                sky_color: 0,
1016                water_color: 0,
1017                water_fog_color: 0,
1018                foliage_color: None,
1019                grass_color: None,
1020                dry_foliage_color: None,
1021                grass_color_modifier: GrassColorModifier::None,
1022                music: None,
1023                ambient_sound: None,
1024                additions_sound: None,
1025                mood_sound: None,
1026                particle: None,
1027            },
1028            creature_spawn_probability: 0.0,
1029            spawners: FxHashMap::default(),
1030            spawn_costs: FxHashMap::default(),
1031            carvers,
1032            features,
1033            id: OnceLock::new(),
1034        }))
1035    }
1036
1037    #[test]
1038    #[should_panic(expected = "references unknown configured carver")]
1039    fn freeze_rejects_missing_biome_carver_reference() {
1040        let mut registry = Registry::new_empty();
1041        registry.biomes.register(biome_with_refs(
1042            vec![Identifier::vanilla_static("missing_carver")],
1043            Vec::new(),
1044        ));
1045
1046        registry.freeze();
1047    }
1048
1049    #[test]
1050    #[should_panic(expected = "references unknown placed feature")]
1051    fn freeze_rejects_missing_biome_placed_feature_reference() {
1052        let mut registry = Registry::new_empty();
1053        registry.biomes.register(biome_with_refs(
1054            Vec::new(),
1055            vec![vec![Identifier::vanilla_static("missing_feature")]],
1056        ));
1057
1058        registry.freeze();
1059    }
1060
1061    #[test]
1062    fn vanilla_feature_registries_initialize_and_validate() {
1063        let mut registry = Registry::new_vanilla();
1064        registry.freeze();
1065
1066        assert!(
1067            registry
1068                .configured_features
1069                .by_key(&Identifier::vanilla_static("ore_diamond_small"))
1070                .is_some()
1071        );
1072        assert!(
1073            registry
1074                .placed_features
1075                .by_key(&Identifier::vanilla_static("ore_diamond"))
1076                .is_some()
1077        );
1078    }
1079
1080    #[test]
1081    fn vanilla_static_entity_data_registries_initialize_in_vanilla_order() {
1082        let registry = Registry::new_vanilla();
1083        let entity_effect = Identifier::vanilla_static("entity_effect");
1084        let plains = Identifier::vanilla_static("plains");
1085        let none = Identifier::vanilla_static("none");
1086        let tabby = Identifier::vanilla_static("tabby");
1087        let angry = Identifier::vanilla_static("angry");
1088        let big = Identifier::vanilla_static("big");
1089        let earth = Identifier::vanilla_static("earth");
1090
1091        assert_eq!(
1092            registry.particle_types.by_id(21).map(|entry| &entry.key),
1093            Some(&entity_effect)
1094        );
1095        assert_eq!(
1096            registry.villager_types.by_id(2).map(|entry| &entry.key),
1097            Some(&plains)
1098        );
1099        assert_eq!(
1100            registry
1101                .villager_professions
1102                .by_id(0)
1103                .map(|entry| &entry.key),
1104            Some(&none)
1105        );
1106        assert_eq!(
1107            registry.cat_variants.by_id(0).map(|entry| &entry.key),
1108            Some(&tabby)
1109        );
1110        assert_eq!(
1111            registry
1112                .wolf_sound_variants
1113                .by_id(3)
1114                .map(|entry| &entry.key),
1115            Some(&angry)
1116        );
1117        assert_eq!(
1118            registry.pig_sound_variants.by_id(1).map(|entry| &entry.key),
1119            Some(&big)
1120        );
1121        assert_eq!(
1122            registry.painting_variants.by_id(25).map(|entry| &entry.key),
1123            Some(&earth)
1124        );
1125    }
1126
1127    #[test]
1128    fn vanilla_game_events_initialize_in_vanilla_order() {
1129        let registry = Registry::new_vanilla();
1130        let block_activate = Identifier::vanilla_static("block_activate");
1131        let resonate_1 = Identifier::vanilla_static("resonate_1");
1132        let resonate_10 = Identifier::vanilla_static("resonate_10");
1133
1134        assert_eq!(
1135            registry.game_events.by_id(0).map(|event| &event.key),
1136            Some(&block_activate)
1137        );
1138        assert_eq!(
1139            registry.game_events.by_id(45).map(|event| &event.key),
1140            Some(&resonate_1)
1141        );
1142        assert_eq!(
1143            registry.game_events.by_id(54).map(|event| &event.key),
1144            Some(&resonate_10)
1145        );
1146    }
1147}