Get rid of loading log since it stalls threads
This commit is contained in:
parent
35fc841037
commit
efadaeb28c
src/main/kotlin/ru/dbotthepony/kstarbound
@ -52,18 +52,13 @@ object GlobalDefaults {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load(log: ILoadingLog, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
fun load(executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
val tasks = ArrayList<ForkJoinTask<*>>()
|
val tasks = ArrayList<ForkJoinTask<*>>()
|
||||||
|
|
||||||
tasks.add(load("/default_actor_movement.config", ::playerMovementParameters, executor))
|
tasks.add(load("/default_actor_movement.config", ::playerMovementParameters, executor))
|
||||||
tasks.add(load("/default_movement.config", ::movementParameters, executor))
|
tasks.add(load("/default_movement.config", ::movementParameters, executor))
|
||||||
tasks.add(load("/client.config", ::clientParameters, executor))
|
tasks.add(load("/client.config", ::clientParameters, executor))
|
||||||
|
|
||||||
return listOf(executor.submit {
|
return tasks
|
||||||
val line = log.line("Loading global defaults...")
|
|
||||||
val time = System.nanoTime()
|
|
||||||
tasks.forEach { it.join() }
|
|
||||||
line.text = "Loaded global defaults in ${((System.nanoTime() - time) / 1_000_000.0).toLong()}ms"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntIterators
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectIterators
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
interface ILoadingLog : Iterable<ILoadingLog.ILine> {
|
|
||||||
interface ILine {
|
|
||||||
var text: String
|
|
||||||
val progress: Float
|
|
||||||
get() = if (maxElements > 0) elements.toFloat() / maxElements.toFloat() else 0f
|
|
||||||
|
|
||||||
val elements: AtomicInteger
|
|
||||||
var maxElements: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
fun line(text: String): ILine
|
|
||||||
|
|
||||||
companion object : ILoadingLog, ILine {
|
|
||||||
override var text: String
|
|
||||||
get() = ""
|
|
||||||
set(value) {}
|
|
||||||
|
|
||||||
override var elements: AtomicInteger = AtomicInteger()
|
|
||||||
|
|
||||||
override var maxElements: Int
|
|
||||||
get() = 0
|
|
||||||
set(value) {}
|
|
||||||
|
|
||||||
override fun line(text: String): ILine {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): Iterator<ILine> {
|
|
||||||
return ObjectIterators.emptyIterator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoadingLog : ILoadingLog {
|
|
||||||
private val lines = arrayOfNulls<Line>(128)
|
|
||||||
@Volatile
|
|
||||||
private var index = 0
|
|
||||||
private val lock = Any()
|
|
||||||
private var size = 0
|
|
||||||
var lastActivity: Long = System.nanoTime()
|
|
||||||
private set
|
|
||||||
|
|
||||||
override fun line(text: String): ILoadingLog.ILine {
|
|
||||||
return Line(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class Line(text: String) : ILoadingLog.ILine {
|
|
||||||
override var text: String = text
|
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
lastActivity = System.nanoTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val elements = AtomicInteger()
|
|
||||||
override var maxElements: Int = 0
|
|
||||||
|
|
||||||
init {
|
|
||||||
lastActivity = System.nanoTime()
|
|
||||||
|
|
||||||
synchronized(lock) {
|
|
||||||
lines[index++ and 127] = this
|
|
||||||
size = (size + 1).coerceAtMost(127)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): Iterator<ILoadingLog.ILine> {
|
|
||||||
return object : Iterator<ILoadingLog.ILine> {
|
|
||||||
private val index = (this@LoadingLog.index - 1) and 127
|
|
||||||
private val parent = IntIterators.fromTo(0, size)
|
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return parent.hasNext()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun next(): ILoadingLog.ILine {
|
|
||||||
return lines[(index - parent.nextInt()) and 127]!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -63,7 +63,7 @@ fun main() {
|
|||||||
|
|
||||||
//Starbound.addPakPath(File("packed.pak"))
|
//Starbound.addPakPath(File("packed.pak"))
|
||||||
|
|
||||||
Starbound.initializeGame(client.loadingLog)
|
Starbound.initializeGame()
|
||||||
|
|
||||||
var ply: PlayerEntity? = null
|
var ply: PlayerEntity? = null
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
|||||||
import ru.dbotthepony.kstarbound.util.KOptional
|
import ru.dbotthepony.kstarbound.util.KOptional
|
||||||
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import java.util.concurrent.ForkJoinPool
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.ForkJoinTask
|
import java.util.concurrent.ForkJoinTask
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
@ -33,63 +34,60 @@ object RecipeRegistry {
|
|||||||
val output2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(output2recipesBacking)
|
val output2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(output2recipesBacking)
|
||||||
val input2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(input2recipesBacking)
|
val input2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(input2recipesBacking)
|
||||||
|
|
||||||
private val lock = ReentrantLock()
|
private val backlog = ConcurrentLinkedQueue<Entry>()
|
||||||
|
|
||||||
fun add(recipe: Entry) {
|
private fun add(recipe: Entry) {
|
||||||
lock.withLock {
|
val value = recipe.value
|
||||||
val value = recipe.value
|
recipesInternal.add(recipe)
|
||||||
recipesInternal.add(recipe)
|
|
||||||
|
|
||||||
for (group in value.groups) {
|
for (group in value.groups) {
|
||||||
group2recipesInternal.computeIfAbsent(group, Object2ObjectFunction { p ->
|
group2recipesInternal.computeIfAbsent(group, Object2ObjectFunction { p ->
|
||||||
ArrayList<Entry>(1).also {
|
|
||||||
group2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
|
||||||
}
|
|
||||||
}).add(recipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
output2recipesInternal.computeIfAbsent(value.output.item.key.left(), Object2ObjectFunction { p ->
|
|
||||||
ArrayList<Entry>(1).also {
|
ArrayList<Entry>(1).also {
|
||||||
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
group2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||||
}
|
}
|
||||||
}).add(recipe)
|
}).add(recipe)
|
||||||
|
}
|
||||||
|
|
||||||
for (input in value.input) {
|
output2recipesInternal.computeIfAbsent(value.output.item.key.left(), Object2ObjectFunction { p ->
|
||||||
input2recipesInternal.computeIfAbsent(input.item.key.left(), Object2ObjectFunction { p ->
|
ArrayList<Entry>(1).also {
|
||||||
ArrayList<Entry>(1).also {
|
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||||
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
|
||||||
}
|
|
||||||
}).add(recipe)
|
|
||||||
}
|
}
|
||||||
|
}).add(recipe)
|
||||||
|
|
||||||
|
for (input in value.input) {
|
||||||
|
input2recipesInternal.computeIfAbsent(input.item.key.left(), Object2ObjectFunction { p ->
|
||||||
|
ArrayList<Entry>(1).also {
|
||||||
|
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||||
|
}
|
||||||
|
}).add(recipe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load(log: ILoadingLog, fileTree: Map<String, List<IStarboundFile>>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
fun finishLoad() {
|
||||||
|
var next = backlog.poll()
|
||||||
|
|
||||||
|
while (next != null) {
|
||||||
|
add(next)
|
||||||
|
next = backlog.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load(fileTree: Map<String, List<IStarboundFile>>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
val files = fileTree["recipe"] ?: return emptyList()
|
val files = fileTree["recipe"] ?: return emptyList()
|
||||||
|
|
||||||
val elements = Starbound.gson.getAdapter(JsonElement::class.java)
|
val elements = Starbound.gson.getAdapter(JsonElement::class.java)
|
||||||
val recipes = Starbound.gson.getAdapter(RecipeDefinition::class.java)
|
val recipes = Starbound.gson.getAdapter(RecipeDefinition::class.java)
|
||||||
|
|
||||||
return listOf(executor.submit {
|
return files.map { listedFile ->
|
||||||
val line = log.line("Loading recipes...")
|
executor.submit {
|
||||||
val time = System.nanoTime()
|
|
||||||
line.maxElements = files.size
|
|
||||||
|
|
||||||
files.batch(executor) { listedFile ->
|
|
||||||
try {
|
try {
|
||||||
line.text = ("Loading $listedFile")
|
|
||||||
val json = elements.read(listedFile.jsonReader())
|
val json = elements.read(listedFile.jsonReader())
|
||||||
val value = recipes.fromJsonTree(json)
|
val value = recipes.fromJsonTree(json)
|
||||||
KOptional.of(Entry(value, json, listedFile))
|
backlog.add(Entry(value, json, listedFile))
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading recipe definition file $listedFile", err)
|
LOGGER.error("Loading recipe definition file $listedFile", err)
|
||||||
KOptional.empty()
|
|
||||||
} finally {
|
|
||||||
line.elements.incrementAndGet()
|
|
||||||
}
|
}
|
||||||
}.forEach { add(it) }
|
}
|
||||||
|
}
|
||||||
line.text = "Loaded recipes in ${((System.nanoTime() - time) / 1_000_000.0).toLong()}ms"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,32 +35,32 @@ import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
|||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
import ru.dbotthepony.kstarbound.util.KOptional
|
|
||||||
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
|
||||||
import java.util.concurrent.ForkJoinPool
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.ForkJoinTask
|
import java.util.concurrent.ForkJoinTask
|
||||||
|
|
||||||
object Registries {
|
object Registries {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
val tiles = Registry<TileDefinition>("tiles")
|
private val registries = ArrayList<Registry<*>>()
|
||||||
val tileModifiers = Registry<MaterialModifier>("tile modifiers")
|
|
||||||
val liquid = Registry<LiquidDefinition>("liquid")
|
val tiles = Registry<TileDefinition>("tiles").also(registries::add)
|
||||||
val species = Registry<Species>("species")
|
val tileModifiers = Registry<MaterialModifier>("tile modifiers").also(registries::add)
|
||||||
val statusEffects = Registry<StatusEffectDefinition>("status effects")
|
val liquid = Registry<LiquidDefinition>("liquid").also(registries::add)
|
||||||
val particles = Registry<ParticleDefinition>("particles")
|
val species = Registry<Species>("species").also(registries::add)
|
||||||
val items = Registry<IItemDefinition>("items")
|
val statusEffects = Registry<StatusEffectDefinition>("status effects").also(registries::add)
|
||||||
val questTemplates = Registry<QuestTemplate>("quest templates")
|
val particles = Registry<ParticleDefinition>("particles").also(registries::add)
|
||||||
val techs = Registry<TechDefinition>("techs")
|
val items = Registry<IItemDefinition>("items").also(registries::add)
|
||||||
val jsonFunctions = Registry<JsonFunction>("json functions")
|
val questTemplates = Registry<QuestTemplate>("quest templates").also(registries::add)
|
||||||
val json2Functions = Registry<Json2Function>("json 2functions")
|
val techs = Registry<TechDefinition>("techs").also(registries::add)
|
||||||
val npcTypes = Registry<NpcTypeDefinition>("npc types")
|
val jsonFunctions = Registry<JsonFunction>("json functions").also(registries::add)
|
||||||
val projectiles = Registry<ProjectileDefinition>("projectiles")
|
val json2Functions = Registry<Json2Function>("json 2functions").also(registries::add)
|
||||||
val tenants = Registry<TenantDefinition>("tenants")
|
val npcTypes = Registry<NpcTypeDefinition>("npc types").also(registries::add)
|
||||||
val treasurePools = Registry<TreasurePoolDefinition>("treasure pools")
|
val projectiles = Registry<ProjectileDefinition>("projectiles").also(registries::add)
|
||||||
val monsterSkills = Registry<MonsterSkillDefinition>("monster skills")
|
val tenants = Registry<TenantDefinition>("tenants").also(registries::add)
|
||||||
val monsterTypes = Registry<MonsterTypeDefinition>("monster types")
|
val treasurePools = Registry<TreasurePoolDefinition>("treasure pools").also(registries::add)
|
||||||
val worldObjects = Registry<ObjectDefinition>("objects")
|
val monsterSkills = Registry<MonsterSkillDefinition>("monster skills").also(registries::add)
|
||||||
|
val monsterTypes = Registry<MonsterTypeDefinition>("monster types").also(registries::add)
|
||||||
|
val worldObjects = Registry<ObjectDefinition>("objects").also(registries::add)
|
||||||
|
|
||||||
private fun <T> key(mapper: (T) -> String): (T) -> Pair<String, Int?> {
|
private fun <T> key(mapper: (T) -> String): (T) -> Pair<String, Int?> {
|
||||||
return { mapper.invoke(it) to null }
|
return { mapper.invoke(it) to null }
|
||||||
@ -95,92 +95,67 @@ object Registries {
|
|||||||
return !any
|
return !any
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadStage(
|
private inline fun <reified T : Any> loadRegistry(
|
||||||
log: ILoadingLog,
|
|
||||||
loader: (ILoadingLog.ILine) -> Unit,
|
|
||||||
name: String,
|
|
||||||
) {
|
|
||||||
if (Starbound.terminateLoading)
|
|
||||||
return
|
|
||||||
|
|
||||||
val time = System.currentTimeMillis()
|
|
||||||
val line = log.line("Loading $name...".also(LOGGER::info))
|
|
||||||
loader(line)
|
|
||||||
line.text = ("Loaded $name in ${System.currentTimeMillis() - time}ms".also(LOGGER::info))
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified T : Any> loadStage(
|
|
||||||
log: ILoadingLog,
|
|
||||||
executor: ForkJoinPool,
|
executor: ForkJoinPool,
|
||||||
registry: Registry<T>,
|
registry: Registry<T>,
|
||||||
files: List<IStarboundFile>,
|
files: List<IStarboundFile>,
|
||||||
noinline keyProvider: (T) -> Pair<String, Int?>,
|
noinline keyProvider: (T) -> Pair<String, Int?>
|
||||||
name: String = registry.name
|
): List<ForkJoinTask<*>> {
|
||||||
) {
|
|
||||||
val adapter = Starbound.gson.getAdapter(T::class.java)
|
val adapter = Starbound.gson.getAdapter(T::class.java)
|
||||||
val elementAdapter = Starbound.gson.getAdapter(JsonElement::class.java)
|
val elementAdapter = Starbound.gson.getAdapter(JsonElement::class.java)
|
||||||
|
|
||||||
loadStage(log, loader = {
|
return files.map { listedFile ->
|
||||||
it.maxElements = files.size
|
executor.submit {
|
||||||
|
|
||||||
files.batch(executor) { listedFile ->
|
|
||||||
try {
|
try {
|
||||||
it.text = "Loading $listedFile"
|
|
||||||
|
|
||||||
AssetPathStack(listedFile.computeDirectory()) {
|
AssetPathStack(listedFile.computeDirectory()) {
|
||||||
val elem = elementAdapter.read(listedFile.jsonReader())
|
val elem = elementAdapter.read(listedFile.jsonReader())
|
||||||
val read = adapter.fromJsonTree(elem)
|
val read = adapter.fromJsonTree(elem)
|
||||||
val keys = keyProvider(read)
|
val keys = keyProvider(read)
|
||||||
|
|
||||||
KOptional.of {
|
registry.add {
|
||||||
try {
|
if (keys.second != null)
|
||||||
if (keys.second != null)
|
registry.add(keys.first, keys.second!!, read, elem, listedFile)
|
||||||
registry.add(keys.first, keys.second!!, read, elem, listedFile)
|
else
|
||||||
else
|
registry.add(keys.first, read, elem, listedFile)
|
||||||
registry.add(keys.first, read, elem, listedFile)
|
|
||||||
} catch (err: Throwable) {
|
|
||||||
LOGGER.error("Loading ${registry.name} definition file $listedFile", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading ${registry.name} definition file $listedFile", err)
|
LOGGER.error("Loading ${registry.name} definition file $listedFile", err)
|
||||||
KOptional.empty()
|
|
||||||
} finally {
|
|
||||||
it.elements.incrementAndGet()
|
|
||||||
}
|
}
|
||||||
}.forEach { it.invoke() }
|
}
|
||||||
}, name)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load(log: ILoadingLog, fileTree: Map<String, List<IStarboundFile>>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
fun finishLoad() {
|
||||||
|
registries.forEach { it.finishLoad() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load(fileTree: Map<String, List<IStarboundFile>>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
val tasks = ArrayList<ForkJoinTask<*>>()
|
val tasks = ArrayList<ForkJoinTask<*>>()
|
||||||
|
|
||||||
tasks.addAll(loadItemDefinitions(log, fileTree, executor))
|
tasks.addAll(loadItemDefinitions(fileTree, executor))
|
||||||
|
|
||||||
tasks.add(executor.submit { loadStage(log, { loadJsonFunctions(it, fileTree["functions"] ?: listOf()) }, "json functions") })
|
tasks.addAll(loadJsonFunctions(fileTree["functions"] ?: listOf(), executor))
|
||||||
tasks.add(executor.submit { loadStage(log, { loadJson2Functions(it, fileTree["2functions"] ?: listOf()) }, "json 2functions") })
|
tasks.addAll(loadJson2Functions(fileTree["2functions"] ?: listOf(), executor))
|
||||||
tasks.add(executor.submit { loadStage(log, { loadTreasurePools(it, fileTree["treasurepools"] ?: listOf()) }, "treasure pools") })
|
tasks.addAll(loadTreasurePools(fileTree["treasurepools"] ?: listOf(), executor))
|
||||||
|
|
||||||
tasks.add(executor.submit { loadStage(log, executor, tiles, fileTree["material"] ?: listOf(), key(TileDefinition::materialName, TileDefinition::materialId)) })
|
tasks.addAll(loadRegistry(executor, tiles, fileTree["material"] ?: listOf(), key(TileDefinition::materialName, TileDefinition::materialId)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, tileModifiers, fileTree["matmod"] ?: listOf(), key(MaterialModifier::modName, MaterialModifier::modId)) })
|
tasks.addAll(loadRegistry(executor, tileModifiers, fileTree["matmod"] ?: listOf(), key(MaterialModifier::modName, MaterialModifier::modId)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, liquid, fileTree["liquid"] ?: listOf(), key(LiquidDefinition::name, LiquidDefinition::liquidId)) })
|
tasks.addAll(loadRegistry(executor, liquid, fileTree["liquid"] ?: listOf(), key(LiquidDefinition::name, LiquidDefinition::liquidId)))
|
||||||
|
|
||||||
tasks.add(executor.submit { loadStage(log, executor, worldObjects, fileTree["object"] ?: listOf(), key(ObjectDefinition::objectName)) })
|
tasks.addAll(loadRegistry(executor, worldObjects, fileTree["object"] ?: listOf(), key(ObjectDefinition::objectName)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, statusEffects, fileTree["statuseffect"] ?: listOf(), key(StatusEffectDefinition::name)) })
|
tasks.addAll(loadRegistry(executor, statusEffects, fileTree["statuseffect"] ?: listOf(), key(StatusEffectDefinition::name)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, species, fileTree["species"] ?: listOf(), key(Species::kind)) })
|
tasks.addAll(loadRegistry(executor, species, fileTree["species"] ?: listOf(), key(Species::kind)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, particles, fileTree["particle"] ?: listOf(), key(ParticleDefinition::kind)) })
|
tasks.addAll(loadRegistry(executor, particles, fileTree["particle"] ?: listOf(), key(ParticleDefinition::kind)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, questTemplates, fileTree["questtemplate"] ?: listOf(), key(QuestTemplate::id)) })
|
tasks.addAll(loadRegistry(executor, questTemplates, fileTree["questtemplate"] ?: listOf(), key(QuestTemplate::id)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, techs, fileTree["tech"] ?: listOf(), key(TechDefinition::name)) })
|
tasks.addAll(loadRegistry(executor, techs, fileTree["tech"] ?: listOf(), key(TechDefinition::name)))
|
||||||
tasks.add(executor.submit { loadStage(log, executor, npcTypes, fileTree["npctype"] ?: listOf(), key(NpcTypeDefinition::type)) })
|
tasks.addAll(loadRegistry(executor, npcTypes, fileTree["npctype"] ?: listOf(), key(NpcTypeDefinition::type)))
|
||||||
// tasks.add(executor.submit { loadStage(log, executor, projectiles, ext2files["projectile"] ?: listOf(), key(ProjectileDefinition::projectileName)) })
|
tasks.addAll(loadRegistry(executor, monsterSkills, fileTree["monsterskill"] ?: listOf(), key(MonsterSkillDefinition::name)))
|
||||||
// tasks.add(executor.submit { loadStage(log, executor, tenants, ext2files["tenant"] ?: listOf(), key(TenantDefinition::name)) })
|
|
||||||
tasks.add(executor.submit { loadStage(log, executor, monsterSkills, fileTree["monsterskill"] ?: listOf(), key(MonsterSkillDefinition::name)) })
|
|
||||||
|
|
||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadItemDefinitions(log: ILoadingLog, files: Map<String, Collection<IStarboundFile>>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
private fun loadItemDefinitions(files: Map<String, Collection<IStarboundFile>>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
val fileMap = mapOf(
|
val fileMap = mapOf(
|
||||||
"item" to ItemDefinition::class.java,
|
"item" to ItemDefinition::class.java,
|
||||||
"currency" to CurrencyItemDefinition::class.java,
|
"currency" to CurrencyItemDefinition::class.java,
|
||||||
@ -201,108 +176,86 @@ object Registries {
|
|||||||
val fileList = files[ext] ?: continue
|
val fileList = files[ext] ?: continue
|
||||||
val adapter = Starbound.gson.getAdapter(clazz)
|
val adapter = Starbound.gson.getAdapter(clazz)
|
||||||
|
|
||||||
tasks.add(executor.submit {
|
for (listedFile in fileList) {
|
||||||
val line = log.line("Loading items '$ext'")
|
tasks.add(executor.submit {
|
||||||
line.maxElements = fileList.size
|
|
||||||
val time = System.nanoTime()
|
|
||||||
|
|
||||||
ParallelPerform(fileList.spliterator(), { listedFile ->
|
|
||||||
try {
|
try {
|
||||||
line.text = "Loading $listedFile"
|
|
||||||
val json = objects.read(listedFile.jsonReader())
|
val json = objects.read(listedFile.jsonReader())
|
||||||
val def = AssetPathStack(listedFile.computeDirectory()) { adapter.fromJsonTree(json) }
|
val def = AssetPathStack(listedFile.computeDirectory()) { adapter.fromJsonTree(json) }
|
||||||
items.add(def.itemName, def, json, listedFile)
|
|
||||||
|
items.add {
|
||||||
|
items.add(def.itemName, def, json, listedFile)
|
||||||
|
}
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading item definition file $listedFile", err)
|
LOGGER.error("Loading item definition file $listedFile", err)
|
||||||
} finally {
|
|
||||||
line.elements.incrementAndGet()
|
|
||||||
}
|
}
|
||||||
}).fork().join()
|
})
|
||||||
|
}
|
||||||
line.text = "Loaded items '$ext' in ${((System.nanoTime() - time) / 1_000_000.0).toLong()}ms"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadJsonFunctions(line: ILoadingLog.ILine, files: Collection<IStarboundFile>) {
|
private fun loadJsonFunctions(files: Collection<IStarboundFile>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
for (listedFile in files) {
|
return files.map { listedFile ->
|
||||||
line.text = ("Loading $listedFile")
|
executor.submit {
|
||||||
|
try {
|
||||||
|
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
|
||||||
|
|
||||||
try {
|
for ((k, v) in json.entrySet()) {
|
||||||
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
|
try {
|
||||||
|
val fn = Starbound.gson.fromJson<JsonFunction>(JsonTreeReader(v), JsonFunction::class.java)
|
||||||
for ((k, v) in json.entrySet()) {
|
jsonFunctions.add(k, fn, v, listedFile)
|
||||||
try {
|
} catch (err: Exception) {
|
||||||
line.text = ("Loading $k from $listedFile")
|
LOGGER.error("Loading json function definition $k from file $listedFile", err)
|
||||||
val fn = Starbound.gson.fromJson<JsonFunction>(JsonTreeReader(v), JsonFunction::class.java)
|
}
|
||||||
jsonFunctions.add(k, fn, v, listedFile)
|
|
||||||
} catch (err: Exception) {
|
|
||||||
LOGGER.error("Loading json function definition $k from file $listedFile", err)
|
|
||||||
}
|
}
|
||||||
|
} catch (err: Exception) {
|
||||||
|
LOGGER.error("Loading json function definition $listedFile", err)
|
||||||
}
|
}
|
||||||
} catch (err: Exception) {
|
|
||||||
LOGGER.error("Loading json function definition $listedFile", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Starbound.terminateLoading) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadJson2Functions(line: ILoadingLog.ILine, files: Collection<IStarboundFile>) {
|
private fun loadJson2Functions(files: Collection<IStarboundFile>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
for (listedFile in files) {
|
return files.map { listedFile ->
|
||||||
line.text = ("Loading $listedFile")
|
executor.submit {
|
||||||
|
try {
|
||||||
|
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
|
||||||
|
|
||||||
try {
|
for ((k, v) in json.entrySet()) {
|
||||||
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
|
try {
|
||||||
|
val fn = Starbound.gson.fromJson<Json2Function>(JsonTreeReader(v), Json2Function::class.java)
|
||||||
for ((k, v) in json.entrySet()) {
|
json2Functions.add(k, fn, v, listedFile)
|
||||||
try {
|
} catch (err: Throwable) {
|
||||||
line.text = ("Loading $k from $listedFile")
|
LOGGER.error("Loading json 2function definition $k from file $listedFile", err)
|
||||||
val fn = Starbound.gson.fromJson<Json2Function>(JsonTreeReader(v), Json2Function::class.java)
|
}
|
||||||
json2Functions.add(k, fn, v, listedFile)
|
|
||||||
} catch (err: Throwable) {
|
|
||||||
LOGGER.error("Loading json 2function definition $k from file $listedFile", err)
|
|
||||||
}
|
}
|
||||||
|
} catch (err: Exception) {
|
||||||
|
LOGGER.error("Loading json 2function definition $listedFile", err)
|
||||||
}
|
}
|
||||||
} catch (err: Exception) {
|
|
||||||
LOGGER.error("Loading json 2function definition $listedFile", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Starbound.terminateLoading) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadTreasurePools(line: ILoadingLog.ILine, files: Collection<IStarboundFile>) {
|
private fun loadTreasurePools(files: Collection<IStarboundFile>, executor: ForkJoinPool): List<ForkJoinTask<*>> {
|
||||||
for (listedFile in files) {
|
return files.map { listedFile ->
|
||||||
line.text = ("Loading $listedFile")
|
executor.submit {
|
||||||
|
try {
|
||||||
|
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
|
||||||
|
|
||||||
try {
|
for ((k, v) in json.entrySet()) {
|
||||||
val json = Starbound.gson.getAdapter(JsonObject::class.java).read(JsonReader(listedFile.reader()).also { it.isLenient = true })
|
try {
|
||||||
|
val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java)
|
||||||
for ((k, v) in json.entrySet()) {
|
result.name = k
|
||||||
try {
|
treasurePools.add(result.name, result, v, listedFile)
|
||||||
line.text = ("Loading $k from $listedFile")
|
} catch (err: Throwable) {
|
||||||
val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java)
|
LOGGER.error("Loading treasure pool definition $k from file $listedFile", err)
|
||||||
result.name = k
|
}
|
||||||
treasurePools.add(result.name, result, v, listedFile)
|
|
||||||
} catch (err: Throwable) {
|
|
||||||
LOGGER.error("Loading treasure pool definition $k from file $listedFile", err)
|
|
||||||
}
|
}
|
||||||
|
} catch (err: Exception) {
|
||||||
|
LOGGER.error("Loading treasure pool definition $listedFile", err)
|
||||||
}
|
}
|
||||||
} catch (err: Exception) {
|
|
||||||
LOGGER.error("Loading treasure pool definition $listedFile", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Starbound.terminateLoading) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import kotlin.collections.contains
|
|||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.concurrent.withLock
|
import kotlin.concurrent.withLock
|
||||||
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
|
||||||
inline fun <reified S : Any> Registry<S>.adapter(): TypeAdapterFactory {
|
inline fun <reified S : Any> Registry<S>.adapter(): TypeAdapterFactory {
|
||||||
return object : TypeAdapterFactory {
|
return object : TypeAdapterFactory {
|
||||||
@ -97,6 +98,21 @@ class Registry<T : Any>(val name: String) {
|
|||||||
private val idsInternal = Int2ObjectOpenHashMap<Impl>()
|
private val idsInternal = Int2ObjectOpenHashMap<Impl>()
|
||||||
private val keyRefs = Object2ObjectOpenHashMap<String, RefImpl>()
|
private val keyRefs = Object2ObjectOpenHashMap<String, RefImpl>()
|
||||||
private val idRefs = Int2ObjectOpenHashMap<RefImpl>()
|
private val idRefs = Int2ObjectOpenHashMap<RefImpl>()
|
||||||
|
private val backlog = ConcurrentLinkedQueue<Runnable>()
|
||||||
|
|
||||||
|
// it is much cheaper to queue registry additions rather than locking during high congestion
|
||||||
|
fun add(task: Runnable) {
|
||||||
|
backlog.add(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finishLoad() {
|
||||||
|
var next = backlog.poll()
|
||||||
|
|
||||||
|
while (next != null) {
|
||||||
|
next.run()
|
||||||
|
next = backlog.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val lock = ReentrantLock()
|
private val lock = ReentrantLock()
|
||||||
|
|
||||||
|
@ -285,6 +285,8 @@ object Starbound : ISBFileLocator {
|
|||||||
private set
|
private set
|
||||||
var bootstrapped = false
|
var bootstrapped = false
|
||||||
private set
|
private set
|
||||||
|
var loadingProgress = 0.0
|
||||||
|
private set
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
var terminateLoading = false
|
var terminateLoading = false
|
||||||
@ -395,7 +397,7 @@ object Starbound : ISBFileLocator {
|
|||||||
checkMailbox()
|
checkMailbox()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doInitialize(log: ILoadingLog, parallel: Boolean) {
|
private fun doInitialize(parallel: Boolean) {
|
||||||
if (!initializing && !initialized) {
|
if (!initializing && !initialized) {
|
||||||
initializing = true
|
initializing = true
|
||||||
} else {
|
} else {
|
||||||
@ -404,8 +406,6 @@ object Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
doBootstrap()
|
doBootstrap()
|
||||||
|
|
||||||
val time = System.currentTimeMillis()
|
|
||||||
|
|
||||||
val ext2files = fileSystems.parallelStream()
|
val ext2files = fileSystems.parallelStream()
|
||||||
.flatMap { it.explore() }
|
.flatMap { it.explore() }
|
||||||
.filter { it.isFile }
|
.filter { it.isFile }
|
||||||
@ -445,32 +445,37 @@ object Starbound : ISBFileLocator {
|
|||||||
val tasks = ArrayList<ForkJoinTask<*>>()
|
val tasks = ArrayList<ForkJoinTask<*>>()
|
||||||
val pool = if (parallel) ForkJoinPool.commonPool() else ForkJoinPool(1)
|
val pool = if (parallel) ForkJoinPool.commonPool() else ForkJoinPool(1)
|
||||||
|
|
||||||
tasks.addAll(Registries.load(log, ext2files, pool))
|
tasks.addAll(Registries.load(ext2files, pool))
|
||||||
tasks.addAll(RecipeRegistry.load(log, ext2files, pool))
|
tasks.addAll(RecipeRegistry.load(ext2files, pool))
|
||||||
tasks.addAll(GlobalDefaults.load(log, pool))
|
tasks.addAll(GlobalDefaults.load(pool))
|
||||||
|
|
||||||
tasks.forEach { it.join() }
|
val total = tasks.size.toDouble()
|
||||||
|
|
||||||
|
while (tasks.isNotEmpty()) {
|
||||||
|
tasks.removeIf { it.isDone }
|
||||||
|
checkMailbox()
|
||||||
|
loadingProgress = (total - tasks.size) / total
|
||||||
|
LockSupport.parkNanos(5_000_000L)
|
||||||
|
}
|
||||||
|
|
||||||
if (!parallel)
|
if (!parallel)
|
||||||
pool.shutdown()
|
pool.shutdown()
|
||||||
|
|
||||||
|
Registries.finishLoad()
|
||||||
|
RecipeRegistry.finishLoad()
|
||||||
|
|
||||||
Registries.validate()
|
Registries.validate()
|
||||||
|
|
||||||
initializing = false
|
initializing = false
|
||||||
initialized = true
|
initialized = true
|
||||||
log.line("Finished loading in ${System.currentTimeMillis() - time}ms")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializeGame(log: ILoadingLog, parallel: Boolean = true) {
|
fun initializeGame(parallel: Boolean = true) {
|
||||||
mailbox.submit {
|
mailbox.submit { doInitialize(parallel) }
|
||||||
doInitialize(log, parallel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bootstrapGame() {
|
fun bootstrapGame() {
|
||||||
mailbox.submit {
|
mailbox.submit { doBootstrap() }
|
||||||
doBootstrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkMailbox() {
|
private fun checkMailbox() {
|
||||||
|
@ -13,7 +13,6 @@ import org.lwjgl.opengl.GL45.*
|
|||||||
import org.lwjgl.opengl.GLCapabilities
|
import org.lwjgl.opengl.GLCapabilities
|
||||||
import org.lwjgl.system.MemoryStack
|
import org.lwjgl.system.MemoryStack
|
||||||
import org.lwjgl.system.MemoryUtil
|
import org.lwjgl.system.MemoryUtil
|
||||||
import ru.dbotthepony.kstarbound.LoadingLog
|
|
||||||
import ru.dbotthepony.kstarbound.util.MailboxExecutorService
|
import ru.dbotthepony.kstarbound.util.MailboxExecutorService
|
||||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT
|
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT
|
||||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||||
@ -166,8 +165,6 @@ class StarboundClient : Closeable {
|
|||||||
private val onViewportChanged = ArrayList<(width: Int, height: Int) -> Unit>()
|
private val onViewportChanged = ArrayList<(width: Int, height: Int) -> Unit>()
|
||||||
private val terminateCallbacks = ArrayList<() -> Unit>()
|
private val terminateCallbacks = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
val loadingLog = LoadingLog()
|
|
||||||
|
|
||||||
private val openglCleanQueue = ReferenceQueue<Any>()
|
private val openglCleanQueue = ReferenceQueue<Any>()
|
||||||
private var openglCleanQueueHead: CleanRef? = null
|
private var openglCleanQueueHead: CleanRef? = null
|
||||||
|
|
||||||
@ -214,7 +211,6 @@ class StarboundClient : Closeable {
|
|||||||
|
|
||||||
window = GLFW.glfwCreateWindow(800, 600, "KStarbound", MemoryUtil.NULL, MemoryUtil.NULL)
|
window = GLFW.glfwCreateWindow(800, 600, "KStarbound", MemoryUtil.NULL, MemoryUtil.NULL)
|
||||||
require(window != MemoryUtil.NULL) { "Unable to create GLFW window" }
|
require(window != MemoryUtil.NULL) { "Unable to create GLFW window" }
|
||||||
loadingLog.line("Created GLFW window")
|
|
||||||
|
|
||||||
input.installCallback(window)
|
input.installCallback(window)
|
||||||
|
|
||||||
@ -269,7 +265,6 @@ class StarboundClient : Closeable {
|
|||||||
GLFW.glfwSwapInterval(0)
|
GLFW.glfwSwapInterval(0)
|
||||||
|
|
||||||
GLFW.glfwShowWindow(window)
|
GLFW.glfwShowWindow(window)
|
||||||
loadingLog.line("Initialized GLFW window")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val maxTextureBlocks = glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS)
|
val maxTextureBlocks = glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS)
|
||||||
@ -761,37 +756,13 @@ class StarboundClient : Closeable {
|
|||||||
private val dotTime = 4
|
private val dotTime = 4
|
||||||
private var dotInc = 1
|
private var dotInc = 1
|
||||||
|
|
||||||
private fun renderLoadingText() {
|
private fun drawPerformanceBasic(onlyMemory: Boolean) {
|
||||||
var alpha = 1f
|
val runtime = Runtime.getRuntime()
|
||||||
|
|
||||||
if (System.nanoTime() - loadingLog.lastActivity >= 3_000_000_000L) {
|
if (!onlyMemory) font.render("Latency: ${(averageRenderWait * 1_00000.0).toInt() / 100f}ms", scale = 0.4f)
|
||||||
alpha = 1f - (System.nanoTime() - loadingLog.lastActivity - 3_000_000_000L) / 1_000_000_000f
|
if (!onlyMemory) font.render("Frame: ${(averageRenderTime * 1_00000.0).toInt() / 100f}ms", y = font.lineHeight * 0.6f, scale = 0.4f)
|
||||||
}
|
font.render("JVM Heap: ${formatBytesShort(runtime.totalMemory() - runtime.freeMemory())}", y = font.lineHeight * 1.2f, scale = 0.4f)
|
||||||
|
if (!onlyMemory) font.render("OGL C: $openglObjectsCreated D: $openglObjectsCleaned A: ${openglObjectsCreated - openglObjectsCleaned}", y = font.lineHeight * 1.8f, scale = 0.4f)
|
||||||
stack.push()
|
|
||||||
stack.last().translate(y = viewportHeight.toFloat())
|
|
||||||
|
|
||||||
var shade = 255
|
|
||||||
|
|
||||||
for (line in loadingLog) {
|
|
||||||
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) {
|
|
||||||
shade -= 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.pop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renderFrame(): Boolean {
|
fun renderFrame(): Boolean {
|
||||||
@ -855,45 +826,50 @@ class StarboundClient : Closeable {
|
|||||||
|
|
||||||
program.colorMultiplier = RGBAColor.WHITE
|
program.colorMultiplier = RGBAColor.WHITE
|
||||||
|
|
||||||
if (!fontInitialized) {
|
builder.builder.begin(GeometryType.QUADS)
|
||||||
builder.builder.begin(GeometryType.QUADS)
|
|
||||||
|
|
||||||
dotsIndex += dotInc
|
dotsIndex += dotInc
|
||||||
|
|
||||||
if (dotsIndex < 0) {
|
if (dotsIndex < 0) {
|
||||||
dotsIndex = 1
|
dotsIndex = 1
|
||||||
dotInc = 1
|
dotInc = 1
|
||||||
} else if (dotsIndex > dotTime * 3) {
|
} else if (dotsIndex > dotTime * 3) {
|
||||||
dotsIndex = dotTime * 3 - 1
|
dotsIndex = dotTime * 3 - 1
|
||||||
dotInc = -1
|
dotInc = -1
|
||||||
}
|
|
||||||
|
|
||||||
val a = if (dotsIndex / dotTime == 0) RGBAColor.SLATE_GRAY else RGBAColor.WHITE
|
|
||||||
val b = if (dotsIndex / dotTime == 1) RGBAColor.SLATE_GRAY else RGBAColor.WHITE
|
|
||||||
val c = if (dotsIndex / dotTime == 2) RGBAColor.SLATE_GRAY else RGBAColor.WHITE
|
|
||||||
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f - size - size * 4f, viewportHeight * 0.5f - size).color(a)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f + size - size * 4f, viewportHeight * 0.5f - size).color(a)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f + size - size * 4f, viewportHeight * 0.5f + size).color(a)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f - size - size * 4f, viewportHeight * 0.5f + size).color(a)
|
|
||||||
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f - size, viewportHeight * 0.5f - size).color(b)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f + size, viewportHeight * 0.5f - size).color(b)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f + size, viewportHeight * 0.5f + size).color(b)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f - size, viewportHeight * 0.5f + size).color(b)
|
|
||||||
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f - size + size * 4f, viewportHeight * 0.5f - size).color(c)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f + size + size * 4f, viewportHeight * 0.5f - size).color(c)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f + size + size * 4f, viewportHeight * 0.5f + size).color(c)
|
|
||||||
builder.builder.vertex(viewportWidth * 0.5f - size + size * 4f, viewportHeight * 0.5f + size).color(c)
|
|
||||||
|
|
||||||
program.use()
|
|
||||||
builder.upload()
|
|
||||||
builder.draw()
|
|
||||||
} else {
|
|
||||||
renderLoadingText()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val a = if (dotsIndex / dotTime == 0) RGBAColor.SLATE_GRAY else RGBAColor.WHITE
|
||||||
|
val b = if (dotsIndex / dotTime == 1) RGBAColor.SLATE_GRAY else RGBAColor.WHITE
|
||||||
|
val c = if (dotsIndex / dotTime == 2) RGBAColor.SLATE_GRAY else RGBAColor.WHITE
|
||||||
|
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f - size - size * 4f, viewportHeight * 0.5f - size).color(a)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f + size - size * 4f, viewportHeight * 0.5f - size).color(a)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f + size - size * 4f, viewportHeight * 0.5f + size).color(a)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f - size - size * 4f, viewportHeight * 0.5f + size).color(a)
|
||||||
|
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f - size, viewportHeight * 0.5f - size).color(b)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f + size, viewportHeight * 0.5f - size).color(b)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f + size, viewportHeight * 0.5f + size).color(b)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f - size, viewportHeight * 0.5f + size).color(b)
|
||||||
|
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f - size + size * 4f, viewportHeight * 0.5f - size).color(c)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f + size + size * 4f, viewportHeight * 0.5f - size).color(c)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f + size + size * 4f, viewportHeight * 0.5f + size).color(c)
|
||||||
|
builder.builder.vertex(viewportWidth * 0.5f - size + size * 4f, viewportHeight * 0.5f + size).color(c)
|
||||||
|
|
||||||
|
builder.builder.vertex(0f, viewportHeight - 20f).color(RGBAColor.GREEN)
|
||||||
|
builder.builder.vertex(viewportWidth * Starbound.loadingProgress.toFloat(), viewportHeight - 20f).color(RGBAColor.GREEN)
|
||||||
|
builder.builder.vertex(viewportWidth * Starbound.loadingProgress.toFloat(), viewportHeight.toFloat()).color(RGBAColor.GREEN)
|
||||||
|
builder.builder.vertex(0f, viewportHeight.toFloat()).color(RGBAColor.GREEN)
|
||||||
|
|
||||||
|
if (fontInitialized) {
|
||||||
|
drawPerformanceBasic(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
program.use()
|
||||||
|
builder.upload()
|
||||||
|
builder.draw()
|
||||||
|
|
||||||
GLFW.glfwSwapBuffers(window)
|
GLFW.glfwSwapBuffers(window)
|
||||||
GLFW.glfwPollEvents()
|
GLFW.glfwPollEvents()
|
||||||
|
|
||||||
@ -993,22 +969,13 @@ class StarboundClient : Closeable {
|
|||||||
uberShaderPrograms.forEachValid { it.viewMatrix = viewportMatrixScreen }
|
uberShaderPrograms.forEachValid { it.viewMatrix = viewportMatrixScreen }
|
||||||
fontShaderPrograms.forEachValid { it.viewMatrix = viewportMatrixScreen }
|
fontShaderPrograms.forEachValid { it.viewMatrix = viewportMatrixScreen }
|
||||||
|
|
||||||
if (System.nanoTime() - loadingLog.lastActivity <= 4_000_000_000L) {
|
|
||||||
renderLoadingText()
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.clear(Matrix3f.identity())
|
stack.clear(Matrix3f.identity())
|
||||||
|
|
||||||
for (fn in onDrawGUI) {
|
for (fn in onDrawGUI) {
|
||||||
fn.invoke()
|
fn.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
val runtime = Runtime.getRuntime()
|
drawPerformanceBasic(false)
|
||||||
|
|
||||||
font.render("Latency: ${(averageRenderWait * 1_00000.0).toInt() / 100f}ms", scale = 0.4f)
|
|
||||||
font.render("Frame: ${(averageRenderTime * 1_00000.0).toInt() / 100f}ms", y = font.lineHeight * 0.6f, scale = 0.4f)
|
|
||||||
font.render("JVM Heap: ${formatBytesShort(runtime.totalMemory() - runtime.freeMemory())}", y = font.lineHeight * 1.2f, scale = 0.4f)
|
|
||||||
font.render("OGL C: $openglObjectsCreated D: $openglObjectsCleaned A: ${openglObjectsCreated - openglObjectsCleaned}", y = font.lineHeight * 1.8f, scale = 0.4f)
|
|
||||||
|
|
||||||
GLFW.glfwSwapBuffers(window)
|
GLFW.glfwSwapBuffers(window)
|
||||||
GLFW.glfwPollEvents()
|
GLFW.glfwPollEvents()
|
||||||
|
Loading…
Reference in New Issue
Block a user