mirror of
https://github.com/yairm210/Unciv.git
synced 2024-12-23 01:24:26 +07:00
Fix OutOfMemoryError when loading a game and another is already loaded (#7306)
* Fix OutOfMemoryError when loading a game and another is already loaded * Fix merge error...
This commit is contained in:
parent
119440ccec
commit
08cede4f5a
@ -24,7 +24,7 @@ buildscript {
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${com.unciv.build.BuildConfig.kotlinVersion}")
|
||||
classpath("de.richsource.gradle.plugins:gwt-gradle-plugin:0.6")
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
classpath("com.android.tools.build:gradle:7.1.3")
|
||||
classpath("com.mobidevelop.robovm:robovm-gradle-plugin:2.3.1")
|
||||
|
||||
// This is for wrapping the .jar file into a standalone executable
|
||||
|
@ -37,6 +37,7 @@ import com.unciv.utils.concurrency.launchOnGLThread
|
||||
import com.unciv.utils.concurrency.withGLContext
|
||||
import com.unciv.utils.concurrency.withThreadPoolContext
|
||||
import com.unciv.utils.debug
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayDeque
|
||||
@ -405,6 +406,9 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
|
||||
|
||||
/** Handles an uncaught exception or error. First attempts a platform-specific handler, and if that didn't handle the exception or error, brings the game to a [CrashScreen]. */
|
||||
fun handleUncaughtThrowable(ex: Throwable) {
|
||||
if (ex is CancellationException) {
|
||||
return // kotlin coroutines use this for control flow... so we can just ignore them.
|
||||
}
|
||||
Log.error("Uncaught throwable", ex)
|
||||
try {
|
||||
PrintWriter(files.fileWriter("lasterror.txt")).use {
|
||||
|
@ -24,6 +24,7 @@ class UncivStage(viewport: Viewport) : Stage(viewport) {
|
||||
private set
|
||||
|
||||
private val events = EventBus.EventReceiver()
|
||||
|
||||
init {
|
||||
lastKnownVisibleArea = Rectangle(0f, 0f, width, height)
|
||||
events.receive(VisibleAreaChanged::class) {
|
||||
@ -35,10 +36,15 @@ class UncivStage(viewport: Viewport) : Stage(viewport) {
|
||||
override fun dispose() {
|
||||
events.stopReceiving()
|
||||
super.dispose()
|
||||
|
||||
/** [Stage.dispose] is supposed to clear all references it holds. But it forgets the mouse over properties:
|
||||
the [Stage.mouseOverActor] and [Stage.pointerOverActors]. [Stage.act] updates those properties,
|
||||
and since there aren't any children left, sets all those properties to `null`. */
|
||||
super.act()
|
||||
}
|
||||
|
||||
override fun draw() =
|
||||
{ super.draw() }.wrapCrashHandlingUnit()()
|
||||
{ super.draw() }.wrapCrashHandlingUnit()()
|
||||
|
||||
/** libGDX has no built-in way to disable/enable pointer enter/exit events. It is simply being done in [Stage.act]. So to disable this, we have
|
||||
* to replicate the [Stage.act] method without the code for pointer enter/exit events. This is of course inherently brittle, but the only way. */
|
||||
@ -54,31 +60,31 @@ class UncivStage(viewport: Viewport) : Stage(viewport) {
|
||||
}.wrapCrashHandlingUnit()()
|
||||
|
||||
override fun act(delta: Float) =
|
||||
{ super.act(delta) }.wrapCrashHandlingUnit()()
|
||||
{ super.act(delta) }.wrapCrashHandlingUnit()()
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int) =
|
||||
{ super.touchDown(screenX, screenY, pointer, button) }.wrapCrashHandling()() ?: true
|
||||
{ super.touchDown(screenX, screenY, pointer, button) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int) =
|
||||
{ super.touchDragged(screenX, screenY, pointer) }.wrapCrashHandling()() ?: true
|
||||
{ super.touchDragged(screenX, screenY, pointer) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int) =
|
||||
{ super.touchUp(screenX, screenY, pointer, button) }.wrapCrashHandling()() ?: true
|
||||
{ super.touchUp(screenX, screenY, pointer, button) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int) =
|
||||
{ super.mouseMoved(screenX, screenY) }.wrapCrashHandling()() ?: true
|
||||
{ super.mouseMoved(screenX, screenY) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun scrolled(amountX: Float, amountY: Float) =
|
||||
{ super.scrolled(amountX, amountY) }.wrapCrashHandling()() ?: true
|
||||
{ super.scrolled(amountX, amountY) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun keyDown(keyCode: Int) =
|
||||
{ super.keyDown(keyCode) }.wrapCrashHandling()() ?: true
|
||||
{ super.keyDown(keyCode) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun keyUp(keyCode: Int) =
|
||||
{ super.keyUp(keyCode) }.wrapCrashHandling()() ?: true
|
||||
{ super.keyUp(keyCode) }.wrapCrashHandling()() ?: true
|
||||
|
||||
override fun keyTyped(character: Char) =
|
||||
{ super.keyTyped(character) }.wrapCrashHandling()() ?: true
|
||||
{ super.keyTyped(character) }.wrapCrashHandling()() ?: true
|
||||
|
||||
class VisibleAreaChanged(
|
||||
val visibleArea: Rectangle
|
||||
|
@ -212,8 +212,9 @@ class WorldScreen(
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
super.dispose()
|
||||
events.stopReceiving()
|
||||
statusButtons.dispose()
|
||||
super.dispose()
|
||||
}
|
||||
|
||||
private fun addKeyboardPresses() {
|
||||
|
@ -11,6 +11,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Stack
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.event.EventBus
|
||||
import com.unciv.logic.multiplayer.HasMultiplayerGameName
|
||||
@ -26,14 +27,15 @@ import com.unciv.ui.utils.extensions.onClick
|
||||
import com.unciv.ui.utils.extensions.setSize
|
||||
import com.unciv.utils.concurrency.Concurrency
|
||||
import com.unciv.utils.concurrency.launchOnGLThread
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
class MultiplayerStatusButton(
|
||||
/*val*/ screen: BaseScreen,
|
||||
screen: BaseScreen,
|
||||
curGame: OnlineMultiplayerGame?
|
||||
) : Button(BaseScreen.skin) {
|
||||
) : Button(BaseScreen.skin), Disposable {
|
||||
private var curGameName = curGame?.name
|
||||
private val multiplayerImage = createMultiplayerImage()
|
||||
private val loadingImage = createLoadingImage()
|
||||
@ -43,6 +45,7 @@ class MultiplayerStatusButton(
|
||||
private var loadingStarted: Instant? = null
|
||||
|
||||
private val events = EventBus.EventReceiver()
|
||||
private var loadStopJob: Job? = null
|
||||
|
||||
init {
|
||||
turnIndicatorCell = add().padTop(10f).padBottom(10f)
|
||||
@ -96,7 +99,7 @@ class MultiplayerStatusButton(
|
||||
} else {
|
||||
Duration.ZERO
|
||||
}
|
||||
Concurrency.run("Hide loading indicator") {
|
||||
loadStopJob = Concurrency.run("Hide loading indicator") {
|
||||
delay(waitFor.toMillis())
|
||||
launchOnGLThread {
|
||||
loadingImage.clearActions()
|
||||
@ -147,11 +150,18 @@ class MultiplayerStatusButton(
|
||||
turnIndicator.flash()
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
events.stopReceiving()
|
||||
turnIndicator.dispose()
|
||||
loadStopJob?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private class TurnIndicator : HorizontalGroup() {
|
||||
private class TurnIndicator : HorizontalGroup(), Disposable {
|
||||
val gameAmount = Label("2", BaseScreen.skin)
|
||||
val image: Image
|
||||
private var job: Job? = null
|
||||
init {
|
||||
image = ImageGetter.getImage("OtherIcons/ExclamationMark")
|
||||
image.setSize(30f)
|
||||
@ -175,11 +185,15 @@ private class TurnIndicator : HorizontalGroup() {
|
||||
if (alternations == 0) return
|
||||
gameAmount.color = nextColor
|
||||
image.color = nextColor
|
||||
Concurrency.run("StatusButton color flash") {
|
||||
job = Concurrency.run("StatusButton color flash") {
|
||||
delay(500)
|
||||
launchOnGLThread {
|
||||
flash(alternations - 1, nextColor, curColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
job?.cancel()
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package com.unciv.ui.worldscreen.status
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
|
||||
class StatusButtons(
|
||||
nextTurnButton: NextTurnButton,
|
||||
multiplayerStatusButton: MultiplayerStatusButton? = null
|
||||
) : HorizontalGroup() {
|
||||
) : HorizontalGroup(), Disposable {
|
||||
var multiplayerStatusButton: MultiplayerStatusButton? = multiplayerStatusButton
|
||||
set(button) {
|
||||
multiplayerStatusButton?.remove()
|
||||
@ -23,4 +24,8 @@ class StatusButtons(
|
||||
}
|
||||
addActor(nextTurnButton)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
multiplayerStatusButton?.dispose()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user