waitForRegistry¶
expect fun waitForRegistry(
mod: Mod,
registryKey: ResourceKey<out Registry<*>>,
block: () -> Unit
)
Schedules block to run on the client at the earliest point client-side registration APIs that depend on registryKey's registry already being populated - like Architectury's MenuRegistry.registerScreenFactory, or registering a block-entity renderer for a just-created BlockEntityType - are safe to call. Backed by an actual per mod loader, since the loaders genuinely differ on where that point is; only call this from inside a client-only guard (e.g. net.kernelpanicsoft.archie.util.onClient) - it does no environment checking of its own.
block isn't necessarily menu-screen-specific - ADeferredRegistryHolder.initClient is a general client-setup hook any registry holder (blocks, items, block entity types, menu types, ...) can override for whatever client-only registration its own entries need, which is why this takes registryKey rather than assuming a single fixed registry.
On Fabric there's no staged registry-event model to race, so this runs block effectively immediately. On NeoForge, dev.architectury.event.events.common.LifecycleEvent.SETUP/ FMLCommonSetupEvent - the timing ADeferredRegistryHolder.initClient used to schedule on unconditionally - actually runs after several client registration-stage events (e.g. RegisterMenuScreensEvent), so calling MenuRegistry.registerScreenFactory from there silently never fires: it internally attaches a listener for that exact event, which has already fired and moved on by the time Common Setup runs.
Parameters¶
-
mod: The mod whose event bus
blockshould run on (NeoForge only needs this - Fabric'sactualignores it, since Fabric has no per-mod bus to look up). -
registryKey: The registry this holder's own entries belong to - NeoForge's
actualwaits specifically for this registry's population event before runningblock.
actual fun waitForRegistry(
mod: Mod,
registryKey: ResourceKey<out Registry<*>>,
block: () -> Unit
)
Client-only registration APIs that touch a by register(...) entry (e.g. passing a MenuType to MenuRegistry.registerScreenFactory, or a BlockEntityType to a renderer registration) aren't safe to call before registryKey's registry has actually been populated, which for a Mod-scoped dev.architectury.registry.registries.DeferredRegister happens on NeoForge's RegisterEvent - not at ADeferredRegistryHolder.init's own call time. Some of those APIs (MenuRegistry.registerScreenFactory among them) also only subscribe a listener at call time - their actual effect happens later, on a different event fired on Architectury's own per-mod bus, not mod's - so deferring block to mod's own firing of that same event (this platform used to hook RegisterMenuScreensEvent directly) races Architectury's: if Architectury's bus fires first, the listener block adds is added too late for that one-shot event and never runs.
RegisterEvent is fired once per mod, per registry, before any client registration-stage event (entries must exist before, say, their screens or renderers can be registered) - so hooking mod's own firing of it, filtered to registryKey, satisfies both constraints: late enough that this holder's own entries are already populated, early enough that whatever listener block itself adds (on Architectury's bus, in the MenuRegistry.registerScreenFactory case) is in place well before any mod's later registration-stage events fire. EventPriority.LOWEST makes the ordering explicit rather than relying on this listener happening to be added after the dev.architectury.registry.registries.DeferredRegister's own RegisterEvent listener (which does the actual population) - it runs after every other listener for this firing, on any priority, has already run.