KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt

89 lines
3.1 KiB
Kotlin

package ru.dbotthepony.kstarbound
import com.google.gson.JsonElement
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.defs.actor.player.RecipeDefinition
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.ExecutorService
import java.util.concurrent.Future
import kotlin.collections.ArrayList
object RecipeRegistry {
private val LOGGER = LogManager.getLogger()
data class Entry(val value: RecipeDefinition, val json: JsonElement, val file: IStarboundFile)
private val recipesInternal = ArrayList<Entry>()
private val group2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
private val group2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
private val output2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
private val output2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
private val input2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
private val input2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
val recipes: List<Entry> = Collections.unmodifiableList(recipesInternal)
val group2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(group2recipesBacking)
val output2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(output2recipesBacking)
val input2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(input2recipesBacking)
private val backlog = ConcurrentLinkedQueue<Entry>()
private fun add(recipe: Entry) {
val value = recipe.value
recipesInternal.add(recipe)
for (group in value.groups) {
group2recipesInternal.computeIfAbsent(group, Object2ObjectFunction { p ->
ArrayList<Entry>(1).also {
group2recipesBacking[p as String] = Collections.unmodifiableList(it)
}
}).add(recipe)
}
output2recipesInternal.computeIfAbsent(value.output.name, Object2ObjectFunction { p ->
ArrayList<Entry>(1).also {
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
}
}).add(recipe)
for (input in value.input) {
input2recipesInternal.computeIfAbsent(input.name, Object2ObjectFunction { p ->
ArrayList<Entry>(1).also {
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
}
}).add(recipe)
}
}
fun finishLoad() {
var next = backlog.poll()
while (next != null) {
add(next)
next = backlog.poll()
}
}
fun load(fileTree: Map<String, List<IStarboundFile>>): List<Future<*>> {
val files = fileTree["recipe"] ?: return emptyList()
val elements = Starbound.gson.getAdapter(JsonElement::class.java)
val recipes = Starbound.gson.getAdapter(RecipeDefinition::class.java)
return files.map { listedFile ->
Starbound.EXECUTOR.submit {
try {
val json = elements.read(listedFile.jsonReader())
val value = recipes.fromJsonTree(json)
backlog.add(Entry(value, json, listedFile))
} catch (err: Throwable) {
LOGGER.error("Loading recipe definition file $listedFile", err)
}
}
}
}
}