Избавляемся от ненужного дублирования кода

This commit is contained in:
DBotThePony 2023-02-05 11:04:29 +07:00
parent d7c16697be
commit 8042cd0a22
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -7,6 +7,7 @@ import com.google.gson.internal.bind.TypeAdapters
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.api.IStarboundFile
@ -47,6 +48,11 @@ import ru.dbotthepony.kstarbound.util.WriteOnce
import java.io.*
import java.text.DateFormat
import java.util.*
import java.util.function.BiConsumer
import java.util.function.BinaryOperator
import java.util.function.Function
import java.util.function.Supplier
import java.util.stream.Collector
import kotlin.collections.ArrayList
const val METRES_IN_STARBOUND_UNIT = 0.5
@ -273,6 +279,9 @@ object Starbound {
loader: ((String) -> Unit) -> Unit,
name: String,
) {
if (terminateLoading)
return
val time = System.currentTimeMillis()
callback(false, false, "Loading $name...")
LOGGER.info("Loading $name...")
@ -289,6 +298,150 @@ object Starbound {
LOGGER.info("Loaded $name in ${System.currentTimeMillis() - time}ms")
}
private fun <T, K : Any> loadStage(
callback: (Boolean, Boolean, String) -> Unit,
clazz: Class<T>,
getKey: (T) -> K,
put: (K, T) -> T?,
files: List<IStarboundFile>,
name: String,
) {
loadStage(callback, loader = {
for (listedFile in files) {
try {
it("Loading $listedFile")
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), clazz) }
val key = getKey.invoke(def)
check(put.invoke(key, def) == null) { "Already has $name with name $key loaded!" }
} catch (err: Throwable) {
LOGGER.error("Loading $name definition file $listedFile", err)
}
if (terminateLoading) {
break
}
}
}, name)
}
private fun <T, K0 : Any, K1 : Any> loadStage(
callback: (Boolean, Boolean, String) -> Unit,
clazz: Class<T>,
getKey0: (T) -> K0,
put0: (K0, T) -> T?,
getKey1: (T) -> K1,
put1: (K1, T) -> T?,
files: List<IStarboundFile>,
name: String,
) {
loadStage(callback, loader = {
for (listedFile in files) {
try {
it("Loading $listedFile")
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), clazz) }
val key0 = getKey0.invoke(def)
val key1 = getKey1.invoke(def)
check(put0.invoke(key0, def) == null) { "Already has $name with name $key0 loaded!" }
check(put1.invoke(key1, def) == null) { "Already has $name with ID $key1 loaded!" }
} catch (err: Throwable) {
LOGGER.error("Loading $name definition file $listedFile", err)
}
if (terminateLoading) {
break
}
}
}, name)
}
private fun doInitialize(callback: (finished: Boolean, replaceStatus: Boolean, status: String) -> Unit) {
var time = System.currentTimeMillis()
if (archivePaths.isNotEmpty()) {
callback(false, false, "Reading pak archives...".also(LOGGER::info))
for (path in archivePaths) {
callback(false, false, "Reading ${path.name}...".also(LOGGER::info))
addPak(StarboundPak(path) { _, status ->
callback(false, true, "${path.name}: $status")
})
}
}
callback(false, false, "Finished reading pak archives in ${System.currentTimeMillis() - time}ms".also(LOGGER::info))
time = System.currentTimeMillis()
callback(false, false, "Building file index...".also(LOGGER::info))
val ext2files = fileSystems.parallelStream()
.flatMap { it.explore() }
.filter { it.isFile }
.collect(object :
Collector<IStarboundFile, Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>,
Map<String, List<IStarboundFile>>>,
Supplier<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>>,
BiConsumer<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>, IStarboundFile>,
BinaryOperator<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>>
{
override fun accept(t: Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>, u: IStarboundFile) {
t.computeIfAbsent(u.name.substringAfterLast('.'), Object2ObjectFunction { ArrayList() }).add(u)
}
override fun get(): Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>> {
return Object2ObjectOpenHashMap()
}
override fun supplier(): Supplier<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>> {
return this
}
override fun accumulator(): BiConsumer<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>, IStarboundFile> {
return this
}
override fun apply(
t: Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>,
u: Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>
): Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>> {
t.putAll(u)
return t
}
override fun combiner(): BinaryOperator<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>> {
return this
}
override fun finisher(): Function<Object2ObjectOpenHashMap<String, ArrayList<IStarboundFile>>, Map<String, List<IStarboundFile>>> {
return Function { it }
}
override fun characteristics(): Set<Collector.Characteristics> {
return setOf(Collector.Characteristics.IDENTITY_FINISH, Collector.Characteristics.UNORDERED)
}
})
callback(false, false, "Finished building file index in ${System.currentTimeMillis() - time}ms".also(LOGGER::info))
loadStage(callback, this::loadFunctions, "functions")
loadStage(callback, this::loadProjectiles, "projectiles")
loadStage(callback, this::loadParallax, "parallax definitions")
loadStage(callback, this::loadItemDefinitions, "item definitions")
loadStage(callback, TileDefinition::class.java, TileDefinition::materialName, tiles::put, TileDefinition::materialId, tilesByMaterialID::put, ext2files["material"] ?: listOf(), "materials")
loadStage(callback, MaterialModifier::class.java, MaterialModifier::modName, tileModifiers::put, MaterialModifier::modId, tileModifiersByID::put, ext2files["matmod"] ?: listOf(), "material modifier definitions")
loadStage(callback, LiquidDefinition::class.java, LiquidDefinition::name, liquid::put, LiquidDefinition::liquidId, liquidByID::put, ext2files["liquid"] ?: listOf(), "liquid definitions")
loadStage(callback, StatusEffectDefinition::class.java, StatusEffectDefinition::name, statusEffects::put, ext2files["statuseffect"] ?: listOf(), "status effects")
loadStage(callback, Species::class.java, Species::kind, species::put, ext2files["species"] ?: listOf(), "species")
pathStack.block("/") {
playerDefinition = GSON.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java)
}
initializing = false
initialized = true
callback(true, false, "Finished loading in ${System.currentTimeMillis() - time}ms")
}
fun initializeGame(callback: (finished: Boolean, replaceStatus: Boolean, status: String) -> Unit) {
if (initializing) {
throw IllegalStateException("Already initializing!")
@ -299,39 +452,7 @@ object Starbound {
}
initializing = true
Thread({
val time = System.currentTimeMillis()
if (archivePaths.isNotEmpty()) {
callback(false, false, "Reading pak archives...")
for (path in archivePaths) {
callback(false, false, "Reading ${path.name}...")
addPak(StarboundPak(path) { _, status ->
callback(false, true, "${path.name}: $status")
})
}
}
loadStage(callback, this::loadFunctions, "functions")
loadStage(callback, this::loadTileMaterials, "materials")
loadStage(callback, this::loadProjectiles, "projectiles")
loadStage(callback, this::loadParallax, "parallax definitions")
loadStage(callback, this::loadMaterialModifiers, "material modifier definitions")
loadStage(callback, this::loadLiquidDefinitions, "liquid definitions")
loadStage(callback, this::loadItemDefinitions, "item definitions")
loadStage(callback, this::loadSpecies, "species")
pathStack.block("/") {
playerDefinition = GSON.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java)
}
initializing = false
initialized = true
callback(true, false, "Finished loading in ${System.currentTimeMillis() - time}ms")
}, "Asset Loader").start()
Thread({ doInitialize(callback) }, "Asset Loader").start()
}
fun onInitialize(callback: () -> Unit) {
@ -352,29 +473,6 @@ object Starbound {
}
}
private fun loadTileMaterials(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".material") }) {
try {
callback("Loading $listedFile")
val tileDef = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), TileDefinition::class.java) }
check(tiles[tileDef.materialName] == null) { "Already has material with name ${tileDef.materialName} loaded!" }
check(tilesByMaterialID[tileDef.materialId] == null) { "Already has material with ID ${tileDef.materialId} loaded!" }
tilesByMaterialID[tileDef.materialId] = tileDef
tiles[tileDef.materialName] = tileDef
} catch (err: Throwable) {
//throw TileDefLoadingException("Loading tile file $listedFile", err)
LOGGER.error("Loading tile file $listedFile", err)
}
if (terminateLoading) {
return
}
}
}
}
private fun loadProjectiles(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".projectile") }) {
@ -437,66 +535,6 @@ object Starbound {
}
}
private fun loadMaterialModifiers(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".matmod") }) {
try {
callback("Loading $listedFile")
val tileDef = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), MaterialModifier::class.java) }
check(tileModifiers[tileDef.modName] == null) { "Already has material with name ${tileDef.modName} loaded!" }
check(tileModifiersByID[tileDef.modId] == null) { "Already has material with ID ${tileDef.modId} loaded!" }
tileModifiersByID[tileDef.modId] = tileDef
tileModifiers[tileDef.modName] = tileDef
} catch (err: Throwable) {
//throw TileDefLoadingException("Loading tile file $listedFile", err)
LOGGER.error("Loading tile modifier file $listedFile", err)
}
if (terminateLoading) {
return
}
}
}
}
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".liquid") }) {
try {
callback("Loading $listedFile")
val liquidDef = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), LiquidDefinition::class.java) }
check(liquid.put(liquidDef.name, liquidDef) == null) { "Already has liquid with name ${liquidDef.name} loaded!" }
check(liquidByID.put(liquidDef.liquidId, liquidDef) == null) { "Already has liquid with ID ${liquidDef.liquidId} loaded!" }
} catch (err: Throwable) {
//throw TileDefLoadingException("Loading tile file $listedFile", err)
LOGGER.error("Loading liquid definition file $listedFile", err)
}
if (terminateLoading) {
return
}
}
}
}
private fun loadSpecies(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".species") }) {
try {
callback("Loading $listedFile")
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), Species::class.java) }
check(species.put(def.kind, def) == null) { "Already has liquid with name ${def.kind} loaded!" }
} catch (err: Throwable) {
LOGGER.error("Loading species definition file $listedFile", err)
}
if (terminateLoading) {
return
}
}
}
}
private fun loadItemDefinitions(callback: (String) -> Unit) {
val files = linkedMapOf(
".item" to ItemPrototype::class.java,