diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/LoadingLog.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/LoadingLog.kt index 8f89a810..b6ef7fae 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/LoadingLog.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/LoadingLog.kt @@ -3,9 +3,14 @@ package ru.dbotthepony.kstarbound import it.unimi.dsi.fastutil.ints.IntIterators import it.unimi.dsi.fastutil.objects.ObjectIterators -interface ILoadingLog : Iterable { +interface ILoadingLog : Iterable { interface ILine { var text: String + val progress: Float + get() = if (maxElements > 0) elements.toFloat() / maxElements.toFloat() else 0f + + var elements: Int + var maxElements: Int } fun line(text: String): ILine @@ -15,11 +20,18 @@ interface ILoadingLog : Iterable { get() = "" set(value) {} + override var elements: Int + get() = 0 + set(value) {} + override var maxElements: Int + get() = 0 + set(value) {} + override fun line(text: String): ILine { return this } - override fun iterator(): Iterator { + override fun iterator(): Iterator { return ObjectIterators.emptyIterator() } } @@ -44,6 +56,10 @@ class LoadingLog : ILoadingLog { lastActivity = System.nanoTime() } + @Volatile + override var elements: Int = 0 + override var maxElements: Int = 0 + init { lastActivity = System.nanoTime() @@ -54,8 +70,8 @@ class LoadingLog : ILoadingLog { } } - override fun iterator(): Iterator { - return object : Iterator { + override fun iterator(): Iterator { + return object : Iterator { private val index = (this@LoadingLog.index - 1) and 127 private val parent = IntIterators.fromTo(0, size) @@ -63,8 +79,8 @@ class LoadingLog : ILoadingLog { return parent.hasNext() } - override fun next(): String { - return lines[(index - parent.nextInt()) and 127]!!.text + override fun next(): ILoadingLog.ILine { + return lines[(index - parent.nextInt()) and 127]!! } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt index 19cedeab..fa8ce1b5 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt @@ -65,15 +65,18 @@ object RecipeRegistry { return listOf(executor.submit(Runnable { val line = log.line("Loading recipes...") val time = System.nanoTime() + line.maxElements = files.size - for (listedFile in files) { + for ((i, listedFile) in files.withIndex()) { try { line.text = ("Loading $listedFile") val json = Starbound.gson.fromJson(listedFile.reader(), JsonElement::class.java) val value = Starbound.gson.fromJson(JsonTreeReader(json), RecipeDefinition::class.java) add(RegistryObject(value, json, listedFile)) + line.elements++ } catch (err: Throwable) { LOGGER.error("Loading recipe definition file $listedFile", err) + line.elements++ } if (Starbound.terminateLoading) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt index 2490de1f..545cf729 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt @@ -63,7 +63,7 @@ object Registries { private fun loadStage( log: ILoadingLog, - loader: ((String) -> Unit) -> Unit, + loader: (ILoadingLog.ILine) -> Unit, name: String, ) { if (Starbound.terminateLoading) @@ -71,15 +71,7 @@ object Registries { val time = System.currentTimeMillis() val line = log.line("Loading $name...".also(LOGGER::info)) - - loader { - if (Starbound.terminateLoading) { - throw InterruptedException("Game is terminating") - } - - line.text = it - } - + loader(line) line.text = ("Loaded $name in ${System.currentTimeMillis() - time}ms".also(LOGGER::info)) } @@ -89,12 +81,16 @@ object Registries { files: List, ) { loadStage(log, loader = { + it.maxElements = files.size + for (listedFile in files) { try { - it("Loading $listedFile") + it.text = "Loading $listedFile" registry.add(listedFile) + it.elements++ } catch (err: Throwable) { LOGGER.error("Loading ${registry.name} definition file $listedFile", err) + it.elements++ } if (Starbound.terminateLoading) { @@ -153,6 +149,7 @@ object Registries { tasks.add(executor.submit { val line = log.line("Loading items '$ext'") val time = System.nanoTime() + line.maxElements = fileList.size for (listedFile in fileList) { try { @@ -160,8 +157,10 @@ object Registries { val json = Starbound.gson.fromJson(listedFile.reader(), JsonObject::class.java) val def: IItemDefinition = AssetPathStack(listedFile.computeDirectory()) { Starbound.gson.fromJson(JsonTreeReader(json), clazz) } items.add(def, json, listedFile) + line.elements++ } catch (err: Throwable) { LOGGER.error("Loading item definition file $listedFile", err) + line.elements++ } if (Starbound.terminateLoading) { @@ -176,17 +175,18 @@ object Registries { return tasks } - private fun loadJsonFunctions(callback: (String) -> Unit, files: Collection) { + private fun loadJsonFunctions(line: ILoadingLog.ILine, files: Collection) { for (listedFile in files) { - callback("Loading $listedFile") + line.text = ("Loading $listedFile") + try { val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true }) for ((k, v) in json.entrySet()) { try { - callback("Loading $k from $listedFile") + line.text = ("Loading $k from $listedFile") val fn = Starbound.gson.fromJson(JsonTreeReader(v), JsonFunction::class.java) - Registries.jsonFunctions.add(fn, v, listedFile, k) + jsonFunctions.add(fn, v, listedFile, k) } catch (err: Exception) { LOGGER.error("Loading json function definition $k from file $listedFile", err) } @@ -201,18 +201,18 @@ object Registries { } } - private fun loadJson2Functions(callback: (String) -> Unit, files: Collection) { + private fun loadJson2Functions(line: ILoadingLog.ILine, files: Collection) { for (listedFile in files) { - callback("Loading $listedFile") + line.text = ("Loading $listedFile") try { val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true }) for ((k, v) in json.entrySet()) { try { - callback("Loading $k from $listedFile") + line.text = ("Loading $k from $listedFile") val fn = Starbound.gson.fromJson(JsonTreeReader(v), Json2Function::class.java) - Registries.json2Functions.add(fn, v, listedFile, k) + json2Functions.add(fn, v, listedFile, k) } catch (err: Throwable) { LOGGER.error("Loading json 2function definition $k from file $listedFile", err) } @@ -227,19 +227,19 @@ object Registries { } } - private fun loadTreasurePools(callback: (String) -> Unit, files: Collection) { + private fun loadTreasurePools(line: ILoadingLog.ILine, files: Collection) { for (listedFile in files) { - callback("Loading $listedFile") + line.text = ("Loading $listedFile") try { val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true }) for ((k, v) in json.entrySet()) { try { - callback("Loading $k from $listedFile") + line.text = ("Loading $k from $listedFile") val result = Starbound.gson.fromJson(JsonTreeReader(v), TreasurePoolDefinition::class.java) result.name = k - Registries.treasurePools.add(result, v, listedFile) + treasurePools.add(result, v, listedFile) } catch (err: Throwable) { LOGGER.error("Loading treasure pool definition $k from file $listedFile", err) } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt index 7d795ee1..30c82a8b 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt @@ -842,7 +842,7 @@ object Starbound : ISBFileLocator { var playerDefinition: PlayerDefinition by WriteOnce() private set - private fun doInitialize(log: ILoadingLog, parallel: Boolean = true) { + private fun doInitialize(log: ILoadingLog, parallel: Boolean) { var time = System.currentTimeMillis() if (archivePaths.isNotEmpty()) { @@ -918,7 +918,7 @@ object Starbound : ISBFileLocator { log.line("Finished loading in ${System.currentTimeMillis() - time}ms") } - fun initializeGame(log: ILoadingLog) { + fun initializeGame(log: ILoadingLog, parallel: Boolean = true) { if (initializing) { throw IllegalStateException("Already initializing!") } @@ -928,7 +928,7 @@ object Starbound : ISBFileLocator { } initializing = true - Thread({ doInitialize(log) }, "Asset Loader").also { + Thread({ doInitialize(log, parallel) }, "Asset Loader").also { it.isDaemon = true it.start() } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt index 0f538795..534dfe86 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt @@ -73,6 +73,7 @@ import java.time.Duration import java.util.* import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.ReentrantLock +import java.util.stream.StreamSupport import kotlin.collections.ArrayList import kotlin.math.absoluteValue import kotlin.math.roundToInt @@ -521,6 +522,20 @@ class StarboundClient : Closeable { builder.draw(GL_LINES) } + inline fun quadColor(color: RGBAColor = RGBAColor.WHITE, lambda: (VertexBuilder) -> Unit) { + val builder = programs.position.builder + + builder.builder.begin(GeometryType.QUADS) + lambda.invoke(builder.builder) + builder.upload() + + programs.position.use() + programs.position.colorMultiplier = color + programs.position.modelMatrix = stack.last() + + builder.draw(GL_TRIANGLES) + } + inline fun lines(color: RGBAColor = RGBAColor.WHITE, lambda: (VertexBuilder) -> Unit) { val builder = programs.position.builder @@ -856,10 +871,20 @@ class StarboundClient : Closeable { stack.push() stack.last().translate(y = viewportHeight.toFloat()) + var shade = 255 for (line in loadingLog) { - val size = font.render(line, alignY = TextAlignY.BOTTOM, scale = 0.4f, color = RGBAColor(shade / 255f, shade / 255f, shade / 255f, alpha)) + if (line.progress in 0.01f ..< 1f) { + quadColor(RGBAColor(0f, shade / 400f * line.progress, 0f, alpha * 0.8f)) { + it.vertex(0f, font.lineHeight * -0.4f) + it.vertex(viewportWidth * line.progress, font.lineHeight * -0.4f) + it.vertex(viewportWidth * line.progress, 0f) + it.vertex(0f, 0f) + } + } + + val size = font.render(line.text, alignY = TextAlignY.BOTTOM, scale = 0.4f, color = RGBAColor(shade / 255f, shade / 255f, shade / 255f, alpha)) stack.last().translate(y = -size.height * 1.2f) if (shade > 120) {