multithreaded tile renumbering

This commit is contained in:
minjaesong
2024-08-31 05:29:59 +09:00
parent 85c1e3ba96
commit 84f0353f09
3 changed files with 84 additions and 5 deletions

View File

@@ -240,7 +240,6 @@ class BTeXDocument : Disposable {
printPageNumber(pixmap, pageNum, 0, 0) printPageNumber(pixmap, pageNum, 0, 0)
pagePixmaps[pageNum] = pixmap pagePixmaps[pageNum] = pixmap
progressIndicator.getAndAdd(1) progressIndicator.getAndAdd(1)
Unit
} } } } } }
ThreadExecutor(THREAD_COUNT).also { ThreadExecutor(THREAD_COUNT).also {

View File

@@ -21,6 +21,8 @@ class ThreadExecutor(
var allFinished = true var allFinished = true
private set private set
private var init = false
init { init {
App.disposables.add(Disposable { this.killAll() }) App.disposables.add(Disposable { this.killAll() })
} }
@@ -35,6 +37,12 @@ class ThreadExecutor(
catch (e: UninitializedPropertyAccessException) {} catch (e: UninitializedPropertyAccessException) {}
} }
private fun checkInit() {
if (!init) {
throw IllegalStateException("ThreadExecuter not initialised; run renew() first!")
}
}
fun renew() { fun renew() {
try { try {
if (!executor.isTerminated && !executor.isShutdown) throw IllegalStateException("Pool is still running") if (!executor.isTerminated && !executor.isShutdown) throw IllegalStateException("Pool is still running")
@@ -45,6 +53,7 @@ class ThreadExecutor(
futures.clear() futures.clear()
isOpen = true isOpen = true
allFinished = false allFinished = false
init = true
} }
/*fun invokeAll(ts: List<Callable<Unit>>) { /*fun invokeAll(ts: List<Callable<Unit>>) {
@@ -52,17 +61,30 @@ class ThreadExecutor(
executor.invokeAll(ts) executor.invokeAll(ts)
}*/ }*/
fun submit1(t: Callable<Any?>) { // is JetBrain's fault, not mine
checkInit()
checkShutdown()
futures.add(executor.submit(t))
}
fun submitAll1(ts: List<Callable<Any?>>) { // is JetBrain's fault, not mine
checkInit()
checkShutdown()
ts.forEach { futures.add(executor.submit(it)) }
}
fun submit(t: Callable<Unit>) { fun submit(t: Callable<Unit>) {
checkInit()
checkShutdown() checkShutdown()
futures.add(executor.submit(t)) futures.add(executor.submit(t))
} }
fun submitAll(ts: List<Callable<Unit>>) { fun submitAll(ts: List<Callable<Unit>>) {
checkInit()
checkShutdown() checkShutdown()
ts.forEach { futures.add(executor.submit(it)) } ts.forEach { futures.add(executor.submit(it)) }
} }
// https://stackoverflow.com/questions/28818494/threads-stopping-prematurely-for-certain-values // https://stackoverflow.com/questions/28818494/threads-stopping-prematurely-for-certain-values
fun join() { fun join() {
checkInit()
//println("ThreadExecutor.join") //println("ThreadExecutor.join")
isOpen = false isOpen = false
futures.forEach { futures.forEach {
@@ -70,7 +92,8 @@ class ThreadExecutor(
it.get() it.get()
} }
catch (e: ExecutionException) { catch (e: ExecutionException) {
throw e e.cause!!.printStackTrace()
throw e.cause!!
} }
} }
executor.shutdown() // thread status of completed ones will be WAIT instead of TERMINATED without this line... executor.shutdown() // thread status of completed ones will be WAIT instead of TERMINATED without this line...

View File

@@ -7,6 +7,7 @@ import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.Fluid import net.torvald.terrarum.blockproperties.Fluid
import net.torvald.terrarum.concurrent.ThreadExecutor
import net.torvald.terrarum.gameactors.ActorID import net.torvald.terrarum.gameactors.ActorID
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameitems.isFluid import net.torvald.terrarum.gameitems.isFluid
@@ -23,6 +24,7 @@ import net.torvald.terrarum.worlddrawer.BlocksDrawer
import net.torvald.util.SortedArrayList import net.torvald.util.SortedArrayList
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
import java.util.* import java.util.*
import java.util.concurrent.Executors.callable
typealias BlockAddress = Long typealias BlockAddress = Long
@@ -301,8 +303,11 @@ open class GameWorld(
// fluidNumberToNameMap[65535] = Fluid.NULL // fluidNumberToNameMap[65535] = Fluid.NULL
// fluidNameToNumberMap[Fluid.NULL] = 0 // fluidNameToNumberMap[Fluid.NULL] = 0
BlocksDrawer.rebuildInternalPrecalculations()
// perform renaming of tile layers // perform renaming of tile layers
for (y in 0 until layerTerrain.height) { /*for (y in 0 until layerTerrain.height) {
for (x in 0 until layerTerrain.width) { for (x in 0 until layerTerrain.width) {
// renumber terrain and wall // renumber terrain and wall
layerTerrain.unsafeSetTile(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerTerrain.unsafeGetTile(x, y).toLong()]]!!) layerTerrain.unsafeSetTile(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerTerrain.unsafeGetTile(x, y).toLong()]]!!)
@@ -318,9 +323,61 @@ open class GameWorld(
val oldFluidName = oldTileNumberToNameMap[oldFluidNum.toLong()] val oldFluidName = oldTileNumberToNameMap[oldFluidNum.toLong()]
layerFluids.unsafeSetTile(x, y, oldFluidName.let { tileNameToNumberMap[it] ?: throw NullPointerException("Unknown tile name: $oldFluidName (<- $oldFluidNum)") }, oldFluidFill) layerFluids.unsafeSetTile(x, y, oldFluidName.let { tileNameToNumberMap[it] ?: throw NullPointerException("Unknown tile name: $oldFluidName (<- $oldFluidNum)") }, oldFluidFill)
} }
} }*/
// will use as much threads you have on the system
printdbg(this, "starting renumbering thread")
try {
val te = ThreadExecutor()
te.renew()
te.submitAll1(
(0 until layerTerrain.width step CHUNK_W).map { xorigin ->
callable {
for (y in 0 until layerTerrain.height) {
for (x in xorigin until (xorigin + CHUNK_W).coerceAtMost(layerTerrain.width)) {
// renumber terrain and wall
layerTerrain.unsafeSetTile(
x, y,
tileNameToNumberMap[oldTileNumberToNameMap[layerTerrain.unsafeGetTile(x, y)
.toLong()]]!!
)
layerWall.unsafeSetTile(
x, y,
tileNameToNumberMap[oldTileNumberToNameMap[layerWall.unsafeGetTile(x, y)
.toLong()]]!!
)
BlocksDrawer.rebuildInternalPrecalculations() // renumber ores
val oldOreNum = layerOres.unsafeGetTile(x, y).toLong()
val oldOreName = oldTileNumberToNameMap[oldOreNum]
layerOres.unsafeSetTileKeepPlacement(x, y,
oldOreName.let {
tileNameToNumberMap[it]
?: throw NullPointerException("Unknown tile name: $oldOreName (<- $oldOreNum)")
})
// renumber fluids
val (oldFluidNum, oldFluidFill) = layerFluids.unsafeGetTile1(x, y)
val oldFluidName = oldTileNumberToNameMap[oldFluidNum.toLong()]
layerFluids.unsafeSetTile(
x, y,
oldFluidName.let {
tileNameToNumberMap[it]
?: throw NullPointerException("Unknown tile name: $oldFluidName (<- $oldFluidNum)")
},
oldFluidFill
)
}
}
}
}
)
te.join()
}
catch (e: Throwable) {
e.printStackTrace()
throw e
}
printdbg(this, "renumbering thread finished")
printdbg(this, "renumberTilesAfterLoad done!") printdbg(this, "renumberTilesAfterLoad done!")
} }