Loading log progress bars

This commit is contained in:
DBotThePony 2023-09-29 23:34:15 +07:00
parent e96d668f26
commit 302aa9b83a
Signed by: DBot
GPG Key ID: DCC23B5715498507
5 changed files with 78 additions and 34 deletions

View File

@ -3,9 +3,14 @@ package ru.dbotthepony.kstarbound
import it.unimi.dsi.fastutil.ints.IntIterators import it.unimi.dsi.fastutil.ints.IntIterators
import it.unimi.dsi.fastutil.objects.ObjectIterators import it.unimi.dsi.fastutil.objects.ObjectIterators
interface ILoadingLog : Iterable<String> { interface ILoadingLog : Iterable<ILoadingLog.ILine> {
interface ILine { interface ILine {
var text: String 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 fun line(text: String): ILine
@ -15,11 +20,18 @@ interface ILoadingLog : Iterable<String> {
get() = "" get() = ""
set(value) {} set(value) {}
override var elements: Int
get() = 0
set(value) {}
override var maxElements: Int
get() = 0
set(value) {}
override fun line(text: String): ILine { override fun line(text: String): ILine {
return this return this
} }
override fun iterator(): Iterator<String> { override fun iterator(): Iterator<ILine> {
return ObjectIterators.emptyIterator() return ObjectIterators.emptyIterator()
} }
} }
@ -44,6 +56,10 @@ class LoadingLog : ILoadingLog {
lastActivity = System.nanoTime() lastActivity = System.nanoTime()
} }
@Volatile
override var elements: Int = 0
override var maxElements: Int = 0
init { init {
lastActivity = System.nanoTime() lastActivity = System.nanoTime()
@ -54,8 +70,8 @@ class LoadingLog : ILoadingLog {
} }
} }
override fun iterator(): Iterator<String> { override fun iterator(): Iterator<ILoadingLog.ILine> {
return object : Iterator<String> { return object : Iterator<ILoadingLog.ILine> {
private val index = (this@LoadingLog.index - 1) and 127 private val index = (this@LoadingLog.index - 1) and 127
private val parent = IntIterators.fromTo(0, size) private val parent = IntIterators.fromTo(0, size)
@ -63,8 +79,8 @@ class LoadingLog : ILoadingLog {
return parent.hasNext() return parent.hasNext()
} }
override fun next(): String { override fun next(): ILoadingLog.ILine {
return lines[(index - parent.nextInt()) and 127]!!.text return lines[(index - parent.nextInt()) and 127]!!
} }
} }
} }

View File

