Open Modular Turrets

Open Modular Turrets

26M Downloads

Asynchronous chunk loading

Closed this issue ยท 5 comments

commented

Issue Description:

Turret base is loading chunks when computing light opacity, causing asynchronous chunk loading.

What happens:

Light computation are done off-thread to save CPU in various mods, notably Sponge. Currently, the mod appears to check attached blocks (?) to compute the light opacity property. Doing so at a chunk border may cause a chunk to load off the main thread.

What you expected to happen:

Consider deferring property computation to the update() method or check if the chunk is loaded before accessing it?

Steps to reproduce:

Issue is intermittent, not sure how to reproduce.


Affected Versions (Do not use "latest"):

  • OMT: 1.12.2-3.1.3-355
  • OMLib: 1.12.2-3.1.3-246
  • Minecraft: 1.12.2
  • Forge: 14.23.5.2838
  • SpongeForge? yes
  • Optifine? no
  • Single Player and/or Server? server

Your most recent log file where the issue was present:

[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /**************************************************************************************************************************/
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*                                                Illegal Async Chunk Load                                                */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /**************************************************************************************************************************/
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /* Sponge relies on knowing when chunks are being loaded as chunks add entities to                                        */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /* the parented world for management. These operations are generally not threadsafe                                       */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /* and shouldn't be considered a "Sponge bug ". Adding/removing entities from                                             */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /* another thread to the world is never ok.                                                                               */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*                                                                                                                        */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*  Chunk Pos : 0, 0                                                                                                      */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*                                                                                                                        */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /* java.lang.Exception: Async Chunk Load Detected                                                                         */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.chunk.Chunk.handler$startLoad$zpc000(Chunk.java:6366)                                          */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.chunk.Chunk.func_76631_c(Chunk.java)                                                           */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraftforge.common.chunkio.ChunkIOProvider.syncCallback(ChunkIOProvider.java:109)                           */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:94)                           */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:118)                                */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.gen.ChunkProviderServer.func_186028_c(ChunkProviderServer.java:89)                             */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.gen.ChunkProviderServer.redirect$impl$ProvideChunkForced$zmj000(ChunkProviderServer.java:1145) */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.gen.ChunkProviderServer.func_186025_d(ChunkProviderServer.java:135)                            */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.World.func_72964_e(World.java:310)                                                             */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.World.func_175726_f(World.java:305)                                                            */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.World.func_175625_s(World.java:7763)                                                           */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     omtteam.openmodularturrets.blocks.BlockTurretBase.func_176221_a(BlockTurretBase.java:171)                          */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.block.state.BlockStateContainer$StateImplementation.func_185899_b(BlockStateContainer.java:423)      */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     omtteam.openmodularturrets.blocks.BlockTurretBase.getLightOpacity(BlockTurretBase.java:162)                        */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.block.state.BlockStateContainer$StateImplementation.getLightOpacity(BlockStateContainer.java:504)    */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     org.spongepowered.common.SpongeImplHooks.getBlockLightOpacity(SpongeImplHooks.java:2068)                           */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.chunk.Chunk.func_150808_b(Chunk.java:4892)                                                     */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.chunk.Chunk.relightBlockAsync(Chunk.java:5732)                                                 */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     net.minecraft.world.chunk.Chunk.lambda$onRelightBlock$3(Chunk.java:5709)                                           */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)                                    */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)                                    */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /*     java.lang.Thread.run(Thread.java:748)                                                                              */
[16:42:03] [Sponge - Async Light Thread/ERROR] [Sponge]: /**************************************************************************************************************************/

This is observed in our ~120 mods test modpack.

commented

Gonna look into that, but I do not think OMT accesses attached blocks for that. Minecraft itself does that when calling for a block update.

commented

That is minecraft doing that, It calculates the light opacity and light value of the turret base when it is updated. Minecraft itself properly loads the surrounding blocks for that. Only probably issue I think that may cause that is that we do a block update from some other place. Will check that out.

commented

From a quick check, the fix is interesting but unrelated to the original issue.

The original issue is that light computation itself triggers a chunk loading.
The latest happens because light was computed outside the main thread, and, probably, the chunk was unloaded during a computation cycle. Hence, this is not a OMT bug, this is rather a bug from the mod doing async light computation (sponge in this case). Long story short, you may close this issue.

On a side note, you might want to check the getActualState call to avoid double lookups:

if (state.getBlock() instanceof BlockTurretBase && worldIn.getTileEntity(pos) instanceof TurretBase) {

Here, we're calling twice world::getTileEntity() which can become fairly slow when you've force field around with thousands of tile entities.

commented

Thanks for the detailed explanations. I'll reduce the number of world.something calls too for the 3.2.x releases. Currently I am not doing much feature, but rather refactor and rewriting anyway.