Minecraftforge: [1.13] Roadmap to minimize race conditions during Parallel mod initialization

Created on 11 Jan 2019  路  8Comments  路  Source: MinecraftForge/MinecraftForge

In 1.13, mod lifecycle events (preinit/init/postinit) are now dispatched in parallel with a parallelStream.

While a bold move, this is risky because there's many subsystems in forge that aren't thread safe.
So mods updating to 1.13 will silently gain race conditions with barely any code changes.
Race conditions are deadly because they always don't show up in testing but cause mysterious crashes months down the line without any trace of where they came from.

Of course, this isn't a problem if registrations have dedicated events to them like the Registry events, but many subsystems of forge don't have these.

So this is a list of everything I've noticed to be unsafe so far, and there's undoubtedly a lot more (basically all mod API registration methods, etc.):

  • EventBus's listeners map is a concurrenthashmap, but the values are normal non-threadsafe arraylists, so parallel calls to EventBus.register() during mod lifecycle events may race adding to the arraylist.
  • Capability registration through CapabilityManager is usually done in mod lifecycle events, and the inner hashmaps are not thread safe
  • Creating network channels during the lifecycle events leads to a call to NetworkRegistry.createInstance which touches a static unsynchronized hashmap
  • Registering key bindings during the lifecycle events using ClientRegistry.registerKeyBinding touches the Minecraft keybinding array without synchronization
  • Registering entity/tileentity renderers, if not done in the synchronous ModelRegistryEvent (many older mods from before this event was introduced use preinit/init), touches global state without synchronization
  • Registering recipe conditions and ingredient serializers touches global maps without synchronization
  • Ditto for loot conditions/serializers/etc.

The solution is either to make all of these systems threadsafe, or don't do parallel lifecycle event dispatch. It's a hard call to make, so I'll refrain from advocating for one or the other, but this is a super critical issue I think should get resolved before we release 1.13.x at large

1.13 Needs Update RFC Stale

Most helpful comment

the third option is to just say "screw it let mods handle it, they need to enqueue any synchronous work they need", but I don't really trust mods to take the right path here, especially since the "wrong" way will compile unmodified from 1.12.

All 8 comments

the third option is to just say "screw it let mods handle it, they need to enqueue any synchronous work they need", but I don't really trust mods to take the right path here, especially since the "wrong" way will compile unmodified from 1.12.

There is a race condition that can appear when registering for any event, inside of the mod's constructor, which the MDK ExampleMod is guilty of:

https://github.com/MinecraftForge/MinecraftForge/blob/1.13-pre/mdk/src/main/java/com/example/examplemod/ExampleMod.java#L30

The issue is that events can be posted while the constructor is still processing, before the mod is able to register for them

Mods should be constructed before any events are fired, are you sure?

Hmm, must be caused by something else. I added some logging. This is when it fails to register the listeners:

