yairm210 / Unciv

Open-source Android/Desktop remake of Civ V
Mozilla Public License 2.0
8.59k stars 1.58k forks source link

Autoplay: scene2d.ui.Cell NullPointerException #12228

Open Ooooscar opened 2 months ago

Ooooscar commented 2 months ago

Is there an existing issue for this?

Game Version

4.13.8-patch1 (Build 1,049)

Describe the bug

I'm just letting the AI to autoplay my losing game by each turn, and suddenly it crashed with a NullPointerException.

I have 5hex tileset mod, but I didn't activate it in the game.


Platform: Android Version: 4.13.8-patch1 (Build 1 049) Rulesets: [Civ V - Gods & Kings, Community Maps, Thin Bubbly Borders, Civ V - Vanilla, 5Hex Tileset] Last Screen: com.unciv.ui.screens.worldscreen.WorldScreen


Device Model: SNE-AL00 API Level: 29 System Memory: 5689 MB Available (used by Kernel): 1435 MB System Low Memory state: false Java heap limit: 512 MB Java heap free: 3 MB


Message:

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.badlogic.gdx.scenes.scene2d.ui.Cell.setTable(com.badlogic.gdx.scenes.scene2d.ui.Table)' on a null object reference
    at com.badlogic.gdx.scenes.scene2d.ui.Table.obtainCell(Table.java:103)
    at com.badlogic.gdx.scenes.scene2d.ui.Table.<init>(Table.java:95)
    at com.badlogic.gdx.scenes.scene2d.ui.Table.<init>(Table.java:88)
    at com.unciv.ui.screens.worldscreen.status.NextTurnProgress.<init>(NextTurnProgress.kt:17)
    at com.unciv.ui.screens.worldscreen.WorldScreen.nextTurn(WorldScreen.kt:572)
    at com.unciv.ui.screens.worldscreen.status.NextTurnButton$update$1.invoke(NextTurnButton.kt:39)
    at com.unciv.ui.screens.worldscreen.status.NextTurnButton$update$1.invoke(NextTurnButton.kt:37)
    at com.unciv.ui.screens.worldscreen.unit.AutoPlay$runAutoPlayJobInNewThread$1.invokeSuspend(AutoPlay.kt:57)
    at com.unciv.ui.screens.worldscreen.unit.AutoPlay$runAutoPlayJobInNewThread$1.invoke(Unknown Source:8)
    at com.unciv.ui.screens.worldscreen.unit.AutoPlay$runAutoPlayJobInNewThread$1.invoke(Unknown Source:4)
    at com.unciv.utils.ConcurrencyKt$launchCrashHandling$1.invokeSuspend(Concurrency.kt:89)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at com.unciv.utils.Dispatchers$CrashHandlingDispatcher$dispatch$1.invoke(Concurrency.kt:190)
    at com.unciv.utils.Dispatchers$CrashHandlingDispatcher$dispatch$1.invoke(Concurrency.kt:190)
    at com.unciv.ui.crashhandling.CrashHandlingExtensionsKt$wrapCrashHandling$1.invoke(CrashHandlingExtensions.kt:17)
    at com.unciv.ui.crashhandling.CrashHandlingExtensionsKt$wrapCrashHandlingUnit$1.invoke(CrashHandlingExtensions.kt:33)
    at com.unciv.ui.crashhandling.CrashHandlingExtensionsKt$wrapCrashHandlingUnit$1.invoke(CrashHandlingExtensions.kt:33)
    at com.unciv.utils.Dispatchers$CrashHandlingDispatcher.dispatch$lambda$0(Concurrency.kt:190)
    at com.unciv.utils.Dispatchers$CrashHandlingDispatcher.$r8$lambda$1exBTjTJ644h9iUU94EW5nQQXpM(Unknown Source:0)
    at com.unciv.utils.Dispatchers$CrashHandlingDispatcher$$ExternalSyntheticLambda0.run(Unknown Source:2)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:929)

Steps to Reproduce

  1. Go to my save file
  2. Try to find the issue...

Screenshots

No response

Link to save file

Link to Gist: https://gist.github.com/Ooooscar/310bf12858639624037fc602afc9f8da

Operating System

Android

Additional Information

No response

Ooooscar commented 2 months ago

I closed the game after the error screen, and I could continue my save normally afterwards (probably because I was doing multi-turn autoplay before, and changed to single-turn after the bug appeared? I can't really remember

yairm210 commented 2 months ago

This shouldn't really be a possible exception unless things on different threads were working at cross-purposes from each other, so I;m not surprised at all it's a transient error I'll try to see if I can find anything but I'm expecting not to :/

yairm210 commented 2 months ago

Yeah, I can't see how this would even be possible This is an internal LibGDX object that creates its child, tries to set its child's parent to itself, and then - its child is null? If this is a bug it's a LibGDX bug but I honestly have no idea what the hell is going on here

Ooooscar commented 2 months ago

Well thanks for your time :) I will try to provide more info if I encounter the same issue again.

SomeTroglodyte commented 2 months ago

Maybe ensure the val progressBar = NextTurnProgress(nextTurnButton) in WorldScreen nextTurn line 572 runs on the GL thread - possibly best by moving up the chain and preparing it before the nextTurn background worker is spawned?

Just a hunch. You should be able to instantiate a Table object off-GL-thread as long as nobody tries to draw it, and you definitely should be able to acquire empty unassociated Cell objects from a Pool on any thread (and here Pool.obtain returned null). But if it's really a reentrancy problem, then it's in Gdx, but by singlethreading that stuff we should be able to minimize the probability.

Another idea: An unusual Java runtime? Nah, gsmarena says that thing was "Released 2018, September"