diff --git a/assets/graphics/fonts/7x13_Tamzen7x14b.tga b/assets/graphics/fonts/7x13_Tamzen7x14b.tga new file mode 100644 index 000000000..e3937e438 --- /dev/null +++ b/assets/graphics/fonts/7x13_Tamzen7x14b.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b5a5fe181fa98c705df6e508433ef44b83016a0fc9de9f07b96637c898c4bfc +size 34988 diff --git a/src/module-info.java.wtf b/src/module-info.java.wtf index f5a203305..6d6af58ec 100644 --- a/src/module-info.java.wtf +++ b/src/module-info.java.wtf @@ -1,16 +1,26 @@ module terrarum { + // java + requires java.desktop; + requires java.logging; + requires jdk.unsupported; // sun.misc.Unsafe + + // kotlin + requires kotlin.stdlib; + + // gdx requires gdx; requires gdx.backend.lwjgl; requires gdx.controllers; + + // terrarum + requires TerrarumSansBitmap; + requires TerranVirtualDisk; + requires Terrarum.Joise; + + // etc + requires GetCpuName; requires jxinput; requires gson; - requires GetCpuName; - requires TerrarumSansBitmap; - requires kotlin.stdlib; - requires java.desktop; - requires java.logging; - requires TerranVirtualDisk; requires commons.codec; requires commons.csv; - requires Terrarum.Joise; } \ No newline at end of file diff --git a/src/net/torvald/terrarum/AppLoader.java b/src/net/torvald/terrarum/AppLoader.java index 6f0dc07ea..aa15a4f56 100644 --- a/src/net/torvald/terrarum/AppLoader.java +++ b/src/net/torvald/terrarum/AppLoader.java @@ -125,10 +125,10 @@ public class AppLoader implements ApplicationListener { public static String GAME_LOCALE = System.getProperty("user.language") + System.getProperty("user.country"); public static final String systemArch = System.getProperty("os.arch"); - public static String processor; - public static String processorVendor; - public static String renderer; - public static String rendererVendor; + public static String processor = "(a super-duper virtual processor)"; + public static String processorVendor = "(andromeda software development)"; // definitely not taken from "that" demogroup + public static String renderer = "(a super-fancy virtual photoradiator)"; + public static String rendererVendor = "(radiosity)"; public static final boolean is32BitJVM = !System.getProperty("sun.arch.data.model").contains("64"); @@ -610,15 +610,14 @@ public class AppLoader implements ApplicationListener { if (injectScreen != null) { setScreen(injectScreen); } + else { + ModMgr.INSTANCE.invoke(); // invoke Module Manager + AppLoader.resourcePool.loadAll(); + printdbg(this, "all modules loaded successfully"); - - ModMgr.INSTANCE.invoke(); // invoke Module Manager - AppLoader.resourcePool.loadAll(); - printdbg(this, "all modules loaded successfully"); - - - BlocksDrawer.INSTANCE.getWorld(); // will initialize the BlocksDrawer by calling dummy method - LightmapRenderer.INSTANCE.hdr(0f); + BlocksDrawer.INSTANCE.getWorld(); // will initialize the BlocksDrawer by calling dummy method + LightmapRenderer.INSTANCE.hdr(0f); + } printdbg(this, "PostInit done"); diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 22f24a9d6..5c8125d04 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -15,6 +15,7 @@ import com.badlogic.gdx.utils.GdxRuntimeException import com.jme3.math.FastMath import net.torvald.random.HQRNG import net.torvald.terrarum.AppLoader.* +import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.gameactors.Actor import net.torvald.terrarum.gameactors.ActorID import net.torvald.terrarum.imagefont.TinyAlphNum @@ -166,7 +167,7 @@ object Terrarum : Screen, Disposable { val STATE_ID_TOOL_RUMBLE_DIAGNOSIS = 0x201 /** Available CPU threads */ - val THREADS = Runtime.getRuntime().availableProcessors() + 1 + val THREADS = ThreadParallel.threadCount //Runtime.getRuntime().availableProcessors() + 1 /** * If the game is multithreading. @@ -196,19 +197,22 @@ object Terrarum : Screen, Disposable { init { - println("$NAME version ${AppLoader.getVERSION_STRING()}") - println("LibGDX version ${com.badlogic.gdx.Version.VERSION}") + println("[Terrarum] init called by:") + Thread.currentThread().stackTrace.forEach { println("... $it") } + + println("[Terrarum] $NAME version ${AppLoader.getVERSION_STRING()}") + println("[Terrarum] LibGDX version ${com.badlogic.gdx.Version.VERSION}") - println("os.arch = $systemArch") // debug info + println("[Terrarum] os.arch = $systemArch") // debug info if (is32BitJVM) { printdbgerr(this, "32 Bit JVM detected") } - println("processor = $processor") - println("vendor = $processorVendor") + println("[Terrarum] processor = $processor") + println("[Terrarum] vendor = $processorVendor") setGamepadButtonLabels() @@ -216,6 +220,9 @@ object Terrarum : Screen, Disposable { AppLoader.disposableSingletonsPool.add(this) + + + println("[Terrarum] init complete") } private fun setGamepadButtonLabels() { diff --git a/src/net/torvald/terrarum/blockproperties/BlockCodex.kt b/src/net/torvald/terrarum/blockproperties/BlockCodex.kt index 64a77e6d4..8855dbf61 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockCodex.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockCodex.kt @@ -93,7 +93,7 @@ object BlockCodex { } } - fun getOrNull(rawIndex: Int?): BlockProp? { + fun getOrNull(rawIndex: Int?): BlockProp? {// return blockProps[rawIndex] } diff --git a/src/net/torvald/terrarum/concurrent/ThreadParallel.kt b/src/net/torvald/terrarum/concurrent/ThreadParallel.kt index 5e144b270..bce092d02 100644 --- a/src/net/torvald/terrarum/concurrent/ThreadParallel.kt +++ b/src/net/torvald/terrarum/concurrent/ThreadParallel.kt @@ -1,6 +1,5 @@ package net.torvald.terrarum.concurrent -import net.torvald.terrarum.Terrarum import kotlin.math.absoluteValue typealias RunnableFun = () -> Unit @@ -11,7 +10,7 @@ typealias ThreadableFun = (Int) -> Unit * Created by minjaesong on 2016-05-25. */ object ThreadParallel { - val threadCount = Terrarum.THREADS // modify this to your taste + val threadCount = Runtime.getRuntime().availableProcessors() + 1 // modify this to your taste private val pool: Array = Array(threadCount) { null } @@ -49,6 +48,7 @@ object ThreadParallel { * Start all thread in the pool and wait for them to all die. If the thread in the pool is NULL, it will simply ignored. */ fun startAllWaitForDie() { + // ThreadParallelTester says this function actually works as intended... pool.forEach { it?.start() } pool.forEach { it?.join() } } @@ -69,7 +69,7 @@ object ThreadParallel { */ @Deprecated("Experimental.", ReplaceWith("ThreadParallel", "net.torvald.terrarum.concurrent.ThreadParallel")) object BlockingThreadPool { - val threadCount = Terrarum.THREADS // modify this to your taste + val threadCount = Runtime.getRuntime().availableProcessors() + 1 // modify this to your taste private val pool: Array = Array(threadCount, { null }) private var tasks: List = ArrayList() @Volatile private var dispatchedTasks = 0 @@ -127,85 +127,84 @@ object BlockingThreadPool { } } -object ParallelUtils { - fun Iterable.parallelMap(transform: (T) -> R): List { - val tasks = this.sliceEvenly(ThreadParallel.threadCount) - val destination = Array(ThreadParallel.threadCount) { ArrayList() } - tasks.forEachIndexed { index, list -> - ThreadParallel.map(index, "ParallelUtils.parallelMap@${this.javaClass.canonicalName}") { - for (item in list) - destination[index].add(transform(item as T)) - } - } - ThreadParallel.startAllWaitForDie() - - return destination.flatten() - } - - /** - * Shallow flat of the array - */ - fun Array>.flatten(): List { - val al = ArrayList() - this.forEach { it.forEach { al.add(it) } } - return al - } - - /** - * Shallow flat of the iterable - */ - fun Iterable>.flatten(): List { - val al = ArrayList() - this.forEach { it.forEach { al.add(it) } } - return al - } - - /** - * Shallow flat of the array - */ - fun Array>.flatten(): List { - val al = ArrayList() - this.forEach { it.forEach { al.add(it) } } - return al - } - - fun Iterable.sliceEvenly(slices: Int): List> = this.toList().sliceEvenly(slices) - - fun List.sliceEvenly(slices: Int): List> { - return (0 until slices).map { - this.subList( - this.size.toFloat().div(slices).times(it).roundInt(), - this.size.toFloat().div(slices).times(it + 1).roundInt() - ) +fun Iterable.parallelMap(transform: (T) -> R): List { + val tasks = this.sliceEvenly(ThreadParallel.threadCount) + val destination = Array(ThreadParallel.threadCount) { ArrayList() } + tasks.forEachIndexed { index, list -> + ThreadParallel.map(index, "ParallelUtils.parallelMap@${this.javaClass.canonicalName}") { + for (item in list) + destination[index].add(transform(item as T)) } } - fun Array.sliceEvenly(slices: Int): List> { - return (0 until slices).map { - this.sliceArray( - this.size.toFloat().div(slices).times(it).roundInt() until - this.size.toFloat().div(slices).times(it + 1).roundInt() - ) - } + ThreadParallel.startAllWaitForDie() + + return destination.flatten() +} + +/** + * Shallow flat of the array + */ +fun Array>.flatten(): List { + val al = ArrayList() + this.forEach { it.forEach { al.add(it) } } + return al +} + +/** + * Shallow flat of the iterable + */ +fun Iterable>.flatten(): List { + val al = ArrayList() + this.forEach { it.forEach { al.add(it) } } + return al +} + +/** + * Shallow flat of the array + */ +fun Array>.flatten(): List { + val al = ArrayList() + this.forEach { it.forEach { al.add(it) } } + return al +} + +fun Iterable.sliceEvenly(slices: Int): List> = this.toList().sliceEvenly(slices) + +fun List.sliceEvenly(slices: Int): List> { + return (0 until slices).map { + this.subList( + this.size.toFloat().div(slices).times(it).roundInt(), + this.size.toFloat().div(slices).times(it + 1).roundInt() + ) } +} - fun IntProgression.sliceEvenly(slices: Int): List { - if (this.step.absoluteValue != 1) throw UnsupportedOperationException("Sorry, step != +1/-1") - val size = (this.last - this.first).absoluteValue + (this.step.toFloat()).absoluteValue - - // println(size) - - return if (this.first < this.last) (0 until slices).map { - this.first + size.div(slices).times(it).roundInt() .. - this.first + size.div(slices).times(it + 1).roundInt() - 1 - } - else (0 until slices).map { - this.first - size.div(slices).times(it).roundInt() downTo - this.first - size.div(slices).times(it + 1).roundInt() + 1 - } +fun Array.sliceEvenly(slices: Int): List> { + return (0 until slices).map { + this.sliceArray( + this.size.toFloat().div(slices).times(it).roundInt() until + this.size.toFloat().div(slices).times(it + 1).roundInt() + ) } +} + +fun IntProgression.sliceEvenly(slices: Int): List { + if (this.step.absoluteValue != 1) throw UnsupportedOperationException("Sorry, step != +1/-1") + val size = (this.last - this.first).absoluteValue + (this.step.toFloat()).absoluteValue + + // println(size) + + return if (this.first < this.last) (0 until slices).map { + this.first + size.div(slices).times(it).roundInt() .. + this.first + size.div(slices).times(it + 1).roundInt() - 1 + } + else (0 until slices).map { + this.first - size.div(slices).times(it).roundInt() downTo + this.first - size.div(slices).times(it + 1).roundInt() + 1 + } +} - private inline fun Float.roundInt(): Int = Math.round(this) -} \ No newline at end of file +private inline fun Float.roundInt(): Int = Math.round(this) \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 3f9479475..71af8f3c1 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -464,6 +464,7 @@ open class GameWorld : Disposable { override fun dispose() { layerWall.dispose() layerTerrain.dispose() + //nullWorldInstance?.dispose() // must be called ONLY ONCE; preferably when the app exits } companion object { diff --git a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt index e878f1e8f..c1bcb13b3 100644 --- a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt +++ b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt @@ -86,7 +86,7 @@ class EntryPoint : ModuleEntryPoint() { - println("Welcome back!") + println("[Basegame.EntryPoint] Welcome back!") } override fun dispose() { diff --git a/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt index 0e94ac84e..2d40cf69e 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt @@ -52,6 +52,7 @@ object WorldSimulator { private val ingame = Terrarum.ingame!! private val world = ingame.world + // TODO use R-Tree instead? https://stackoverflow.com/questions/10269179/find-rectangles-that-contain-point-efficient-algorithm#10269695 private var actorsKDTree: KDTree? = null fun resetForThisFrame() { diff --git a/src/net/torvald/terrarum/tests/NoiseGenerator.kt b/src/net/torvald/terrarum/tests/NoiseGenerator.kt index 7fda7fb6a..6eee0a34f 100644 --- a/src/net/torvald/terrarum/tests/NoiseGenerator.kt +++ b/src/net/torvald/terrarum/tests/NoiseGenerator.kt @@ -20,7 +20,7 @@ import net.torvald.random.HQRNG import net.torvald.terrarum.AppLoader import net.torvald.terrarum.Terrarum import net.torvald.terrarum.concurrent.BlockingThreadPool -import net.torvald.terrarum.concurrent.ParallelUtils.sliceEvenly +import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.inUse import net.torvald.terrarum.modulebasegame.Ingame import net.torvald.terrarum.roundInt diff --git a/src/net/torvald/terrarum/tests/ThreadParallelTester.kt b/src/net/torvald/terrarum/tests/ThreadParallelTester.kt new file mode 100644 index 000000000..026a3b920 --- /dev/null +++ b/src/net/torvald/terrarum/tests/ThreadParallelTester.kt @@ -0,0 +1,164 @@ +package net.torvald.terrarum.tests + +import com.badlogic.gdx.ApplicationAdapter +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.Input +import com.badlogic.gdx.InputAdapter +import com.badlogic.gdx.backends.lwjgl.LwjglApplication +import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.OrthographicCamera +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.Texture +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import com.badlogic.gdx.graphics.glutils.ShaderProgram +import com.sudoplay.joise.Joise +import com.sudoplay.joise.module.ModuleBasisFunction +import com.sudoplay.joise.module.ModuleFractal +import com.sudoplay.joise.module.ModuleScaleOffset +import net.torvald.random.HQRNG +import net.torvald.terrarum.concurrent.ThreadParallel +import net.torvald.terrarum.concurrent.ThreadableFun +import net.torvald.terrarum.concurrent.sliceEvenly +import net.torvald.terrarum.inUse +import net.torvald.terrarum.roundInt +import kotlin.math.absoluteValue +import kotlin.system.measureNanoTime + +/** + * Created by minjaesong on 2019-06-17. + */ +class ThreadParallelTester : ApplicationAdapter() { + + lateinit var batch: SpriteBatch + lateinit var camera: OrthographicCamera + lateinit var pixmap: Pixmap + lateinit var texture: Texture + private val IMAGE_SIZE = 1024 + private val IMAGE_SIZEF = IMAGE_SIZE.toFloat() + private val IMAGE_SIZED = IMAGE_SIZE.toDouble() + private val RNG = HQRNG() + + override fun create() { + Gdx.input.inputProcessor = ThreadParallelTesterController(this) + + batch = SpriteBatch() + camera = OrthographicCamera(IMAGE_SIZEF, IMAGE_SIZEF) + + camera.setToOrtho(true, IMAGE_SIZEF, IMAGE_SIZEF) + camera.update() + Gdx.gl20.glViewport(0, 0, IMAGE_SIZE, IMAGE_SIZE) + + pixmap = Pixmap(IMAGE_SIZE, IMAGE_SIZE, Pixmap.Format.RGBA8888) + texture = Texture(1, 1, Pixmap.Format.RGBA8888) + + batch.projectionMatrix = camera.combined + + println("[ThreadParallelTester] Hello, world!") + } + + var regenerate = true + var generateDone = true + + override fun render() { + Gdx.graphics.setTitle("F: ${Gdx.graphics.framesPerSecond}") + + if (regenerate) { + // fill pixmap with slow-to-calculate noises. + // create parallel job + // run parallel job, wait all of them to die + // render the pixmap + + // expected result: app freezes (or nothing is drawn) until all the parallel job is done + + println("Noise regenerating...") + regenerate = false + generateDone = false + val time = measureNanoTime { + setupParallelJobs() + //ThreadParallel.startAll() + ThreadParallel.startAllWaitForDie() + } + generateDone = true + println("Noise generation complete, took ${time.toDouble() / 1_000_000} ms\n") + } + + // render + texture.dispose() + texture = Texture(pixmap) + + batch.inUse { + batch.projectionMatrix = camera.combined + batch.color = Color.WHITE + batch.draw(texture, 0f, 0f) + } + } + + private fun setupParallelJobs() { + val seed = RNG.nextLong() + for (i in 0 until ThreadParallel.threadCount) { + ThreadParallel.map(i, "NoiseGen", makeGenFun(seed, i)) + } + } + + private val scanlineNumbers: List = (0 until IMAGE_SIZE).sliceEvenly(ThreadParallel.threadCount) + private fun makeGenFun(seed: Long, index: Int): ThreadableFun = { i -> + val module = ModuleFractal() + module.setType(ModuleFractal.FractalType.BILLOW) + module.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + module.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + module.setNumOctaves(10) + module.setFrequency(8.0) + module.seed = seed + + val moduleScale = ModuleScaleOffset() + moduleScale.setSource(module) + moduleScale.setScale(0.5) + moduleScale.setOffset(0.0) + + val noiseModule = Joise(moduleScale) + + for (y in scanlineNumbers[index]) { + for (x in 0 until IMAGE_SIZE) { + val uvX = x / IMAGE_SIZED + val uvY = y / IMAGE_SIZED + + val noiseValue = noiseModule.get(uvX, uvY).absoluteValue + val rgb = (noiseValue * 255.0).roundInt() + + pixmap.drawPixel(x, y, (rgb shl 24) or (rgb shl 16) or (rgb shl 8) or 0xFF) + } + } + } + + override fun dispose() { + pixmap.dispose() + texture.dispose() + } +} + +class ThreadParallelTesterController(val host: ThreadParallelTester) : InputAdapter() { + override fun keyDown(keycode: Int): Boolean { + if (keycode == Input.Keys.SPACE && host.generateDone) { + host.regenerate = true + } + return true + } +} + +fun main(args: Array) { + ShaderProgram.pedantic = false + + val appConfig = LwjglApplicationConfiguration() + appConfig.vSyncEnabled = false + appConfig.resizable = false + appConfig.width = 1024 + appConfig.height = 1024 + appConfig.backgroundFPS = 9999 + appConfig.foregroundFPS = 9999 + + appConfig.forceExit = true + + //LwjglApplication(AppLoader(appConfig, ThreadParallelTester()), appConfig) + LwjglApplication(ThreadParallelTester(), appConfig) +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/tests/UITestPad1.kt b/src/net/torvald/terrarum/tests/UITestPad1.kt index f3ad25dde..fcedbe9c6 100644 --- a/src/net/torvald/terrarum/tests/UITestPad1.kt +++ b/src/net/torvald/terrarum/tests/UITestPad1.kt @@ -20,33 +20,33 @@ class UITestPad1 : ScreenAdapter() { val treeStr = """ - File - - New : Ctrl-N - - Open : Ctrl-O + - New + - Open - Open Recent - yaml_example.yaml - Yaml.kt - - Close : Ctrl-W + - Close - Settings - Line Separators - CRLF - CR - LF - Edit - - Undo : Ctrl-Z - - Redo : Shift-Ctrl-Z - - Cut : Ctrl-X - - Copy : Ctrl-C - - Paste : Ctrl-V + - Undo + - Redo + - Cut + - Copy + - Paste - Find - - Find : Ctrl-F - - Replace : Shift-Ctrl-F + - Find + - Replace - Convert Indents - To Spaces - Set Project Indentation - To Tabs - Refactor - Refactor This - - Rename : Shift-Ctrl-R + - Rename - Extract - Variable - Property diff --git a/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt b/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt index b7d7efe0f..1a90c27bd 100644 --- a/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt @@ -13,7 +13,6 @@ import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator import net.torvald.terrarum.modulebasegame.gameworld.WorldTime -import net.torvald.terrarum.utils.JsonWriter import net.torvald.terrarum.worlddrawer.CreateTileAtlas.TILES_IN_X import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import kotlin.math.roundToInt @@ -98,7 +97,7 @@ internal object BlocksDrawer { printdbg(this, "Making terrain textures...") CreateTileAtlas() - JsonWriter.writeToFile(CreateTileAtlas.tags, "${AppLoader.defaultDir}/test_rendertags.json") + //JsonWriter.writeToFile(CreateTileAtlas.tags, "${AppLoader.defaultDir}/test_rendertags.json") // each takes about 60 seconds //printdbg(this, "Writing pixmap as tga: atlas.tga") //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlas.tga"), CreateTileAtlas.atlas, false) diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt index 4a3d8c1d8..0562780f3 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt @@ -11,7 +11,7 @@ import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid -import net.torvald.terrarum.concurrent.ParallelUtils.sliceEvenly +import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.gameactors.ActorWBMovable import net.torvald.terrarum.gameactors.ActorWithBody @@ -400,7 +400,15 @@ object LightmapRenderer { } private fun buildNoopMask() { - fun isShaded(x: Int, y: Int) = BlockCodex[world.getTileFromTerrain(x, y) ?: Block.STONE].isSolid + fun isShaded(x: Int, y: Int) = try { + BlockCodex[world.getTileFromTerrain(x, y)].isSolid + } + catch (e: NullPointerException) { + System.err.println("Invalid block id ${world.getTileFromTerrain(x, y)} from coord ($x, $y)") + e.printStackTrace() + + false + } /* update ordering: clockwise snake