1pub mod holder;
4pub mod holder_set;
5pub mod reference;
6mod tags;
7
8pub use holder::{RegistryHolder, RegistryHolderEntry};
9pub use holder_set::{RegistryHolderSet, RegistryHolderSetEntry};
10pub use reference::{RegistryReference, RegistryReferenceEntry};
11pub use tags::RegistryTags;
12
13use crate::advancement::registry::AdvancementRegistry;
14use crate::game_events::GameEventRegistry;
15use crate::stat::custom::CustomStatRegistry;
16use crate::stat::{StatTypeRegistry, vanilla_stat_types};
17use crate::ticket_type::TicketTypeRegistry;
18use crate::world_clock::WorldClockRegistry;
19use crate::{
20 attribute::AttributeRegistry,
21 banner_pattern::BannerPatternRegistry,
22 biome::BiomeRegistry,
23 block_entity_type::BlockEntityTypeRegistry,
24 block_transformer::BlockTransformerRegistry,
25 blocks::BlockRegistry,
26 carver::ConfiguredCarverRegistry,
27 cat_sound_variant::CatSoundVariantRegistry,
28 cat_variant::CatVariantRegistry,
29 chat_type::ChatTypeRegistry,
30 chicken_sound_variant::ChickenSoundVariantRegistry,
31 chicken_variant::ChickenVariantRegistry,
32 consume_effect::{self, ConsumeEffectTypeRegistry},
33 cow_sound_variant::CowSoundVariantRegistry,
34 cow_variant::CowVariantRegistry,
35 damage_type::DamageTypeRegistry,
36 data_component_predicate::{self, DataComponentPredicateTypeRegistry},
37 data_components::{DataComponentRegistry, vanilla_components},
38 decorated_pot_pattern::DecoratedPotPatternRegistry,
39 dialog::DialogRegistry,
40 dimension_type::DimensionTypeRegistry,
41 enchantment::EnchantmentRegistry,
42 entity_data::{EntityDataSerializerRegistry, register_vanilla_entity_data_serializers},
43 entity_type::EntityTypeRegistry,
44 feature::{
45 BlockStateProviderRegistry, ConfiguredFeatureKind, ConfiguredFeatureRef,
46 ConfiguredFeatureRegistry, PlacedFeatureData, PlacedFeatureRef, PlacedFeatureRegistry,
47 },
48 fluid::FluidRegistry,
49 frog_variant::FrogVariantRegistry,
50 game_rules::GameRuleRegistry,
51 instrument::InstrumentRegistry,
52 items::ItemRegistry,
53 jukebox_song::JukeboxSongRegistry,
54 loot_table::LootTableRegistry,
55 map_decoration_type::MapDecorationTypeRegistry,
56 menu_type::MenuTypeRegistry,
57 mob_effect::MobEffectRegistry,
58 painting_variant::PaintingVariantRegistry,
59 particle_type::ParticleTypeRegistry,
60 pig_sound_variant::PigSoundVariantRegistry,
61 pig_variant::PigVariantRegistry,
62 poi::PoiTypeRegistry,
63 position_source::PositionSourceTypeRegistry,
64 potion::PotionRegistry,
65 recipe::{
66 RecipeBookCategoryRegistry, RecipeRegistry, RecipeTypeRegistry,
67 vanilla_recipe_book_categories, vanilla_recipe_types,
68 },
69 sound_event::SoundEventRegistry,
70 sound_events, steel_ticket_types,
71 structure::StructureRegistry,
72 structure_processor::StructureProcessorListRegistry,
73 template_pool,
74 timeline::TimelineRegistry,
75 trim_material::TrimMaterialRegistry,
76 trim_pattern::TrimPatternRegistry,
77 vanilla_advancements, vanilla_attributes, vanilla_banner_pattern_tags, vanilla_banner_patterns,
78 vanilla_biome_tags, vanilla_biomes, vanilla_block_entity_types, vanilla_block_state_providers,
79 vanilla_block_tags, vanilla_block_transformers, vanilla_blocks, vanilla_cat_sound_variants,
80 vanilla_cat_variants, vanilla_chat_types, vanilla_chicken_sound_variants,
81 vanilla_chicken_variants, vanilla_configured_carvers, vanilla_configured_features,
82 vanilla_cow_sound_variants, vanilla_cow_variants, vanilla_custom_stats,
83 vanilla_damage_type_tags, vanilla_damage_types, vanilla_decorated_pot_patterns,
84 vanilla_dialog_tags, vanilla_dialogs, vanilla_dimension_types, vanilla_enchantment_tags,
85 vanilla_enchantments, vanilla_entities, vanilla_entity_type_tags, vanilla_fluid_tags,
86 vanilla_fluids, vanilla_frog_variants, vanilla_game_events, vanilla_game_rules,
87 vanilla_instrument_tags, vanilla_instruments, vanilla_item_tags, vanilla_items,
88 vanilla_jukebox_songs, vanilla_loot_tables, vanilla_map_decoration_types, vanilla_menu_types,
89 vanilla_mob_effects, vanilla_painting_variant_tags, vanilla_painting_variants,
90 vanilla_particle_types, vanilla_pig_sound_variants, vanilla_pig_variants,
91 vanilla_placed_features, vanilla_poi_type_tags, vanilla_poi_types,
92 vanilla_position_source_types, vanilla_potion_tags, vanilla_potions, vanilla_recipes,
93 vanilla_structure_processors, vanilla_structure_tags, vanilla_structures,
94 vanilla_template_pools, vanilla_ticket_types, vanilla_timeline_tags, vanilla_timelines,
95 vanilla_trim_materials, vanilla_trim_patterns, vanilla_villager_professions,
96 vanilla_villager_types, vanilla_wolf_sound_variants, vanilla_wolf_variants,
97 vanilla_world_clocks, vanilla_zombie_nautilus_variants,
98 villager_profession::VillagerProfessionRegistry,
99 villager_type::VillagerTypeRegistry,
100 wolf_sound_variant::WolfSoundVariantRegistry,
101 wolf_variant::WolfVariantRegistry,
102 zombie_nautilus_variant::ZombieNautilusVariantRegistry,
103};
104use std::{
105 fmt::Debug,
106 ops::Deref,
107 sync::{Once, OnceLock},
108};
109use steel_utils::Identifier;
110
111pub struct RegistryLock(OnceLock<Registry>);
112
113impl RegistryLock {
114 #[expect(clippy::result_large_err)]
115 pub fn init(&self, value: Registry) -> Result<(), Registry> {
116 self.0.set(value)
117 }
118}
119
120pub fn init_vanilla_registry() -> bool {
122 static INIT: Once = Once::new();
123
124 let mut published = false;
125 INIT.call_once(|| {
126 let mut registry = Registry::new_vanilla();
127 registry.freeze();
128 published = REGISTRY.init(registry).is_ok();
129 });
130 published
131}
132
133impl Deref for RegistryLock {
134 type Target = Registry;
135
136 fn deref(&self) -> &Self::Target {
137 self.0.get().expect("Registry not init")
138 }
139}
140
141pub static REGISTRY: RegistryLock = RegistryLock(OnceLock::new());
142
143pub trait RegistryEntry: PartialEq + 'static {
145 fn key(&self) -> &Identifier;
146 fn try_id(&self) -> Option<usize>;
147
148 fn id(&self) -> usize {
151 self.try_id().expect("entry not found in registry")
152 }
153}
154
155pub trait RegistryExt {
160 type Entry: RegistryEntry;
161
162 fn freeze(&mut self);
163 fn by_id(&self, id: usize) -> Option<&'static Self::Entry>;
164 fn by_key(&self, key: &Identifier) -> Option<&'static Self::Entry>;
165 fn id_from_key(&self, key: &Identifier) -> Option<usize>;
166 fn len(&self) -> usize;
167 fn is_empty(&self) -> bool;
168}
169
170pub trait TaggedRegistryExt: RegistryExt {
172 fn register_tag(&mut self, tag: Identifier, keys: &[&'static str]);
173 fn modify_tag(&mut self, tag: &Identifier, f: impl FnOnce(Vec<Identifier>) -> Vec<Identifier>);
174 fn is_in_tag(&self, entry: &'static Self::Entry, tag: &Identifier) -> bool;
175 fn get_tag(&self, tag: &Identifier) -> Option<Vec<&'static Self::Entry>>;
176 fn iter_tag(&self, tag: &Identifier) -> impl Iterator<Item = &'static Self::Entry> + '_;
177 fn tag_keys(&self) -> impl Iterator<Item = &Identifier> + '_;
178}
179
180pub const ADVANCEMENT_REGISTRY: Identifier = Identifier::vanilla_static("advancement");
181pub const BLOCKS_REGISTRY: Identifier = Identifier::vanilla_static("block");
182pub const ITEMS_REGISTRY: Identifier = Identifier::vanilla_static("item");
183pub const BIOMES_REGISTRY: Identifier = Identifier::vanilla_static("worldgen/biome");
184pub const CHAT_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("chat_type");
185pub const TRIM_PATTERN_REGISTRY: Identifier = Identifier::vanilla_static("trim_pattern");
186pub const TRIM_MATERIAL_REGISTRY: Identifier = Identifier::vanilla_static("trim_material");
187pub const DECORATED_POT_PATTERN_REGISTRY: Identifier =
188 Identifier::vanilla_static("decorated_pot_pattern");
189pub const WOLF_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("wolf_variant");
190pub const WOLF_SOUND_VARIANT_REGISTRY: Identifier =
191 Identifier::vanilla_static("wolf_sound_variant");
192pub const PIG_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("pig_variant");
193pub const PIG_SOUND_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("pig_sound_variant");
194pub const CHICKEN_SOUND_VARIANT_REGISTRY: Identifier =
195 Identifier::vanilla_static("chicken_sound_variant");
196pub const CAT_SOUND_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cat_sound_variant");
197pub const COW_SOUND_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cow_sound_variant");
198pub const FROG_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("frog_variant");
199pub const CAT_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cat_variant");
200pub const COW_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("cow_variant");
201pub const CHICKEN_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("chicken_variant");
202pub const PAINTING_VARIANT_REGISTRY: Identifier = Identifier::vanilla_static("painting_variant");
203pub const PARTICLE_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("particle_type");
204pub const POSITION_SOURCE_TYPE_REGISTRY: Identifier =
205 Identifier::vanilla_static("position_source_type");
206pub const VILLAGER_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("villager_type");
207pub const VILLAGER_PROFESSION_REGISTRY: Identifier =
208 Identifier::vanilla_static("villager_profession");
209pub const DIMENSION_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("dimension_type");
210pub const DAMAGE_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("damage_type");
211pub const BANNER_PATTERN_REGISTRY: Identifier = Identifier::vanilla_static("banner_pattern");
212pub const ENCHANTMENT_REGISTRY: Identifier = Identifier::vanilla_static("enchantment");
213pub const JUKEBOX_SONG_REGISTRY: Identifier = Identifier::vanilla_static("jukebox_song");
214pub const INSTRUMENT_REGISTRY: Identifier = Identifier::vanilla_static("instrument");
215pub const DIALOG_REGISTRY: Identifier = Identifier::vanilla_static("dialog");
216pub const MENU_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("menu");
217pub const MOB_EFFECT_REGISTRY: Identifier = Identifier::vanilla_static("mob_effect");
218pub const MAP_DECORATION_TYPE_REGISTRY: Identifier =
219 Identifier::vanilla_static("map_decoration_type");
220pub const ZOMBIE_NAUTILUS_VARIANT_REGISTRY: Identifier =
221 Identifier::vanilla_static("zombie_nautilus_variant");
222pub const TIMELINE_REGISTRY: Identifier = Identifier::vanilla_static("timeline");
223pub const LOOT_TABLE_REGISTRY: Identifier = Identifier::vanilla_static("loot_table");
224pub const BLOCK_ENTITY_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("block_entity_type");
225pub const FLUID_REGISTRY: Identifier = Identifier::vanilla_static("fluid");
226pub const ENTITY_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("entity_type");
227pub const SOUND_EVENT_REGISTRY: Identifier = Identifier::vanilla_static("sound_event");
228pub const POI_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("point_of_interest_type");
229pub const WORLD_CLOCK_REGISTRY: Identifier = Identifier::vanilla_static("world_clock");
230pub const CONFIGURED_CARVER_REGISTRY: Identifier =
231 Identifier::vanilla_static("worldgen/configured_carver");
232pub const CONFIGURED_FEATURE_REGISTRY: Identifier =
233 Identifier::vanilla_static("worldgen/configured_feature");
234pub const PLACED_FEATURE_REGISTRY: Identifier =
235 Identifier::vanilla_static("worldgen/placed_feature");
236pub const BLOCK_STATE_PROVIDER_REGISTRY: Identifier =
237 Identifier::vanilla_static("worldgen/block_state_provider");
238pub const BLOCK_TRANSFORMER_REGISTRY: Identifier = Identifier::vanilla_static("block_transformer");
239pub const STRUCTURE_REGISTRY: Identifier = Identifier::vanilla_static("worldgen/structure");
240pub const STRUCTURE_PROCESSOR_LIST_REGISTRY: Identifier =
241 Identifier::vanilla_static("worldgen/processor_list");
242pub const CUSTOM_STAT_REGISTRY: Identifier = Identifier::vanilla_static("custom_stat");
243pub const STAT_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("stat_type");
244pub const TICKET_TYPE_REGISTRY: Identifier = Identifier::vanilla_static("ticket_type");
245
246pub struct Registry {
247 pub attributes: AttributeRegistry,
248 pub blocks: BlockRegistry,
249 pub items: ItemRegistry,
250 pub data_components: DataComponentRegistry,
251 pub data_component_predicate_types: DataComponentPredicateTypeRegistry,
252 pub consume_effect_types: ConsumeEffectTypeRegistry,
253 pub entity_data_serializers: EntityDataSerializerRegistry,
254 pub biomes: BiomeRegistry,
255 pub chat_types: ChatTypeRegistry,
256 pub trim_patterns: TrimPatternRegistry,
257 pub trim_materials: TrimMaterialRegistry,
258 pub decorated_pot_patterns: DecoratedPotPatternRegistry,
259 pub wolf_variants: WolfVariantRegistry,
260 pub wolf_sound_variants: WolfSoundVariantRegistry,
261 pub pig_sound_variants: PigSoundVariantRegistry,
262 pub chicken_sound_variants: ChickenSoundVariantRegistry,
263 pub cat_sound_variants: CatSoundVariantRegistry,
264 pub cow_sound_variants: CowSoundVariantRegistry,
265 pub pig_variants: PigVariantRegistry,
266 pub frog_variants: FrogVariantRegistry,
267 pub cat_variants: CatVariantRegistry,
268 pub cow_variants: CowVariantRegistry,
269 pub chicken_variants: ChickenVariantRegistry,
270 pub painting_variants: PaintingVariantRegistry,
271 pub particle_types: ParticleTypeRegistry,
272 pub position_source_types: PositionSourceTypeRegistry,
273 pub villager_types: VillagerTypeRegistry,
274 pub villager_professions: VillagerProfessionRegistry,
275 pub dimension_types: DimensionTypeRegistry,
276 pub damage_types: DamageTypeRegistry,
277 pub block_transformers: BlockTransformerRegistry,
278 pub banner_patterns: BannerPatternRegistry,
279 pub jukebox_songs: JukeboxSongRegistry,
280 pub instruments: InstrumentRegistry,
281 pub dialogs: DialogRegistry,
282 pub menu_types: MenuTypeRegistry,
283 pub mob_effects: MobEffectRegistry,
284 pub map_decoration_types: MapDecorationTypeRegistry,
285 pub potions: PotionRegistry,
286 pub zombie_nautilus_variants: ZombieNautilusVariantRegistry,
287 pub timelines: TimelineRegistry,
288 pub recipe_types: RecipeTypeRegistry,
289 pub recipe_book_categories: RecipeBookCategoryRegistry,
290 pub recipes: RecipeRegistry,
291 pub entity_types: EntityTypeRegistry,
292 pub loot_tables: LootTableRegistry,
293 pub block_entity_types: BlockEntityTypeRegistry,
294 pub game_rules: GameRuleRegistry,
295 pub game_events: GameEventRegistry,
296 pub sound_events: SoundEventRegistry,
297 pub fluids: FluidRegistry,
298 pub poi_types: PoiTypeRegistry,
299 pub enchantments: EnchantmentRegistry,
300 pub world_clocks: WorldClockRegistry,
301 pub configured_carvers: ConfiguredCarverRegistry,
302 pub block_state_providers: BlockStateProviderRegistry,
303 pub configured_features: ConfiguredFeatureRegistry,
304 pub placed_features: PlacedFeatureRegistry,
305 pub structures: StructureRegistry,
306 pub structure_processors: StructureProcessorListRegistry,
307 pub custom_stats: CustomStatRegistry,
308 pub stat_types: StatTypeRegistry,
309 pub ticket_types: TicketTypeRegistry,
310 pub advancements: AdvancementRegistry,
311}
312
313impl Debug for Registry {
314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315 f.write_str("Registry {")
316 .and_then(|()| f.write_fmt(format_args!("Blocks Loaded: {}", self.blocks.len())))
317 .and_then(|()| f.write_str("}"))
318 }
319}
320
321impl Registry {
322 #[must_use]
323 pub fn new_vanilla() -> Self {
324 let mut registry = Self::new_empty();
325 vanilla_advancements::register_advancements(&mut registry.advancements);
326 vanilla_attributes::register_attributes(&mut registry.attributes);
327
328 vanilla_blocks::register_blocks(&mut registry.blocks);
329 vanilla_block_tags::BlockTag::register_block_tags(&mut registry.blocks);
330
331 vanilla_components::register_vanilla_data_components(&mut registry.data_components);
332
333 data_component_predicate::vanilla_data_component_predicate_types::register_data_component_predicate_types(
334 &mut registry.data_component_predicate_types,
335 );
336
337 consume_effect::vanilla_consume_effect_types::register_consume_effect_types(
338 &mut registry.consume_effect_types,
339 );
340
341 register_vanilla_entity_data_serializers(&mut registry.entity_data_serializers);
342
343 vanilla_items::register_items(&mut registry.items);
344 vanilla_item_tags::ItemTag::register_item_tags(&mut registry.items);
345
346 vanilla_biomes::register_biomes(&mut registry.biomes);
347 vanilla_biome_tags::BiomeTag::register_biome_tags(&mut registry.biomes);
348 vanilla_chat_types::register_chat_types(&mut registry.chat_types);
349 vanilla_trim_patterns::register_trim_patterns(&mut registry.trim_patterns);
350 vanilla_trim_materials::register_trim_materials(&mut registry.trim_materials);
351 vanilla_decorated_pot_patterns::register_decorated_pot_patterns(
352 &mut registry.decorated_pot_patterns,
353 );
354 vanilla_wolf_variants::register_wolf_variants(&mut registry.wolf_variants);
355 vanilla_wolf_sound_variants::register_wolf_sound_variants(
356 &mut registry.wolf_sound_variants,
357 );
358 vanilla_pig_variants::register_pig_variants(&mut registry.pig_variants);
359 vanilla_pig_sound_variants::register_pig_sound_variants(&mut registry.pig_sound_variants);
360 vanilla_chicken_sound_variants::register_chicken_sound_variants(
361 &mut registry.chicken_sound_variants,
362 );
363 vanilla_cat_sound_variants::register_cat_sound_variants(&mut registry.cat_sound_variants);
364 vanilla_cow_sound_variants::register_cow_sound_variants(&mut registry.cow_sound_variants);
365 vanilla_frog_variants::register_frog_variants(&mut registry.frog_variants);
366 vanilla_cat_variants::register_cat_variants(&mut registry.cat_variants);
367 vanilla_cow_variants::register_cow_variants(&mut registry.cow_variants);
368 vanilla_chicken_variants::register_chicken_variants(&mut registry.chicken_variants);
369 vanilla_painting_variants::register_painting_variants(&mut registry.painting_variants);
370 vanilla_particle_types::register_particle_types(&mut registry.particle_types);
371 vanilla_position_source_types::register_position_source_types(
372 &mut registry.position_source_types,
373 );
374 vanilla_villager_types::register_villager_types(&mut registry.villager_types);
375 vanilla_villager_professions::register_villager_professions(
376 &mut registry.villager_professions,
377 );
378 vanilla_painting_variant_tags::PaintingVariantTag::register_painting_variant_tags(
379 &mut registry.painting_variants,
380 );
381 vanilla_dimension_types::register_dimension_types(&mut registry.dimension_types);
382 vanilla_damage_types::register_damage_types(&mut registry.damage_types);
383 vanilla_damage_type_tags::DamageTypeTag::register_damage_type_tags(
384 &mut registry.damage_types,
385 );
386 vanilla_block_transformers::register_block_transformers(&mut registry.block_transformers);
387 vanilla_banner_patterns::register_banner_patterns(&mut registry.banner_patterns);
388 vanilla_banner_pattern_tags::BannerPatternTag::register_banner_pattern_tags(
389 &mut registry.banner_patterns,
390 );
391 vanilla_jukebox_songs::register_jukebox_songs(&mut registry.jukebox_songs);
392 vanilla_instruments::register_instruments(&mut registry.instruments);
393 vanilla_instrument_tags::InstrumentTag::register_instrument_tags(&mut registry.instruments);
394 vanilla_dialogs::register_dialogs(&mut registry.dialogs);
395 vanilla_dialog_tags::DialogTag::register_dialog_tags(&mut registry.dialogs);
396 vanilla_menu_types::register_menu_types(&mut registry.menu_types);
397 vanilla_mob_effects::register_mob_effects(&mut registry.mob_effects);
398 vanilla_map_decoration_types::register_map_decoration_types(
399 &mut registry.map_decoration_types,
400 );
401 vanilla_potions::register_potions(&mut registry.potions);
402 vanilla_potion_tags::PotionTag::register_potion_tags(&mut registry.potions);
403 vanilla_zombie_nautilus_variants::register_zombie_nautilus_variants(
404 &mut registry.zombie_nautilus_variants,
405 );
406 vanilla_timelines::register_timelines(&mut registry.timelines);
407 vanilla_timeline_tags::TimelineTag::register_timeline_tags(&mut registry.timelines);
408 vanilla_recipe_types::register(&mut registry.recipe_types);
409 vanilla_recipe_book_categories::register(&mut registry.recipe_book_categories);
410 vanilla_recipes::register_recipes(&mut registry.recipes);
411 vanilla_entities::register_entity_types(&mut registry.entity_types);
412 vanilla_entity_type_tags::EntityTypeTag::register_entity_type_tags(
413 &mut registry.entity_types,
414 );
415 vanilla_loot_tables::register_loot_tables(&mut registry.loot_tables);
416 vanilla_block_entity_types::register_block_entity_types(&mut registry.block_entity_types);
417 vanilla_game_rules::register_game_rules(&mut registry.game_rules);
418 vanilla_game_events::register_game_events(&mut registry.game_events);
419 sound_events::register_sound_events(&mut registry.sound_events);
420
421 vanilla_fluids::register_fluids(&mut registry.fluids);
422 vanilla_fluid_tags::FluidTag::register_fluid_tags(&mut registry.fluids);
423
424 vanilla_poi_types::register_poi_types(&mut registry.poi_types);
425 vanilla_poi_type_tags::PoiTag::register_poi_tags(&mut registry.poi_types);
426 registry.poi_types.build_state_index(®istry.blocks);
427
428 vanilla_enchantments::register_enchantments(&mut registry.enchantments);
429 vanilla_enchantment_tags::EnchantmentTag::register_enchantment_tags(
430 &mut registry.enchantments,
431 );
432
433 vanilla_world_clocks::register_world_clocks(&mut registry.world_clocks);
434 vanilla_structures::register_structures(&mut registry.structures);
435 vanilla_structure_tags::StructureTag::register_structure_tags(&mut registry.structures);
436 vanilla_structure_processors::register_structure_processor_lists(
437 &mut registry.structure_processors,
438 );
439
440 vanilla_block_state_providers::register_block_state_providers(
441 &mut registry.block_state_providers,
442 );
443
444 vanilla_configured_carvers::register_configured_carvers(&mut registry.configured_carvers);
445 vanilla_configured_features::register_configured_features(
446 &mut registry.configured_features,
447 );
448 vanilla_placed_features::register_placed_features(&mut registry.placed_features);
449
450 vanilla_custom_stats::register_custom_stats(&mut registry.custom_stats);
451 vanilla_stat_types::register_vanilla_stat_types(&mut registry.stat_types);
452
453 vanilla_ticket_types::register_vanilla_ticket_types(&mut registry.ticket_types);
454 steel_ticket_types::register_steel_ticket_types(&mut registry.ticket_types);
455
456 registry
457 }
458
459 pub fn freeze(&mut self) {
460 self.validate_references();
461
462 self.attributes.freeze();
463 self.blocks.freeze();
464 self.data_components.freeze();
465 self.data_component_predicate_types.freeze();
466 self.consume_effect_types.freeze();
467 self.entity_data_serializers.freeze();
468 self.items.freeze();
469 self.biomes.freeze();
470 self.chat_types.freeze();
471 self.trim_patterns.freeze();
472 self.trim_materials.freeze();
473 self.decorated_pot_patterns.freeze();
474 self.wolf_variants.freeze();
475 self.wolf_sound_variants.freeze();
476 self.pig_variants.freeze();
477 self.pig_sound_variants.freeze();
478 self.chicken_sound_variants.freeze();
479 self.cat_sound_variants.freeze();
480 self.cow_sound_variants.freeze();
481 self.frog_variants.freeze();
482 self.cat_variants.freeze();
483 self.cow_variants.freeze();
484 self.chicken_variants.freeze();
485 self.painting_variants.freeze();
486 self.particle_types.freeze();
487 self.position_source_types.freeze();
488 self.villager_types.freeze();
489 self.villager_professions.freeze();
490 self.dimension_types.freeze();
491 self.damage_types.freeze();
492 self.block_transformers.freeze();
493 self.banner_patterns.freeze();
494 self.jukebox_songs.freeze();
495 self.instruments.freeze();
496 self.dialogs.freeze();
497 self.menu_types.freeze();
498 self.mob_effects.freeze();
499 self.map_decoration_types.freeze();
500 self.potions.freeze();
501 self.zombie_nautilus_variants.freeze();
502 self.timelines.freeze();
503 self.recipe_types.freeze();
504 self.recipe_book_categories.freeze();
505 self.recipes.freeze(&self.recipe_types);
506 self.entity_types.freeze();
507 self.loot_tables.freeze();
508 self.block_entity_types.freeze();
509 self.game_rules.freeze();
510 self.game_events.freeze();
511 self.sound_events.freeze();
512 self.fluids.freeze();
513 self.poi_types.freeze();
514 self.enchantments.freeze();
515 self.world_clocks.freeze();
516 self.configured_carvers.freeze();
517 self.block_state_providers.freeze();
518 self.configured_features.freeze();
519 self.placed_features.freeze();
520 self.structures.freeze();
521 self.structure_processors.freeze();
522 self.custom_stats.freeze();
523 self.stat_types.freeze();
524 self.ticket_types.freeze();
525 self.advancements.update_tree();
526 }
527
528 fn validate_references(&self) {
529 let mut time_markers = rustc_hash::FxHashSet::default();
530 for (_, timeline) in self.timelines.iter() {
531 assert!(
532 self.world_clocks.by_key(&timeline.clock.key).is_some(),
533 "timeline {} references unknown world clock {}",
534 timeline.key,
535 timeline.clock.key
536 );
537 if let Some(period_ticks) = timeline.period_ticks {
538 assert!(
539 period_ticks > 0,
540 "timeline {} has invalid period_ticks {}",
541 timeline.key,
542 period_ticks
543 );
544 }
545 for marker in timeline.time_markers {
546 assert!(
547 marker.ticks >= 0,
548 "time marker {} has invalid tick {}",
549 marker.key,
550 marker.ticks
551 );
552 if let Some(period_ticks) = timeline.period_ticks {
553 assert!(
554 marker.ticks < period_ticks,
555 "time marker {} tick {} is outside timeline {} period {}",
556 marker.key,
557 marker.ticks,
558 timeline.key,
559 period_ticks
560 );
561 }
562 assert!(
563 time_markers.insert((timeline.clock.key.clone(), marker.key.clone())),
564 "time marker {} is defined multiple times for world clock {}",
565 marker.key,
566 timeline.clock.key
567 );
568 }
569 }
570
571 for (_, dimension_type) in self.dimension_types.iter() {
572 if let Some(clock) = dimension_type.default_clock {
573 assert!(
574 self.world_clocks.by_key(&clock.key).is_some(),
575 "dimension type {} references unknown default world clock {}",
576 dimension_type.key,
577 clock.key
578 );
579 }
580 }
581
582 for (_, biome) in self.biomes.iter() {
583 for carver_key in &biome.carvers {
584 assert!(
585 self.configured_carvers.by_key(carver_key).is_some(),
586 "biome {} references unknown configured carver {}",
587 biome.key,
588 carver_key
589 );
590 }
591
592 for feature_stage in &biome.features {
593 for placed_feature_key in feature_stage {
594 assert!(
595 self.placed_features.by_key(placed_feature_key).is_some(),
596 "biome {} references unknown placed feature {}",
597 biome.key,
598 placed_feature_key
599 );
600 }
601 }
602 }
603
604 for (_, placed_feature) in self.placed_features.iter() {
605 self.validate_placed_feature_data(&placed_feature.data);
606 }
607
608 for (_, configured_feature) in self.configured_features.iter() {
609 self.validate_configured_feature_kind(&configured_feature.kind);
610 }
611
612 if !self.placed_features.is_empty() {
613 for pool in vanilla_template_pools::vanilla_template_pools() {
614 for (element, _) in &pool.elements {
615 self.validate_template_pool_feature_refs(element);
616 }
617 }
618 }
619 }
620
621 fn validate_placed_feature_ref(&self, feature: &PlacedFeatureRef) {
622 match feature {
623 PlacedFeatureRef::Reference(feature) => {
624 let key = &feature.key;
625 assert!(
626 self.placed_features.by_key(key).is_some(),
627 "unknown placed feature reference {key}"
628 );
629 }
630 PlacedFeatureRef::Inline(data) => self.validate_placed_feature_data(data),
631 }
632 }
633
634 fn validate_placed_feature_data(&self, feature: &PlacedFeatureData) {
635 self.validate_configured_feature_ref(&feature.feature);
636 }
637
638 fn validate_configured_feature_ref(&self, feature: &ConfiguredFeatureRef) {
639 match feature {
640 ConfiguredFeatureRef::Reference(feature) => {
641 let key = &feature.key;
642 assert!(
643 self.configured_features.by_key(key).is_some(),
644 "unknown configured feature reference {key}"
645 );
646 }
647 ConfiguredFeatureRef::Inline(kind) => self.validate_configured_feature_kind(kind),
648 }
649 }
650
651 fn validate_configured_feature_kind(&self, kind: &ConfiguredFeatureKind) {
652 match kind {
653 ConfiguredFeatureKind::RandomBooleanSelector(config) => {
654 self.validate_placed_feature_ref(&config.feature_true);
655 self.validate_placed_feature_ref(&config.feature_false);
656 }
657 ConfiguredFeatureKind::RandomSelector(config) => {
658 for feature in &config.features {
659 self.validate_placed_feature_ref(&feature.feature);
660 }
661 self.validate_placed_feature_ref(&config.default);
662 }
663 ConfiguredFeatureKind::WeightedRandomSelector(config) => {
664 for feature in &config.features {
665 self.validate_placed_feature_ref(&feature.data);
666 }
667 }
668 ConfiguredFeatureKind::RootSystem(config) => {
669 self.validate_placed_feature_ref(&config.feature);
670 }
671 ConfiguredFeatureKind::Fossil(config) => {
672 assert!(
673 self.structure_processors
674 .by_key(&config.fossil_processors)
675 .is_some(),
676 "fossil configured feature references unknown processor list {}",
677 config.fossil_processors
678 );
679 assert!(
680 self.structure_processors
681 .by_key(&config.overlay_processors)
682 .is_some(),
683 "fossil configured feature references unknown processor list {}",
684 config.overlay_processors
685 );
686 }
687 ConfiguredFeatureKind::SimpleRandomSelector(config) => {
688 for feature in &config.features {
689 self.validate_placed_feature_ref(feature);
690 }
691 }
692 ConfiguredFeatureKind::Sequence(config) => {
693 for feature in &config.features {
694 self.validate_placed_feature_ref(feature);
695 }
696 }
697 ConfiguredFeatureKind::VegetationPatch(config)
698 | ConfiguredFeatureKind::WaterloggedVegetationPatch(config) => {
699 self.validate_placed_feature_ref(&config.vegetation_feature);
700 }
701 _ => {}
702 }
703 }
704
705 fn validate_template_pool_feature_refs(&self, element: &template_pool::PoolElement) {
706 match element {
707 template_pool::PoolElement::Feature { feature, .. } => {
708 assert!(
709 self.placed_features.by_key(feature).is_some(),
710 "template pool references unknown placed feature {feature}"
711 );
712 }
713 template_pool::PoolElement::List { elements, .. } => {
714 for element in elements {
715 self.validate_template_pool_feature_refs(element);
716 }
717 }
718 template_pool::PoolElement::Single { .. }
719 | template_pool::PoolElement::LegacySingle { .. }
720 | template_pool::PoolElement::Empty => {}
721 }
722 }
723
724 #[must_use]
725 pub fn new_empty() -> Self {
726 Self {
727 attributes: AttributeRegistry::new(),
728 blocks: BlockRegistry::new(),
729 data_components: DataComponentRegistry::new(),
730 data_component_predicate_types: DataComponentPredicateTypeRegistry::new(),
731 consume_effect_types: ConsumeEffectTypeRegistry::new(),
732 entity_data_serializers: EntityDataSerializerRegistry::new(),
733 items: ItemRegistry::new(),
734 biomes: BiomeRegistry::new(),
735 chat_types: ChatTypeRegistry::new(),
736 trim_patterns: TrimPatternRegistry::new(),
737 trim_materials: TrimMaterialRegistry::new(),
738 decorated_pot_patterns: DecoratedPotPatternRegistry::new(),
739 wolf_variants: WolfVariantRegistry::new(),
740 wolf_sound_variants: WolfSoundVariantRegistry::new(),
741 pig_variants: PigVariantRegistry::new(),
742 pig_sound_variants: PigSoundVariantRegistry::new(),
743 chicken_sound_variants: ChickenSoundVariantRegistry::new(),
744 cat_sound_variants: CatSoundVariantRegistry::new(),
745 cow_sound_variants: CowSoundVariantRegistry::new(),
746 frog_variants: FrogVariantRegistry::new(),
747 cat_variants: CatVariantRegistry::new(),
748 cow_variants: CowVariantRegistry::new(),
749 chicken_variants: ChickenVariantRegistry::new(),
750 painting_variants: PaintingVariantRegistry::new(),
751 particle_types: ParticleTypeRegistry::new(),
752 position_source_types: PositionSourceTypeRegistry::new(),
753 villager_types: VillagerTypeRegistry::new(),
754 villager_professions: VillagerProfessionRegistry::new(),
755 dimension_types: DimensionTypeRegistry::new(),
756 damage_types: DamageTypeRegistry::new(),
757 block_transformers: BlockTransformerRegistry::new(),
758 banner_patterns: BannerPatternRegistry::new(),
759 jukebox_songs: JukeboxSongRegistry::new(),
760 instruments: InstrumentRegistry::new(),
761 dialogs: DialogRegistry::new(),
762 menu_types: MenuTypeRegistry::new(),
763 mob_effects: MobEffectRegistry::new(),
764 map_decoration_types: MapDecorationTypeRegistry::new(),
765 potions: PotionRegistry::new(),
766 zombie_nautilus_variants: ZombieNautilusVariantRegistry::new(),
767 timelines: TimelineRegistry::new(),
768 recipe_types: RecipeTypeRegistry::new(),
769 recipe_book_categories: RecipeBookCategoryRegistry::new(),
770 recipes: RecipeRegistry::new(),
771 entity_types: EntityTypeRegistry::new(),
772 loot_tables: LootTableRegistry::new(),
773 block_entity_types: BlockEntityTypeRegistry::new(),
774 game_rules: GameRuleRegistry::new(),
775 game_events: GameEventRegistry::new(),
776 sound_events: SoundEventRegistry::new(),
777 fluids: FluidRegistry::new(),
778 world_clocks: WorldClockRegistry::new(),
779 poi_types: PoiTypeRegistry::new(),
780 enchantments: EnchantmentRegistry::new(),
781 configured_carvers: ConfiguredCarverRegistry::new(),
782 block_state_providers: BlockStateProviderRegistry::new(),
783 configured_features: ConfiguredFeatureRegistry::new(),
784 placed_features: PlacedFeatureRegistry::new(),
785 structures: StructureRegistry::new(),
786 structure_processors: StructureProcessorListRegistry::new(),
787 custom_stats: CustomStatRegistry::new(),
788 stat_types: StatTypeRegistry::new(),
789 ticket_types: TicketTypeRegistry::new(),
790 advancements: AdvancementRegistry::new(),
791 }
792 }
793}
794
795#[cfg(test)]
796mod tests {
797 use std::sync::OnceLock;
798
799 use rustc_hash::FxHashMap;
800 use steel_utils::Identifier;
801
802 use crate::biome::{Biome, BiomeEffects, GrassColorModifier, TemperatureModifier};
803
804 use super::{Registry, RegistryExt};
805
806 fn biome_with_refs(carvers: Vec<Identifier>, features: Vec<Vec<Identifier>>) -> &'static Biome {
807 Box::leak(Box::new(Biome {
808 key: Identifier::new_static("test", "missing_carver_biome"),
809 has_precipitation: false,
810 temperature: 0.5,
811 downfall: 0.0,
812 temperature_modifier: TemperatureModifier::None,
813 effects: BiomeEffects {
814 fog_color: 0,
815 sky_color: 0,
816 water_color: 0,
817 water_fog_color: 0,
818 foliage_color: None,
819 grass_color: None,
820 dry_foliage_color: None,
821 grass_color_modifier: GrassColorModifier::None,
822 music: None,
823 ambient_sound: None,
824 additions_sound: None,
825 mood_sound: None,
826 particle: None,
827 },
828 creature_spawn_probability: 0.0,
829 spawners: FxHashMap::default(),
830 spawn_costs: FxHashMap::default(),
831 carvers,
832 features,
833 id: OnceLock::new(),
834 }))
835 }
836
837 #[test]
838 #[should_panic(expected = "references unknown configured carver")]
839 fn freeze_rejects_missing_biome_carver_reference() {
840 let mut registry = Registry::new_empty();
841 registry.biomes.register(biome_with_refs(
842 vec![Identifier::vanilla_static("missing_carver")],
843 Vec::new(),
844 ));
845
846 registry.freeze();
847 }
848
849 #[test]
850 #[should_panic(expected = "references unknown placed feature")]
851 fn freeze_rejects_missing_biome_placed_feature_reference() {
852 let mut registry = Registry::new_empty();
853 registry.biomes.register(biome_with_refs(
854 Vec::new(),
855 vec![vec![Identifier::vanilla_static("missing_feature")]],
856 ));
857
858 registry.freeze();
859 }
860
861 #[test]
862 fn vanilla_feature_registries_initialize_and_validate() {
863 let mut registry = Registry::new_vanilla();
864 registry.freeze();
865
866 assert!(
867 registry
868 .configured_features
869 .by_key(&Identifier::vanilla_static("ore_diamond_small"))
870 .is_some()
871 );
872 assert!(
873 registry
874 .placed_features
875 .by_key(&Identifier::vanilla_static("ore_diamond"))
876 .is_some()
877 );
878 }
879
880 #[test]
881 fn vanilla_static_entity_data_registries_initialize_in_vanilla_order() {
882 let registry = Registry::new_vanilla();
883 let entity_effect = Identifier::vanilla_static("entity_effect");
884 let dust = Identifier::vanilla_static("dust");
885 let plains = Identifier::vanilla_static("plains");
886 let none = Identifier::vanilla_static("none");
887 let tabby = Identifier::vanilla_static("tabby");
888 let angry = Identifier::vanilla_static("angry");
889 let big = Identifier::vanilla_static("big");
890 let earth = Identifier::vanilla_static("earth");
891
892 assert_eq!(
893 registry.particle_types.by_id(21).map(|entry| &entry.key),
894 Some(&dust)
895 );
896 assert_eq!(
897 registry.particle_types.by_id(28).map(|entry| &entry.key),
898 Some(&entity_effect)
899 );
900 assert_eq!(
901 registry.villager_types.by_id(2).map(|entry| &entry.key),
902 Some(&plains)
903 );
904 assert_eq!(
905 registry
906 .villager_professions
907 .by_id(0)
908 .map(|entry| &entry.key),
909 Some(&none)
910 );
911 assert_eq!(
912 registry.cat_variants.by_id(9).map(|entry| &entry.key),
913 Some(&tabby)
914 );
915 assert_eq!(
916 registry
917 .wolf_sound_variants
918 .by_id(0)
919 .map(|entry| &entry.key),
920 Some(&angry)
921 );
922 assert_eq!(
923 registry.pig_sound_variants.by_id(0).map(|entry| &entry.key),
924 Some(&big)
925 );
926 assert_eq!(
927 registry.painting_variants.by_id(16).map(|entry| &entry.key),
928 Some(&earth)
929 );
930 }
931
932 #[test]
933 fn vanilla_game_events_initialize_in_vanilla_order() {
934 let registry = Registry::new_vanilla();
935 let block_activate = Identifier::vanilla_static("block_activate");
936 let unequip = Identifier::vanilla_static("unequip");
937 let resonate_1 = Identifier::vanilla_static("resonate_1");
938 let resonate_10 = Identifier::vanilla_static("resonate_10");
939
940 assert_eq!(
941 registry.game_events.by_id(0).map(|event| &event.key),
942 Some(&block_activate)
943 );
944 assert_eq!(
945 registry.game_events.by_id(45).map(|event| &event.key),
946 Some(&unequip)
947 );
948 assert_eq!(
949 registry.game_events.by_id(46).map(|event| &event.key),
950 Some(&resonate_1)
951 );
952 assert_eq!(
953 registry.game_events.by_id(55).map(|event| &event.key),
954 Some(&resonate_10)
955 );
956 }
957}