diff --git a/assets/mods/LoadOrder.csv b/assets/mods/LoadOrder.csv index 2fd792740..1d47f6ac0 100644 --- a/assets/mods/LoadOrder.csv +++ b/assets/mods/LoadOrder.csv @@ -3,4 +3,4 @@ # You can disable basegame, but we don't recommend. basegame -dwarventech +#dwarventech diff --git a/assets/mods/dwarventech/ModuleComputers.jar b/assets/mods/dwarventech/ModuleComputers.jar index 142f94021..02a0ee35f 100644 Binary files a/assets/mods/dwarventech/ModuleComputers.jar and b/assets/mods/dwarventech/ModuleComputers.jar differ diff --git a/src/net/torvald/terrarum/App.java b/src/net/torvald/terrarum/App.java index 1f840e067..6a33f5ff5 100644 --- a/src/net/torvald/terrarum/App.java +++ b/src/net/torvald/terrarum/App.java @@ -134,7 +134,7 @@ public class App implements ApplicationListener { public static String renderer = "(a super-fancy virtual photoradiator)"; public static String rendererVendor = "(aperture science psychovisualcomputation laboratory)"; - public static int THREAD_COUNT = ThreadExecutor.INSTANCE.getThreadCount(); + public static int THREAD_COUNT = Runtime.getRuntime().availableProcessors(); public static boolean MULTITHREAD; public static final boolean is32BitJVM = !System.getProperty("sun.arch.data.model").contains("64"); @@ -774,8 +774,6 @@ public class App implements ApplicationListener { //MinimapComposer.INSTANCE.dispose(); //FloatDrawer.INSTANCE.dispose(); - ThreadExecutor.INSTANCE.killAll(); - for (Texture texture : ditherPatterns) { texture.dispose(); } diff --git a/src/net/torvald/terrarum/blockstats/MinimapComposer.kt b/src/net/torvald/terrarum/blockstats/MinimapComposer.kt index d2517808d..036d2c174 100644 --- a/src/net/torvald/terrarum/blockstats/MinimapComposer.kt +++ b/src/net/torvald/terrarum/blockstats/MinimapComposer.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum.blockstats +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.glutils.FrameBuffer @@ -8,12 +9,17 @@ import com.badlogic.gdx.utils.GdxRuntimeException import com.badlogic.gdx.utils.Queue import net.torvald.terrarum.App import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.concurrent.ThreadExecutor import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_HEIGHT import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_WIDTH +import net.torvald.terrarum.toInt +import java.util.concurrent.atomic.AtomicInteger object MinimapComposer : Disposable { + private val threadExecutor = ThreadExecutor(maxOf(1, App.THREAD_COUNT.times(2).div(3))) + val MINIMAP_TILE_WIDTH = MINIMAP_WIDTH.toInt() + 16 val MINIMAP_TILE_HEIGHT = MINIMAP_HEIGHT.toInt() + 16 @@ -38,10 +44,9 @@ object MinimapComposer : Disposable { val pixmaps = Array(9) { Pixmap(MINIMAP_TILE_WIDTH, MINIMAP_TILE_HEIGHT, Pixmap.Format.RGBA8888) } - private val updaterQueue = Queue(pixmaps.size) - private var currentThreads = Array(maxOf(1, App.THREAD_COUNT.times(2).div(3))) { - Thread() - } + private val updaterQueue = Array(pixmaps.size) { null } + private var currentThreads = Array(9) { Thread() } + init { @@ -55,41 +60,64 @@ object MinimapComposer : Disposable { */ fun queueRender(x: Int, y: Int) { - val tlx = x - (MINIMAP_TILE_WIDTH / 2) - val tly = y - (MINIMAP_TILE_HEIGHT / 2) + val udc = updaterQueue.sumOf { (it != null).toInt() } + + if (udc == 0) { + val tlx = x - (MINIMAP_TILE_WIDTH / 2) + val tly = y - (MINIMAP_TILE_HEIGHT / 2) // printdbg(this, "queue render - c($x,$y), tl($tlx,$tlx)") - // make the queueing work - // enqueue first - pixmaps.forEachIndexed { i, pixmap -> - val tx = tlx + (MINIMAP_TILE_WIDTH * ((i % 3) - 1)) - val ty = tly + (MINIMAP_TILE_HEIGHT * ((i / 3) - 1)) + // make the queueing work + // enqueue first + pixmaps.forEachIndexed { i, pixmap -> + val tx = tlx + (MINIMAP_TILE_WIDTH * ((i % 3) - 1)) + val ty = tly + (MINIMAP_TILE_HEIGHT * ((i / 3) - 1)) - updaterQueue.addLast(createUpdater(tx, ty, pixmap)) - printdbg(this, "Queueing tilemap update ($tx,$ty); queue size now: ${updaterQueue.size}") - } - - // consume the queue - for (k in currentThreads.indices) { - if (currentThreads[k].state == Thread.State.TERMINATED && !updaterQueue.isEmpty) { - currentThreads[k] = Thread(updaterQueue.removeFirst(), "MinimapLivetilePainter") - printdbg(this, "Consuming from queue; queue size now: ${updaterQueue.size}") + updaterQueue[i] = createUpdater(tx, ty, pixmap, i) + printdbg(this, "Queueing tilemap update ($tx,$ty) from queue[$i]") } - if (currentThreads[k].state == Thread.State.NEW) { - currentThreads[k].start() + + // consume the queue + /*for (k in currentThreads.indices) { + if (currentThreads[k].state == Thread.State.TERMINATED && !updaterQueue.isEmpty) { + currentThreads[k] = Thread(updaterQueue.removeFirst(), "MinimapLivetilePainter") + printdbg(this, "Consuming from queue; queue size now: ${updaterQueue.size}") + } + if (currentThreads[k].state == Thread.State.NEW) { + currentThreads[k].start() + } + }*/ + + updaterQueue.forEachIndexed { k, runnable -> + if (runnable != null) { + currentThreads[k] = Thread(runnable, "MinimapLivetilePainter") + printdbg(this, "Consuming from queue[$k]") + currentThreads[k].start() + } } } + else { + printdbg(this, "$udc Threads still running, request disregarded") + } + + printdbg(this, "** $udc Threads still running **") } private val HQRNG = net.torvald.random.HQRNG() + private val testcols = arrayOf( + Color.CORAL, Color.LIME, Color.CYAN, + Color.YELLOW, Color.SKY, Color.GOLD, + Color.BROWN, Color.DARK_GRAY, Color.RED + ).map { Color(it.lerp(Color.WHITE, 0.5f)) } + /** - * @param tx top-left - * @param ty top-left + * @param tx top-left of the world + * @param ty top-left of the world * @param pixmap pixmap to draw pixels on */ - private fun createUpdater(tx: Int, ty: Int, pixmap: Pixmap) = Runnable { + private fun createUpdater(tx: Int, ty: Int, pixmap: Pixmap, index: Int) = Runnable { for (y in ty until ty + MINIMAP_TILE_HEIGHT) { for (x in tx until tx + MINIMAP_TILE_WIDTH) { val tileTerr = world.getTileFromTerrain(x, y) @@ -100,11 +128,13 @@ object MinimapComposer : Disposable { val outCol = if (colTerr.a > 0.1f) colTerr else colWall pixmap.blending = Pixmap.Blending.None - pixmap.setColor(outCol) - //pixmap.setColor(Color.CORAL) - pixmap.drawPixel(x, y) +// pixmap.setColor(outCol) + pixmap.setColor(outCol.mul(testcols[index])) + pixmap.drawPixel(x - tx, y - ty) } } + + updaterQueue[index] = null } override fun dispose() { diff --git a/src/net/torvald/terrarum/concurrent/ThreadExecutor.kt b/src/net/torvald/terrarum/concurrent/ThreadExecutor.kt index 92b470e4e..8b2d1da76 100644 --- a/src/net/torvald/terrarum/concurrent/ThreadExecutor.kt +++ b/src/net/torvald/terrarum/concurrent/ThreadExecutor.kt @@ -1,5 +1,7 @@ package net.torvald.terrarum.concurrent +import com.badlogic.gdx.utils.Disposable +import net.torvald.terrarum.App import java.util.concurrent.* import kotlin.math.absoluteValue import kotlin.math.roundToInt @@ -9,8 +11,9 @@ typealias RunnableFun = () -> Unit 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 +class ThreadExecutor( + val threadCount: Int = 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 lateinit var executor: ExecutorService// = Executors.newFixedThreadPool(threadCount) val futures = ArrayList>() private var isOpen = true @@ -18,6 +21,10 @@ object ThreadExecutor { var allFinished = true private set + init { + App.disposables.add(Disposable { this.killAll() }) + } + private fun checkShutdown() { try { if (executor.isTerminated) diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index 6f73e778f..f236987fb 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -14,6 +14,7 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.blockproperties.BlockPropUtil import net.torvald.terrarum.blockstats.BlockStats import net.torvald.terrarum.blockstats.MinimapComposer +import net.torvald.terrarum.concurrent.ThreadExecutor import net.torvald.terrarum.console.AVTracker import net.torvald.terrarum.console.ActorsList import net.torvald.terrarum.console.Authenticator @@ -146,6 +147,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { val SIZE_LARGE = Point2i(13500, 2970) val SIZE_HUGE = Point2i(22500, 4500) val WORLDSIZE = arrayOf(SIZE_SMALL, SIZE_NORMAL, SIZE_LARGE, SIZE_HUGE) + + val worldgenThreadExecutor = ThreadExecutor() } diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryMinimap.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryMinimap.kt index 7f7b46c5a..016017108 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryMinimap.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryMinimap.kt @@ -45,7 +45,7 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { private val minimapCamera = OrthographicCamera(MINIMAP_WIDTH, MINIMAP_HEIGHT) private var minimapRerenderTimer = 0f - private val minimapRerenderInterval = 5f // seconds + private val minimapRerenderInterval = 0.5f // seconds private var dragStatus = 0 @@ -69,16 +69,14 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { val mdx = Terrarum.mouseDeltaX * 2f / minimapZoom val mdy = Terrarum.mouseDeltaY * 2f / minimapZoom - minimapPanX += mdx - minimapPanY += mdy + minimapPanX -= mdx + minimapPanY -= mdy minimapTranslateX += mdx minimapTranslateY += mdy dragStatus = 1 } - else if (dragStatus == 1 && !Terrarum.mouseDown) { - dragStatus = 2 - } + if (Gdx.input.isKeyPressed(Input.Keys.NUM_1)) { @@ -109,7 +107,7 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { // render minimap batch.end() - if (dragStatus == 2 || minimapRerenderTimer >= minimapRerenderInterval) { + if (!Terrarum.mouseDown && (dragStatus == 1 || minimapRerenderTimer >= minimapRerenderInterval)) { dragStatus = 0 minimapRerenderTimer = 0f @@ -121,6 +119,8 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { minimapFBO.inActionF(minimapCamera, batch) { + gdxClearAndSetBlend(MINIMAP_SKYCOL) + batch.inUse { // [ 1 0 0 ] [ s 0 0 ] [ s 0 0 ] @@ -130,17 +130,16 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { // https://www.wolframalpha.com/input/?i=%7B%7B1,0,0%7D,%7B0,1,0%7D,%7Bp_x,p_y,1%7D%7D+*+%7B%7Bs,0,0%7D,%7B0,s,0%7D,%7Bw%2F2,h%2F2,1%7D%7D // sky background - batch.color = MINIMAP_SKYCOL - Toolkit.fillArea(batch, 0f, 0f, MINIMAP_WIDTH, MINIMAP_HEIGHT) + batch.color = Color.WHITE MinimapComposer.pixmaps.forEachIndexed { index, pixmap -> - renderTextures[index].dispose() - renderTextures[index] = Texture(pixmap) + renderTextures[MinimapComposer.pixmaps.lastIndex - index].dispose() + renderTextures[MinimapComposer.pixmaps.lastIndex - index] = Texture(pixmap) val ix = index % 3; val iy = index / 3 - val ox = (ix - 1) * MINIMAP_TILE_WIDTH - val oy = (iy - 1) * MINIMAP_TILE_HEIGHT + val ox = (ix - 0.5f) * MINIMAP_TILE_WIDTH + val oy = (iy - 0.5f) * MINIMAP_TILE_HEIGHT val tx = (minimapTranslateX - ox) * minimapZoom + 0.5f * MINIMAP_WIDTH val ty = (minimapTranslateY - oy) * minimapZoom + 0.5f * MINIMAP_HEIGHT @@ -156,7 +155,7 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { val minimapDrawY = (height - cellOffY - App.scr.tvSafeGraphicsHeight - MINIMAP_HEIGHT - 72) / 2 + cellOffY * 1f if (debugvals) { - App.fontSmallNumbers.draw(batch, "$minimapPanX, $minimapPanY; x$minimapZoom", minimapDrawX, minimapDrawY - 16f) + App.fontSmallNumbers.draw(batch, "$minimapPanX, $minimapPanY; $minimapTranslateX, $minimapTranslateY; x$minimapZoom", minimapDrawX, minimapDrawY - 16f) } batch.color = Color.WHITE diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt index ac97d6ff7..a0d402f9a 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt @@ -11,6 +11,7 @@ import net.torvald.terrarum.concurrent.ThreadExecutor import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.fmod +import net.torvald.terrarum.modulebasegame.TerrarumIngame import kotlin.math.cos import kotlin.math.sin @@ -19,15 +20,17 @@ import kotlin.math.sin */ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, params) { - private val genSlices = maxOf(ThreadExecutor.threadCount, world.width / 8) + private val threadExecutor = TerrarumIngame.worldgenThreadExecutor + + private val genSlices = maxOf(threadExecutor.threadCount, world.width / 8) private val YHEIGHT_MAGIC = 2800.0 / 3.0 private val YHEIGHT_DIVISOR = 2.0 / 7.0 override fun getDone() { - ThreadExecutor.renew() + threadExecutor.renew() (0 until world.width).sliceEvenly(genSlices).map { xs -> - ThreadExecutor.submit { + threadExecutor.submit { val localJoise = getGenerator(seed, params as BiomegenParams) for (x in xs) { for (y in 0 until world.height) { @@ -45,7 +48,7 @@ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par } } - ThreadExecutor.join() + threadExecutor.join() App.printdbg(this, "Waking up Worldgen") } diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index dd04da2f9..e5e2ad172 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -8,6 +8,7 @@ import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.concurrent.ThreadExecutor import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.modulebasegame.TerrarumIngame import kotlin.math.cos import kotlin.math.sin @@ -16,7 +17,9 @@ import kotlin.math.sin */ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, params) { - private val genSlices = maxOf(ThreadExecutor.threadCount, world.width / 8) + private val threadExecutor = TerrarumIngame.worldgenThreadExecutor + + private val genSlices = maxOf(threadExecutor.threadCount, world.width / 8) private val YHEIGHT_MAGIC = 2800.0 / 3.0 private val YHEIGHT_DIVISOR = 2.0 / 7.0 @@ -25,9 +28,9 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par private val stoneSlateDitherSize = 4 override fun getDone() { - ThreadExecutor.renew() + threadExecutor.renew() (0 until world.width).sliceEvenly(genSlices).mapIndexed { i, xs -> - ThreadExecutor.submit { + threadExecutor.submit { val localJoise = getGenerator(seed, params as TerragenParams) for (x in xs) { val sampleTheta = (x.toDouble() / world.width) * TWO_PI @@ -37,7 +40,7 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par } } - ThreadExecutor.join() + threadExecutor.join() printdbg(this, "Waking up Worldgen") } diff --git a/src/net/torvald/terrarum/tests/NoiseGenerator.kt b/src/net/torvald/terrarum/tests/NoiseGenerator.kt index 892df2633..92eed2bcc 100644 --- a/src/net/torvald/terrarum/tests/NoiseGenerator.kt +++ b/src/net/torvald/terrarum/tests/NoiseGenerator.kt @@ -31,6 +31,8 @@ import kotlin.math.roundToInt */ class NoiseGenerator : ScreenAdapter() { + private val threadExecutor = ThreadExecutor() + lateinit var batch: SpriteBatch lateinit var camera: OrthographicCamera lateinit var pixmap: Pixmap @@ -109,13 +111,13 @@ class NoiseGenerator : ScreenAdapter() { // regen - if (timerFired && ThreadExecutor.allFinished) { + if (timerFired && threadExecutor.allFinished) { timerFired = false totalTestsDone += 1 } - if (regenerate && ThreadExecutor.allFinished) { + if (regenerate && threadExecutor.allFinished) { //printdbg(this, "Reticulating splines...") regenerate = false @@ -126,9 +128,9 @@ class NoiseGenerator : ScreenAdapter() { val seed = RNG.nextLong() val jobs = List(jobsCount) { makeGenFun(seed, it) } - ThreadExecutor.renew() - ThreadExecutor.submitAll(jobs) - ThreadExecutor.join() + threadExecutor.renew() + threadExecutor.submitAll(jobs) + threadExecutor.join() } @@ -195,7 +197,7 @@ class NoiseGenerator : ScreenAdapter() { System.exit(0) } // time to construct a new test - if (totalTestsDone % samplingCount == 0 && ThreadExecutor.allFinished) { + if (totalTestsDone % samplingCount == 0 && threadExecutor.allFinished) { pixelsInSingleJob = (IMAGE_SIZE * IMAGE_SIZE) / testSets[totalTestsDone / samplingCount] @@ -216,7 +218,7 @@ class NoiseGenerator : ScreenAdapter() { } // auto-press SPACE - if (ThreadExecutor.allFinished) { + if (threadExecutor.allFinished) { regenerate = true constructOnce = false } diff --git a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt index c72608629..0f7a8b8a3 100644 --- a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt +++ b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt @@ -38,6 +38,8 @@ const val TWO_PI = Math.PI * 2 */ class WorldgenNoiseSandbox : ApplicationAdapter() { + private val threadExecutor = ThreadExecutor() + private lateinit var batch: SpriteBatch private lateinit var camera: OrthographicCamera private lateinit var font: BitmapFont @@ -70,7 +72,7 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { testTex.blending = Pixmap.Blending.None tempTex = Texture(1, 1, Pixmap.Format.RGBA8888) - genSlices = maxOf(ThreadExecutor.threadCount, testTex.width / 8) + genSlices = maxOf(threadExecutor.threadCount, testTex.width / 8) println("Init done") } @@ -234,12 +236,12 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { } } - ThreadExecutor.renew() + threadExecutor.renew() runnables.forEach { - ThreadExecutor.submit(it) + threadExecutor.submit(it) } - ThreadExecutor.join() + threadExecutor.join() initialGenDone = true }