@ -65,15 +65,18 @@ object RecipeRegistry {
return listOf(executor.submit(Runnable { return listOf(executor.submit(Runnable {
val line = log.line("Loading recipes...") val line = log.line("Loading recipes...")
val time = System.nanoTime() val time = System.nanoTime()
line.maxElements = files.size
for (listedFile in files) { for ((i, listedFile) in files.withIndex()) {
try { try {
line.text = ("Loading $listedFile") line.text = ("Loading $listedFile")
val json = Starbound.gson.fromJson(listedFile.reader(), JsonElement::class.java) val json = Starbound.gson.fromJson(listedFile.reader(), JsonElement::class.java)
val value = Starbound.gson.fromJson<RecipeDefinition>(JsonTreeReader(json), RecipeDefinition::class.java) val value = Starbound.gson.fromJson<RecipeDefinition>(JsonTreeReader(json), RecipeDefinition::class.java)
add(RegistryObject(value, json, listedFile)) add(RegistryObject(value, json, listedFile))
line.elements++
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Loading recipe definition file $listedFile", err) LOGGER.error("Loading recipe definition file $listedFile", err)
line.elements++
} }
if (Starbound.terminateLoading) { if (Starbound.terminateLoading) {

View File

@ -63,7 +63,7 @@ object Registries {
private fun loadStage( private fun loadStage(
log: ILoadingLog, log: ILoadingLog,
loader: ((String) -> Unit) -> Unit, loader: (ILoadingLog.ILine) -> Unit,
name: String, name: String,
) { ) {
if (Starbound.terminateLoading) if (Starbound.terminateLoading)
@ -71,15 +71,7 @@ object Registries {
val time = System.currentTimeMillis() val time = System.currentTimeMillis()
val line = log.line("Loading $name...".also(LOGGER::info)) val line = log.line("Loading $name...".also(LOGGER::info))
loader(line)
loader {
if (Starbound.terminateLoading) {
throw InterruptedException("Game is terminating")
}
line.text = it
}
line.text = ("Loaded $name in ${System.currentTimeMillis() - time}ms".also(LOGGER::info)) line.text = ("Loaded $name in ${System.currentTimeMillis() - time}ms".also(LOGGER::info))
} }
@ -89,12 +81,16 @@ object Registries {
files: List<IStarboundFile>, files: List<IStarboundFile>,
) { ) {
loadStage(log, loader = { loadStage(log, loader = {
it.maxElements = files.size
for (listedFile in files) { for (listedFile in files) {
try { try {
it("Loading $listedFile") it.text = "Loading $listedFile"
registry.add(listedFile) registry.add(listedFile)
it.elements++
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Loading ${registry.name} definition file $listedFile", err) LOGGER.error("Loading ${registry.name} definition file $listedFile", err)
it.elements++
} }
if (Starbound.terminateLoading) { if (Starbound.terminateLoading) {
@ -153,6 +149,7 @@ object Registries {
tasks.add(executor.submit { tasks.add(executor.submit {
val line = log.line("Loading items '$ext'") val line = log.line("Loading items '$ext'")
val time = System.nanoTime() val time = System.nanoTime()
line.maxElements = fileList.size
for (listedFile in fileList) { for (listedFile in fileList) {
try { try {
@ -160,8 +157,10 @@ object Registries {
val json = Starbound.gson.fromJson(listedFile.reader(), JsonObject::class.java) val json = Starbound.gson.fromJson(listedFile.reader(), JsonObject::class.java)
val def: IItemDefinition = AssetPathStack(listedFile.computeDirectory()) { Starbound.gson.fromJson(JsonTreeReader(json), clazz) } val def: IItemDefinition = AssetPathStack(listedFile.computeDirectory()) { Starbound.gson.fromJson(JsonTreeReader(json), clazz) }
items.add(def, json, listedFile) items.add(def, json, listedFile)
line.elements++
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Loading item definition file $listedFile", err) LOGGER.error("Loading item definition file $listedFile", err)
line.elements++
} }
if (Starbound.terminateLoading) { if (Starbound.terminateLoading) {
@ -176,17 +175,18 @@ object Registries {
return tasks return tasks
} }
private fun loadJsonFunctions(callback: (String) -> Unit, files: Collection<IStarboundFile>) { private fun loadJsonFunctions(line: ILoadingLog.ILine, files: Collection<IStarboundFile>) {
for (listedFile in files) { for (listedFile in files) {
callback("Loading $listedFile") line.text = ("Loading $listedFile")
try { try {
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true }) val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
for ((k, v) in json.entrySet()) { for ((k, v) in json.entrySet()) {
try { try {
callback("Loading $k from $listedFile") line.text = ("Loading $k from $listedFile")
val fn = Starbound.gson.fromJson<JsonFunction>(JsonTreeReader(v), JsonFunction::class.java) val fn = Starbound.gson.fromJson<JsonFunction>(JsonTreeReader(v), JsonFunction::class.java)
Registries.jsonFunctions.add(fn, v, listedFile, k) jsonFunctions.add(fn, v, listedFile, k)
} catch (err: Exception) { } catch (err: Exception) {
LOGGER.error("Loading json function definition $k from file $listedFile", err) 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<IStarboundFile>) { private fun loadJson2Functions(line: ILoadingLog.ILine, files: Collection<IStarboundFile>) {
for (listedFile in files) { for (listedFile in files) {
callback("Loading $listedFile") line.text = ("Loading $listedFile")
try { try {
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true }) val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
for ((k, v) in json.entrySet()) { for ((k, v) in json.entrySet()) {
try { try {
callback("Loading $k from $listedFile") line.text = ("Loading $k from $listedFile")
val fn = Starbound.gson.fromJson<Json2Function>(JsonTreeReader(v), Json2Function::class.java) val fn = Starbound.gson.fromJson<Json2Function>(JsonTreeReader(v), Json2Function::class.java)
Registries.json2Functions.add(fn, v, listedFile, k) json2Functions.add(fn, v, listedFile, k)
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Loading json 2function definition $k from file $listedFile", err) 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<IStarboundFile>) { private fun loadTreasurePools(line: ILoadingLog.ILine, files: Collection<IStarboundFile>) {
for (listedFile in files) { for (listedFile in files) {
callback("Loading $listedFile") line.text = ("Loading $listedFile")
try { try {
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true }) val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
for ((k, v) in json.entrySet()) { for ((k, v) in json.entrySet()) {
try { try {
callback("Loading $k from $listedFile") line.text = ("Loading $k from $listedFile")
val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java) val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java)
result.name = k result.name = k
Registries.treasurePools.add(result, v, listedFile) treasurePools.add(result, v, listedFile)
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Loading treasure pool definition $k from file $listedFile", err) LOGGER.error("Loading treasure pool definition $k from file $listedFile", err)
} }

View File

@ -842,7 +842,7 @@ object Starbound : ISBFileLocator {
var playerDefinition: PlayerDefinition by WriteOnce() var playerDefinition: PlayerDefinition by WriteOnce()
private set private set
private fun doInitialize(log: ILoadingLog, parallel: Boolean = true) { private fun doInitialize(log: ILoadingLog, parallel: Boolean) {
var time = System.currentTimeMillis() var time = System.currentTimeMillis()
if (archivePaths.isNotEmpty()) { if (archivePaths.isNotEmpty()) {
@ -918,7 +918,7 @@ object Starbound : ISBFileLocator {
log.line("Finished loading in ${System.currentTimeMillis() - time}ms") log.line("Finished loading in ${System.currentTimeMillis() - time}ms")
} }
fun initializeGame(log: ILoadingLog) { fun initializeGame(log: ILoadingLog, parallel: Boolean = true) {
if (initializing) { if (initializing) {
throw IllegalStateException("Already initializing!") throw IllegalStateException("Already initializing!")
} }
@ -928,7 +928,7 @@ object Starbound : ISBFileLocator {
} }
initializing = true initializing = true
Thread({ doInitialize(log) }, "Asset Loader").also { Thread({ doInitialize(log, parallel) }, "Asset Loader").also {
it.isDaemon = true it.isDaemon = true
it.start() it.start()
} }

View File

@ -73,6 +73,7 @@ import java.time.Duration
import java.util.* import java.util.*
import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.LockSupport
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import java.util.stream.StreamSupport
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -521,6 +522,20 @@ class StarboundClient : Closeable {
builder.draw(GL_LINES) 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) { inline fun lines(color: RGBAColor = RGBAColor.WHITE, lambda: (VertexBuilder) -> Unit) {
val builder = programs.position.builder val builder = programs.position.builder
@ -856,10 +871,20 @@ class StarboundClient : Closeable {
stack.push() stack.push()
stack.last().translate(y = viewportHeight.toFloat()) stack.last().translate(y = viewportHeight.toFloat())
var shade = 255 var shade = 255
for (line in loadingLog) { 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) stack.last().translate(y = -size.height * 1.2f)
if (shade > 120) { if (shade > 120) {