From e71c56cf0d4604780c23135b27d6ad9b7e442c94 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 16 Nov 2019 02:41:25 +0900 Subject: [PATCH] fixed worldgen and threadexecutor so that they will actually wait for the thread termination --- src/net/torvald/terrarum/LoadScreen.kt | 14 ++-- .../terrarum/concurrent/ThreadParallel.kt | 22 ++++++- src/net/torvald/terrarum/console/Version.kt | 5 +- .../modulebasegame/WorldgenLoadScreen.kt | 24 ++++++- .../modulebasegame/worldgenerator/Terragen.kt | 7 +- .../modulebasegame/worldgenerator/Worldgen.kt | 1 - src/net/torvald/terrarum/ui/ConsoleWindow.kt | 12 ++-- src/net/torvald/util/CircularArray.kt | 17 ++++- src/net/torvald/util/HistoryArray.kt | 66 ------------------- 9 files changed, 74 insertions(+), 94 deletions(-) delete mode 100644 src/net/torvald/util/HistoryArray.kt diff --git a/src/net/torvald/terrarum/LoadScreen.kt b/src/net/torvald/terrarum/LoadScreen.kt index 74c516559..48e39be28 100644 --- a/src/net/torvald/terrarum/LoadScreen.kt +++ b/src/net/torvald/terrarum/LoadScreen.kt @@ -9,7 +9,7 @@ import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.jme3.math.FastMath import net.torvald.terrarum.langpack.Lang -import net.torvald.util.HistoryArray +import net.torvald.util.CircularArray /** * Created by minjaesong on 2017-07-13. @@ -20,10 +20,10 @@ object LoadScreen : ScreenAdapter() { private lateinit var screenLoadingThread: Thread - private val messages = HistoryArray(20) + private val messages = CircularArray(20, true) fun addMessage(msg: String) { - messages.add(msg) + messages.appendHead(msg) } @@ -238,9 +238,9 @@ object LoadScreen : ScreenAdapter() { // log messages it.color = messageForegroundColour - for (i in 0 until messages.elemCount) { + messages.forEachIndexed { i, s -> AppLoader.fontGame.draw(it, - messages[i] ?: "", + s, AppLoader.getTvSafeGraphicsWidth() + 16f, 80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight ) @@ -263,9 +263,9 @@ object LoadScreen : ScreenAdapter() { // log messages it.color = messageForegroundColour - for (i in 0 until messages.elemCount) { + messages.forEachIndexed { i, s -> AppLoader.fontGame.draw(it, - messages[i] ?: "", + s, AppLoader.getTvSafeGraphicsWidth() + 16f, 80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight ) diff --git a/src/net/torvald/terrarum/concurrent/ThreadParallel.kt b/src/net/torvald/terrarum/concurrent/ThreadParallel.kt index e36188c54..a79684e47 100644 --- a/src/net/torvald/terrarum/concurrent/ThreadParallel.kt +++ b/src/net/torvald/terrarum/concurrent/ThreadParallel.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.concurrent import java.util.concurrent.Executors +import java.util.concurrent.Future import java.util.concurrent.TimeUnit import kotlin.math.absoluteValue @@ -11,12 +12,27 @@ typealias ThreadableFun = (Int) -> Unit object ThreadExecutor { val threadCount = Runtime.getRuntime().availableProcessors() // not using (logicalCores + 1) method; it's often better idea to reserve one extra thread for other jobs in the app - private val executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) + private var executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) - fun submit(t: Runnable) = executor.submit(t) - fun submit(f: RunnableFun) = executor.submit { f() } + private fun checkShutdown() { + if (!executor.isShutdown) return + if (executor.isShutdown&& !executor.isTerminated) + throw IllegalStateException("Thread pool is still running") + + executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) + } + + fun submit(t: Runnable): Future<*> { + checkShutdown() + return executor.submit(t) + } + fun submit(f: RunnableFun): Future<*> { + checkShutdown() + return executor.submit { f() } + } fun join() { + executor.shutdown() // thread status of completed ones will be WAIT instead of TERMINATED without this line... executor.awaitTermination(24L, TimeUnit.HOURS) } diff --git a/src/net/torvald/terrarum/console/Version.kt b/src/net/torvald/terrarum/console/Version.kt index b9af9b391..ce54993e7 100644 --- a/src/net/torvald/terrarum/console/Version.kt +++ b/src/net/torvald/terrarum/console/Version.kt @@ -12,8 +12,9 @@ internal object Version : ConsoleCommand { override fun execute(args: Array) { Echo("${AppLoader.GAME_NAME} ${AppLoader.getVERSION_STRING()}") - Echo("Polyglot language pack version ${Lang.POLYGLOT_VERSION}") - Echo("GL_VERSION: ${Terrarum.GL_VERSION}") + Echo("Java version: ${System.getProperty("java.version")}") + Echo("Polyglot language pack version: ${Lang.POLYGLOT_VERSION}") + Echo("GL version: ${Terrarum.GL_VERSION}") Echo("Renderer: ${Gdx.graphics.glVersion.rendererString}, ${Gdx.graphics.glVersion.vendorString}") } diff --git a/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt b/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt index e9f0408d8..c7d32f4d0 100644 --- a/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt +++ b/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt @@ -1,10 +1,12 @@ package net.torvald.terrarum.modulebasegame import com.badlogic.gdx.ScreenAdapter +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.Texture import net.torvald.terrarum.AppLoader import net.torvald.terrarum.IngameInstance import net.torvald.terrarum.gameworld.GameWorld -import net.torvald.util.HistoryArray +import net.torvald.util.CircularArray import kotlin.math.roundToInt /** @@ -25,7 +27,25 @@ class WorldgenLoadScreen(private var world: GameWorld, private var screenToLoad: private lateinit var screenLoadingThread: Thread + private lateinit var previewPixmap: Pixmap + private lateinit var previewTexture: Texture - private val messages = HistoryArray(20) + private val messages = CircularArray(20, true) // this many texts will be shown at once + override fun show() { + previewPixmap = Pixmap(previewWidth, previewHeight, Pixmap.Format.RGBA8888) + previewTexture = Texture(1, 1, Pixmap.Format.RGBA8888) + } + + override fun render(delta: Float) { + previewTexture.dispose() + previewTexture = Texture(previewPixmap) + + // + } + + override fun dispose() { + previewPixmap.dispose() + previewTexture.dispose() + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index a2a638351..c755c86c0 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -3,11 +3,8 @@ package net.torvald.terrarum.modulebasegame.worldgenerator import com.sudoplay.joise.Joise import com.sudoplay.joise.module.* import net.torvald.terrarum.AppLoader.printdbg -import net.torvald.terrarum.LoadScreen import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.concurrent.ThreadExecutor -import net.torvald.terrarum.concurrent.ThreadParallel -import net.torvald.terrarum.concurrent.mapToThreadPoolDirectly import net.torvald.terrarum.gameworld.GameWorld import java.util.concurrent.Future import kotlin.math.cos @@ -31,7 +28,7 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par // single-threaded impl because I couldn't resolve multithread memory corruption issue... genFuture = ThreadExecutor.submit { for (x in 0 until world.width) { - //printdbg(this, "Tile draw for y=$y") + printdbg(this, "Tile draw for x=$x") for (y in 0 until world.height) { val sampleTheta = (x.toDouble() / world.width) * TWO_PI val sampleOffset = world.width / 8.0 @@ -45,6 +42,8 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par } } + ThreadExecutor.join() + printdbg(this, "Waking up Worldgen") //Worldgen.wake() } diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt index b84c7c2b2..948c44e91 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt @@ -1,6 +1,5 @@ package net.torvald.terrarum.modulebasegame.worldgenerator -import net.torvald.terrarum.AppLoader import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.LoadScreen import net.torvald.terrarum.gameworld.GameWorld diff --git a/src/net/torvald/terrarum/ui/ConsoleWindow.kt b/src/net/torvald/terrarum/ui/ConsoleWindow.kt index 639f5c00e..374bafe58 100644 --- a/src/net/torvald/terrarum/ui/ConsoleWindow.kt +++ b/src/net/torvald/terrarum/ui/ConsoleWindow.kt @@ -10,7 +10,7 @@ import net.torvald.terrarum.console.Authenticator import net.torvald.terrarum.console.CommandInterpreter import net.torvald.terrarum.fillRect import net.torvald.terrarum.langpack.Lang -import net.torvald.util.HistoryArray +import net.torvald.util.CircularArray /** @@ -30,7 +30,7 @@ class ConsoleWindow : UICanvas() { private var messagesCount: Int = 0 private var commandInputPool: StringBuilder? = null - private var commandHistory = HistoryArray(COMMAND_HISTORY_MAX) + private var commandHistory = CircularArray(COMMAND_HISTORY_MAX, true) private val LINE_HEIGHT = 20 private val MESSAGES_DISPLAY_COUNT = 11 @@ -83,7 +83,7 @@ class ConsoleWindow : UICanvas() { override fun keyDown(key: Int): Boolean { // history - if (key == Input.Keys.UP && historyIndex < commandHistory.history.size) + if (key == Input.Keys.UP && historyIndex < commandHistory.elemCount) historyIndex++ else if (key == Input.Keys.DOWN && historyIndex >= 0) historyIndex-- @@ -92,7 +92,7 @@ class ConsoleWindow : UICanvas() { // execute if (key == Input.Keys.ENTER && commandInputPool!!.isNotEmpty()) { - commandHistory.add(commandInputPool!!.toString()) + commandHistory.appendHead(commandInputPool!!.toString()) executeCommand() commandInputPool = StringBuilder() } @@ -105,7 +105,7 @@ class ConsoleWindow : UICanvas() { // create new stringbuilder commandInputPool = StringBuilder() if (historyIndex >= 0) // just leave blank if index is -1 - commandInputPool!!.append(commandHistory[historyIndex] ?: "") + commandInputPool!!.append(commandHistory[historyIndex]) } // delete input else if (key == Input.Keys.BACKSPACE) { @@ -179,7 +179,7 @@ class ConsoleWindow : UICanvas() { messageDisplayPos = 0 messagesCount = 0 inputCursorPos = 0 - commandHistory = HistoryArray(COMMAND_HISTORY_MAX) + commandHistory = CircularArray(COMMAND_HISTORY_MAX, true) commandInputPool = StringBuilder() if (Authenticator.b()) { diff --git a/src/net/torvald/util/CircularArray.kt b/src/net/torvald/util/CircularArray.kt index 85cdf2fa1..fd54ef0cb 100644 --- a/src/net/torvald/util/CircularArray.kt +++ b/src/net/torvald/util/CircularArray.kt @@ -16,7 +16,7 @@ import java.util.* class CircularArray(val size: Int, val overwriteOnOverflow: Boolean): Iterable { /** - * What to do when old element is being overridden by the new element (only makes sense when ```overwriteOnOverflow = true```) + * What to do RIGHT BEFORE old element is being overridden by the new element (only makes sense when ```overwriteOnOverflow = true```) * * This function will not be called when ```removeHead()``` or ```removeTail()``` is called. */ @@ -48,6 +48,12 @@ class CircularArray(val size: Int, val overwriteOnOverflow: Boolean): Iterabl private inline fun incTail() { tail = (tail + 1).wrap() } private inline fun decTail() { tail = (tail - 1).wrap() } + fun clear() { + tail = 0 + head = 0 + overflow = false + } + /** * When the overflowing is enabled, tail element (ultimate element) will be changed into the penultimate element. */ @@ -116,6 +122,11 @@ class CircularArray(val size: Int, val overwriteOnOverflow: Boolean): Iterabl /** Returns the oldest (first of the array) element */ fun getTailElem(): T = buffer[tail] + /** + * Relative-indexed get. Index of zero will return the head element. + */ + operator fun get(index: Int) = buffer[(head - 1 - index).wrap()] + private fun getAbsoluteRange() = 0 until when { head == tail -> buffer.size tail > head -> buffer.size - (((head - 1).wrap()) - tail) @@ -171,11 +182,11 @@ class CircularArray(val size: Int, val overwriteOnOverflow: Boolean): Iterabl return accumulator } - private fun Int.wrap() = this fmod size + private inline fun Int.wrap() = this fmod size override fun toString(): String { return "CircularArray(size=${buffer.size}, head=$head, tail=$tail, overflow=$overflow)" } - private infix fun Int.fmod(other: Int) = Math.floorMod(this, other) + private inline infix fun Int.fmod(other: Int) = Math.floorMod(this, other) } \ No newline at end of file diff --git a/src/net/torvald/util/HistoryArray.kt b/src/net/torvald/util/HistoryArray.kt deleted file mode 100644 index 5c4762050..000000000 --- a/src/net/torvald/util/HistoryArray.kt +++ /dev/null @@ -1,66 +0,0 @@ -package net.torvald.util - -import java.util.* - -/** - * Simple ArrayList wrapper that acts as history keeper. You can append any data but cannot delete. - * - * Created by minjaesong on 2016-07-13. - */ -class HistoryArray(val size: Int) { - - val history = ArrayList(Math.min(size, 256)) // 256: arbitrary set upper bound - - val lastIndex = size - 1 - - val elemCount: Int - get() = history.size - - fun add(value: T) { - if (history.size == 0) { - history.add(value) - return - } - // push existing values to an index - else { - for (i in history.size - 1 downTo 0) { - // if history.size is smaller than 'size', make room by appending - if (i == history.size - 1 && i < size - 1) - history.add(history[i]) - // actually move if we have some room - else if (i < size - 1) - history[i + 1] = history[i] - } - } - // add new value to the room - history[0] = value - } - - /** - * Get certain index from history. NOTE: index 0 means latest! - */ - operator fun get(index: Int): T? = - if (index >= history.size) null - else history[index] - - /** - * Iterate from latest to oldest - */ - fun iterator() = history.iterator() - - /** - * Iterate from latest to oldest - */ - fun forEach(action: (T?) -> Unit) = history.forEach(action) - - val latest: T? - get() = this[0] - - val oldest: T? - get() = this[history.size - 1] - - fun clear() { - history.clear() - } - -} \ No newline at end of file