mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-13 03:54:06 +09:00
fixed worldgen and threadexecutor so that they will actually wait for the thread termination
This commit is contained in:
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user