[20:57:30] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemodlib.ExampleModLib with id examplemodlib
[20:57:30] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemod2.ExampleMod2 with id examplemod2
[20:57:30] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemod1.ExampleMod1 with id examplemod1
[20:57:30] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemodlib.ExampleModLibTest with id examplemodlibtest
[20:57:31] [Client thread/INFO]: Setting user: Player855
[20:57:36] [Client thread/WARN]: Skipping bad option: lastServer:
[20:57:36] [Client thread/INFO]: LWJGL Version: 3.1.6 build 14
[20:57:37] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[20:57:37] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[20:57:37] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[20:57:37] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[20:57:37] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[20:57:37] [ForkJoinPool-1-worker-4/INFO] [net.minecraftforge.common.ForgeMod/]: Forge mod loading, version 24.0.83-userdev-check-path-exists, for MC 1.13 with MCP 2018.09.12.04.11.00
[20:57:37] [ForkJoinPool-1-worker-4/WARN] [net.minecraftforge.common.ForgeConfigSpec/CORE]: Configuration file AutosaveCommentedFileConfig:SimpleCommentedConfig:{general=SimpleCommentedConfig:{disableVersionCheck=false, dimensionUnloadQueueDelay=0, zombieBaseSummonChance=0.1, zombieBabyChance=0.05, removeErroringEntities=false, fullBoundingBoxLadders=false, logCascadingWorldGeneration=true, clumpingThreshold=64, removeErroringTileEntities=false, fixVanillaCascading=false}, client=SimpleCommentedConfig:{disableStairSlabCulling=false, zoomInMissingModelTextInGui=false, alwaysSetupTerrainOffThread=false, forgeLightPipelineEnabled=true, forgeCloudsEnabled=true, selectiveResourceReloadEnabled=true}} is not correct. Correcting
[20:57:37] [ForkJoinPool-1-worker-4/WARN] [net.minecraftforge.common.ForgeConfigSpec/CORE]: Configuration file AutosaveCommentedFileConfig:SimpleCommentedConfig:{mods=[SimpleCommentedConfig:{modid=forge, maxTickets=200, chunksPerTicket=25}], defaults=SimpleCommentedConfig:{enable=true, playerTicketCount=500, dormantChunkCacheSize=0, asyncChunkLoading=true, maxTickets=200, chunksPerTicket=25}} is not correct. Correcting
[20:57:37] [ForkJoinPool-1-worker-4/WARN] [net.minecraftforge.common.ForgeConfigSpec/CORE]: Incorrect key [mods] was corrected from [SimpleCommentedConfig:{modid=forge, maxTickets=200, chunksPerTicket=25}] to [SimpleCommentedConfig:{modid=forge, maxTickets=200, chunksPerTicket=25}]
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$NewRegistry, Listener Count: 0
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$NewRegistry
[20:57:37] [Client thread/INFO] [net.minecraftforge.registries.ObjectHolderRegistry/]: Processing ObjectHolder annotations
[20:57:37] [Client thread/INFO] [net.minecraftforge.registries.ObjectHolderRegistry/]: Found 1746 ObjectHolder annotations
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[20:57:37] [Client thread/INFO] [examplemod.examplemod1.ExampleMod1/]: HELLO FROM REGISTER BLOCKS
[20:57:37] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod1` for name `block_yellow`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[20:57:37] [Client thread/INFO] [examplemod.examplemod2.ExampleMod2/]: HELLO FROM REGISTER BLOCKS
[20:57:37] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod2` for name `block_blue`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[20:57:37] [Client thread/INFO] [examplemod.examplemodlib.ExampleModLibTest/]: HELLO from Register Item
[20:57:37] [Client thread/INFO] [examplemod.examplemod1.ExampleMod1/]: HELLO FROM REGISTER ITEMS
[20:57:37] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod1` for name `block_yellow`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[20:57:37] [Client thread/INFO] [examplemod.examplemod2.ExampleMod2/]: HELLO FROM REGISTER ITEMS
[20:57:37] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod2` for name `block_blue`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 6
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 0
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 0
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[20:57:37] [ForkJoinPool-1-worker-6/INFO] [examplemod.examplemodlib.ExampleModLib/]: HELLO FROM SETUP
[20:57:37] [ForkJoinPool-1-worker-1/INFO] [examplemod.examplemodlib.ExampleModLibTest/]: HELLO FROM SETUP
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[20:57:37] [ForkJoinPool-1-worker-1/INFO] [examplemod.examplemodlib.ExampleModLib/]: someLibraryMethod: examplemodlibtest
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent

This is how it should be, when all the listeners are registered:

