Discord thread shutdown, last Autosave singlethreaded (#2318)

* Bring Incas into the main game
(also changes slinger withdraw ability to inheritable)

* Update Nations.json

* Discord thread is now a timer and gets notified to shut down
Solved truncated Autosaves: Made it singlethreaded within shutdown.

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
proteus-anguinus 2020-04-06 12:43:40 +02:00 committed by GitHub
parent adb52acd24
commit cee794b29c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 29 deletions

View file

@ -24,7 +24,8 @@ import kotlin.concurrent.thread
class UncivGame(
val version: String,
private val crashReportSender: CrashReportSender? = null,
val exitEvent: (()->Unit)? = null
val exitEvent: (()->Unit)? = null,
val cancelDiscordEvent: (()->Unit)? = null
) : Game() {
// we need this secondary constructor because Java code for iOS can't handle Kotlin lambda parameters
constructor(version: String) : this(version, null)
@ -177,10 +178,19 @@ class UncivGame(
}
override fun dispose() {
if (::gameInfo.isInitialized) {
GameSaver().autoSave(gameInfo)
cancelDiscordEvent?.invoke()
if (::gameInfo.isInitialized){
GameSaver().autoSaveSingleThreaded(gameInfo) // NO new thread
settings.save()
}
// Log still running threads (should be only this one and "DestroyJavaVM")
val numThreads = Thread.activeCount()
val threadList = Array<Thread>(numThreads) { _ -> Thread() }
Thread.enumerate(threadList)
threadList.filter { it !== Thread.currentThread() && it.name != "DestroyJavaVM"}.forEach {
println (" Thread ${it.name} still running in UncivGame.dispose().")
}
}
companion object {

View file

@ -80,25 +80,26 @@ class GameSaver {
// On the other hand if we alter the game data while it's being serialized we could get a concurrent modification exception.
// So what we do is we clone all the game data and serialize the clone.
val gameInfoClone = gameInfo.clone()
thread(name="Autosave") {
saveGame(gameInfoClone, "Autosave")
// keep auto-saves for the last 10 turns for debugging purposes
val newAutosaveFilename = saveFilesFolder + File.separator + "Autosave-${gameInfo.currentPlayer}-${gameInfoClone.turns}"
getSave("Autosave").copyTo(Gdx.files.local(newAutosaveFilename))
fun getAutosaves(): List<String> { return getSaves().filter { it.startsWith("Autosave") } }
while(getAutosaves().size>10){
val saveToDelete = getAutosaves().minBy { getSave(it).lastModified() }!!
deleteSave(saveToDelete)
}
thread(name = "Autosave") {
autoSaveSingleThreaded(gameInfoClone)
// do this on main thread
Gdx.app.postRunnable {
postRunnable()
}
}
}
fun autoSaveSingleThreaded (gameInfo: GameInfo) {
saveGame(gameInfo, "Autosave")
// keep auto-saves for the last 10 turns for debugging purposes
val newAutosaveFilename = saveFilesFolder + File.separator + "Autosave-${gameInfo.currentPlayer}-${gameInfo.turns}"
getSave("Autosave").copyTo(Gdx.files.local(newAutosaveFilename))
fun getAutosaves(): List<String> { return getSaves().filter { it.startsWith("Autosave") } }
while(getAutosaves().size>10){
val saveToDelete = getAutosaves().minBy { getSave(it).lastModified() }!!
deleteSave(saveToDelete)
}
}
/**

View file

@ -11,11 +11,14 @@ import com.badlogic.gdx.tools.texturepacker.TexturePacker
import com.unciv.UncivGame
import com.unciv.models.translations.tr
import java.io.File
import kotlin.concurrent.thread
import java.util.*
import kotlin.concurrent.timer
import kotlin.system.exitProcess
internal object DesktopLauncher {
private var discordTimer: Timer? = null
@JvmStatic
fun main(arg: Array<String>) {
@ -27,9 +30,9 @@ internal object DesktopLauncher {
config.title = "Unciv"
config.useHDPI = true
val versionFromJar = DesktopLauncher.javaClass.`package`.specificationVersion
val versionFromJar = DesktopLauncher.javaClass.`package`.specificationVersion ?: "Desktop"
val game = UncivGame(if (versionFromJar != null) versionFromJar else "Desktop", null){exitProcess(0)}
val game = UncivGame ( versionFromJar, null, { exitProcess(0) }, { discordTimer?.cancel() } )
if(!RaspberryPiDetector.isRaspberryPi()) // No discord RPC for Raspberry Pi, see https://github.com/yairm210/Unciv/issues/1624
tryActivateDiscord(game)
@ -71,27 +74,23 @@ internal object DesktopLauncher {
}
private fun tryActivateDiscord(game: UncivGame) {
try {
val handlers = DiscordEventHandlers()
DiscordRPC.INSTANCE.Discord_Initialize("647066573147996161", handlers, true, null)
Runtime.getRuntime().addShutdownHook(Thread { DiscordRPC.INSTANCE.Discord_Shutdown() })
thread {
while (true) {
try {
updateRpc(game)
}catch (ex:Exception){}
Thread.sleep(1000)
}
discordTimer = timer(name = "Discord", daemon = true, period = 1000) {
try {
updateRpc(game)
} catch (ex:Exception){}
}
} catch (ex: Exception) {
print("Could not initialize Discord")
println("Could not initialize Discord")
}
}
fun updateRpc(game: UncivGame) {
private fun updateRpc(game: UncivGame) {
if(!game.isInitialized) return
val presence = DiscordRichPresence()
val currentPlayerCiv = game.gameInfo.getCurrentPlayerCivilization()