fixed worldgen and threadexecutor so that they will actually wait for the thread termination

This commit is contained in:
minjaesong
2019-11-16 02:41:25 +09:00
parent 9a139be7ad
commit 9972f80874
9 changed files with 74 additions and 94 deletions

View File

@@ -9,7 +9,7 @@ import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.util.HistoryArray import net.torvald.util.CircularArray
/** /**
* Created by minjaesong on 2017-07-13. * Created by minjaesong on 2017-07-13.
@@ -20,10 +20,10 @@ object LoadScreen : ScreenAdapter() {
private lateinit var screenLoadingThread: Thread private lateinit var screenLoadingThread: Thread
private val messages = HistoryArray<String>(20) private val messages = CircularArray<String>(20, true)
fun addMessage(msg: String) { fun addMessage(msg: String) {
messages.add(msg) messages.appendHead(msg)
} }
@@ -238,9 +238,9 @@ object LoadScreen : ScreenAdapter() {
// log messages // log messages
it.color = messageForegroundColour it.color = messageForegroundColour
for (i in 0 until messages.elemCount) { messages.forEachIndexed { i, s ->
AppLoader.fontGame.draw(it, AppLoader.fontGame.draw(it,
messages[i] ?: "", s,
AppLoader.getTvSafeGraphicsWidth() + 16f, AppLoader.getTvSafeGraphicsWidth() + 16f,
80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight 80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight
) )
@@ -263,9 +263,9 @@ object LoadScreen : ScreenAdapter() {
// log messages // log messages
it.color = messageForegroundColour it.color = messageForegroundColour
for (i in 0 until messages.elemCount) { messages.forEachIndexed { i, s ->
AppLoader.fontGame.draw(it, AppLoader.fontGame.draw(it,
messages[i] ?: "", s,
AppLoader.getTvSafeGraphicsWidth() + 16f, AppLoader.getTvSafeGraphicsWidth() + 16f,
80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight 80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight
) )

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum.concurrent package net.torvald.terrarum.concurrent
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
@@ -11,12 +12,27 @@ typealias ThreadableFun = (Int) -> Unit
object ThreadExecutor { 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 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) private fun checkShutdown() {
fun submit(f: RunnableFun) = executor.submit { f() } 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() { fun join() {
executor.shutdown() // thread status of completed ones will be WAIT instead of TERMINATED without this line...
executor.awaitTermination(24L, TimeUnit.HOURS) executor.awaitTermination(24L, TimeUnit.HOURS)
} }

View File

@@ -12,8 +12,9 @@ internal object Version : ConsoleCommand {
override fun execute(args: Array<String>) { override fun execute(args: Array<String>) {
Echo("${AppLoader.GAME_NAME} ${AppLoader.getVERSION_STRING()}") Echo("${AppLoader.GAME_NAME} ${AppLoader.getVERSION_STRING()}")
Echo("Polyglot language pack version ${Lang.POLYGLOT_VERSION}") Echo("Java version: ${System.getProperty("java.version")}")
Echo("GL_VERSION: ${Terrarum.GL_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}") Echo("Renderer: ${Gdx.graphics.glVersion.rendererString}, ${Gdx.graphics.glVersion.vendorString}")
} }

View File

@@ -1,10 +1,12 @@
package net.torvald.terrarum.modulebasegame package net.torvald.terrarum.modulebasegame
import com.badlogic.gdx.ScreenAdapter 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.AppLoader
import net.torvald.terrarum.IngameInstance import net.torvald.terrarum.IngameInstance
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.util.HistoryArray import net.torvald.util.CircularArray
import kotlin.math.roundToInt 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 screenLoadingThread: Thread
private lateinit var previewPixmap: Pixmap
private lateinit var previewTexture: Texture
private val messages = HistoryArray<String>(20) private val messages = CircularArray<String>(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()
}
} }

View File

@@ -3,11 +3,8 @@ package net.torvald.terrarum.modulebasegame.worldgenerator
import com.sudoplay.joise.Joise import com.sudoplay.joise.Joise
import com.sudoplay.joise.module.* import com.sudoplay.joise.module.*
import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.AppLoader.printdbg
import net.torvald.terrarum.LoadScreen
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.concurrent.ThreadExecutor 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 net.torvald.terrarum.gameworld.GameWorld
import java.util.concurrent.Future import java.util.concurrent.Future
import kotlin.math.cos 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... // single-threaded impl because I couldn't resolve multithread memory corruption issue...
genFuture = ThreadExecutor.submit { genFuture = ThreadExecutor.submit {
for (x in 0 until world.width) { 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) { for (y in 0 until world.height) {
val sampleTheta = (x.toDouble() / world.width) * TWO_PI val sampleTheta = (x.toDouble() / world.width) * TWO_PI
val sampleOffset = world.width / 8.0 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") printdbg(this, "Waking up Worldgen")
//Worldgen.wake() //Worldgen.wake()
} }

View File

@@ -1,6 +1,5 @@
package net.torvald.terrarum.modulebasegame.worldgenerator package net.torvald.terrarum.modulebasegame.worldgenerator
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.AppLoader.printdbg
import net.torvald.terrarum.LoadScreen import net.torvald.terrarum.LoadScreen
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld

View File

@@ -10,7 +10,7 @@ import net.torvald.terrarum.console.Authenticator
import net.torvald.terrarum.console.CommandInterpreter import net.torvald.terrarum.console.CommandInterpreter
import net.torvald.terrarum.fillRect import net.torvald.terrarum.fillRect
import net.torvald.terrarum.langpack.Lang 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 messagesCount: Int = 0
private var commandInputPool: StringBuilder? = null private var commandInputPool: StringBuilder? = null
private var commandHistory = HistoryArray<String>(COMMAND_HISTORY_MAX) private var commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true)
private val LINE_HEIGHT = 20 private val LINE_HEIGHT = 20
private val MESSAGES_DISPLAY_COUNT = 11 private val MESSAGES_DISPLAY_COUNT = 11
@@ -83,7 +83,7 @@ class ConsoleWindow : UICanvas() {
override fun keyDown(key: Int): Boolean { override fun keyDown(key: Int): Boolean {
// history // history
if (key == Input.Keys.UP && historyIndex < commandHistory.history.size) if (key == Input.Keys.UP && historyIndex < commandHistory.elemCount)
historyIndex++ historyIndex++
else if (key == Input.Keys.DOWN && historyIndex >= 0) else if (key == Input.Keys.DOWN && historyIndex >= 0)
historyIndex-- historyIndex--
@@ -92,7 +92,7 @@ class ConsoleWindow : UICanvas() {
// execute // execute
if (key == Input.Keys.ENTER && commandInputPool!!.isNotEmpty()) { if (key == Input.Keys.ENTER && commandInputPool!!.isNotEmpty()) {
commandHistory.add(commandInputPool!!.toString()) commandHistory.appendHead(commandInputPool!!.toString())
executeCommand() executeCommand()
commandInputPool = StringBuilder() commandInputPool = StringBuilder()
} }
@@ -105,7 +105,7 @@ class ConsoleWindow : UICanvas() {
// create new stringbuilder // create new stringbuilder
commandInputPool = StringBuilder() commandInputPool = StringBuilder()
if (historyIndex >= 0) // just leave blank if index is -1 if (historyIndex >= 0) // just leave blank if index is -1
commandInputPool!!.append(commandHistory[historyIndex] ?: "") commandInputPool!!.append(commandHistory[historyIndex])
} }
// delete input // delete input
else if (key == Input.Keys.BACKSPACE) { else if (key == Input.Keys.BACKSPACE) {
@@ -179,7 +179,7 @@ class ConsoleWindow : UICanvas() {
messageDisplayPos = 0 messageDisplayPos = 0
messagesCount = 0 messagesCount = 0
inputCursorPos = 0 inputCursorPos = 0
commandHistory = HistoryArray<String>(COMMAND_HISTORY_MAX) commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true)
commandInputPool = StringBuilder() commandInputPool = StringBuilder()
if (Authenticator.b()) { if (Authenticator.b()) {

View File

@@ -16,7 +16,7 @@ import java.util.*
class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterable<T> { class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterable<T> {
/** /**
* 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. * This function will not be called when ```removeHead()``` or ```removeTail()``` is called.
*/ */
@@ -48,6 +48,12 @@ class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterabl
private inline fun incTail() { tail = (tail + 1).wrap() } private inline fun incTail() { tail = (tail + 1).wrap() }
private inline fun decTail() { 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. * When the overflowing is enabled, tail element (ultimate element) will be changed into the penultimate element.
*/ */
@@ -116,6 +122,11 @@ class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterabl
/** Returns the oldest (first of the array) element */ /** Returns the oldest (first of the array) element */
fun getTailElem(): T = buffer[tail] 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 { private fun getAbsoluteRange() = 0 until when {
head == tail -> buffer.size head == tail -> buffer.size
tail > head -> buffer.size - (((head - 1).wrap()) - tail) tail > head -> buffer.size - (((head - 1).wrap()) - tail)
@@ -171,11 +182,11 @@ class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterabl
return accumulator return accumulator
} }
private fun Int.wrap() = this fmod size private inline fun Int.wrap() = this fmod size
override fun toString(): String { override fun toString(): String {
return "CircularArray(size=${buffer.size}, head=$head, tail=$tail, overflow=$overflow)" 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)
} }

View File

@@ -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<T>(val size: Int) {
val history = ArrayList<T?>(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()
}
}