[21:05:14] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemodlib.ExampleModLib with id examplemodlib
[21:05:14] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemod2.ExampleMod2 with id examplemod2
[21:05:14] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemod1.ExampleMod1 with id examplemod1
[21:05:14] [pool-2-thread-1/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/SCAN]: Found @Mod class examplemod.examplemodlib.ExampleModLibTest with id examplemodlibtest
[21:05:15] [Client thread/INFO]: Setting user: Player890
[21:05:19] [Client thread/WARN]: Skipping bad option: lastServer:
[21:05:19] [Client thread/INFO]: LWJGL Version: 3.1.6 build 14
[21:05:21] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[21:05:21] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[21:05:21] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[21:05:21] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[21:05:21] [Client thread/DEBUG] [net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider/LOADING]: Loading FMLModContainer from classloader cpw.mods.modlauncher.TransformingClassLoader@651aed93 - got cpw.mods.modlauncher.TransformingClassLoader$DelegatedClassLoader@b83a9be
[21:05:21] [ForkJoinPool-1-worker-4/INFO] [net.minecraftforge.common.ForgeMod/]: Forge mod loading, version 24.0.83-userdev-check-path-exists, for MC 1.13 with MCP 2018.09.12.04.11.00
[21:05:21] [ForkJoinPool-1-worker-4/WARN] [net.minecraftforge.common.ForgeConfigSpec/CORE]: Configuration file AutosaveCommentedFileConfig:SimpleCommentedConfig:{general=SimpleCommentedConfig:{disableVersionCheck=false, dimensionUnloadQueueDelay=0, zombieBaseSummonChance=0.1, zombieBabyChance=0.05, removeErroringEntities=false, fullBoundingBoxLadders=false, logCascadingWorldGeneration=true, clumpingThreshold=64, removeErroringTileEntities=false, fixVanillaCascading=false}, client=SimpleCommentedConfig:{disableStairSlabCulling=false, zoomInMissingModelTextInGui=false, alwaysSetupTerrainOffThread=false, forgeLightPipelineEnabled=true, forgeCloudsEnabled=true, selectiveResourceReloadEnabled=true}} is not correct. Correcting
[21:05:21] [ForkJoinPool-1-worker-4/WARN] [net.minecraftforge.common.ForgeConfigSpec/CORE]: Configuration file AutosaveCommentedFileConfig:SimpleCommentedConfig:{mods=[SimpleCommentedConfig:{modid=forge, maxTickets=200, chunksPerTicket=25}], defaults=SimpleCommentedConfig:{enable=true, playerTicketCount=500, dormantChunkCacheSize=0, asyncChunkLoading=true, maxTickets=200, chunksPerTicket=25}} is not correct. Correcting
[21:05:21] [ForkJoinPool-1-worker-4/WARN] [net.minecraftforge.common.ForgeConfigSpec/CORE]: Incorrect key [mods] was corrected from [SimpleCommentedConfig:{modid=forge, maxTickets=200, chunksPerTicket=25}] to [SimpleCommentedConfig:{modid=forge, maxTickets=200, chunksPerTicket=25}]
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$NewRegistry, Listener Count: 0
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$NewRegistry
[21:05:21] [Client thread/INFO] [net.minecraftforge.registries.ObjectHolderRegistry/]: Processing ObjectHolder annotations
[21:05:21] [Client thread/INFO] [net.minecraftforge.registries.ObjectHolderRegistry/]: Found 1746 ObjectHolder annotations
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[21:05:21] [Client thread/INFO] [examplemod.examplemodlib.ExampleModLib/]: HELLO from Register Block
[21:05:21] [Client thread/INFO] [examplemod.examplemodlib.ExampleModLibTest/]: HELLO from Register Block
[21:05:21] [Client thread/INFO] [examplemod.examplemod1.ExampleMod1/]: HELLO FROM REGISTER BLOCKS
[21:05:21] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod1` for name `block_yellow`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[21:05:21] [Client thread/INFO] [examplemod.examplemod2.ExampleMod2/]: HELLO FROM REGISTER BLOCKS
[21:05:21] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod2` for name `block_blue`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[21:05:21] [Client thread/INFO] [examplemod.examplemodlib.ExampleModLibTest/]: HELLO from Register Item
[21:05:21] [Client thread/INFO] [examplemod.examplemod2.ExampleMod2/]: HELLO FROM REGISTER ITEMS
[21:05:21] [Client thread/INFO] [net.minecraftforge.registries.GameData/]: Potentially Dangerous alternative prefix `examplemod2` for name `block_blue`, expected `minecraft`. This could be a intended override, but in most cases indicates a broken mod.
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.event.RegistryEvent$Register, Listener Count: 7
[EventBus#post(Event)] [POST] Event: net.minecraftforge.event.RegistryEvent$Register
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[EventBus#post(Event)] [PRE] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent, Listener Count: 2
[21:05:21] [ForkJoinPool-1-worker-4/INFO] [examplemod.examplemod2.ExampleMod2/]: HELLO FROM SETUP
[21:05:21] [ForkJoinPool-1-worker-3/INFO] [examplemod.examplemod1.ExampleMod1/]: HELLO FROM SETUP
[21:05:21] [ForkJoinPool-1-worker-1/INFO] [examplemod.examplemodlib.ExampleModLibTest/]: HELLO FROM SETUP
[21:05:21] [ForkJoinPool-1-worker-2/INFO] [examplemod.examplemodlib.ExampleModLib/]: HELLO FROM SETUP
[21:05:21] [ForkJoinPool-1-worker-1/INFO] [examplemod.examplemodlib.ExampleModLib/]: someLibraryMethod: examplemodlibtest
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[21:05:21] [ForkJoinPool-1-worker-4/INFO] [examplemod.examplemod2.api.ExampleMod2API/]: HELLO FROM API INIT
[21:05:21] [ForkJoinPool-1-worker-4/INFO] [examplemod.examplemodlib.ExampleModLib/]: someLibraryMethod: examplemod2
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[21:05:21] [ForkJoinPool-1-worker-3/INFO] [examplemod.examplemod1.api.ExampleMod1API/]: HELLO FROM API INIT
[21:05:21] [ForkJoinPool-1-worker-3/INFO] [examplemod.examplemodlib.ExampleModLib/]: someLibraryMethod: examplemod1
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
[EventBus#post(Event)] [POST] Event: net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent

One other thing to note is that constructing a new ItemGroup is not thread-safe, as it resizes and reassigns the array within the constructor.

There is a race condition that can appear when registering for any event, inside of the mod's constructor, which the MDK ExampleMod is guilty of:

https://github.com/MinecraftForge/MinecraftForge/blob/1.13-pre/mdk/src/main/java/com/example/examplemod/ExampleMod.java#L30

The issue is that events can be posted while the constructor is still processing, before the mod is able to register for them

There was indeed a race condition in the Event handling. It has been fixed and newest version is referenced in Forge now.

This issue has been automatically marked as stale because it has not had activity in a long time. If this issue is still relevant and should remain open, please reply with a short explanation (e.g. "I have checked the code and this issue is still relevant because ___." or "Here's a screenshot of this issue on the latest version"). Thank you for your contributions!

This issue has been automatically closed because it has not had activity in a long time. Please feel free to reopen it or create a new issue.

Was this page helpful?
0 / 5 - 0 ratings