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

87 lines
3.2 KiB
Kotlin

package ru.dbotthepony.kstarbound.item
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.IStarboundFile
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.defs.actor.player.RecipeDefinition
import ru.dbotthepony.kstarbound.json.JsonPatch
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
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 tasks = 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() {
tasks.forEach { add(it) }
tasks.clear()
}
fun load(fileTree: Map<String, Collection<IStarboundFile>>, patchTree: Map<String, List<IStarboundFile>>): List<Future<*>> {
val files = fileTree["recipe"] ?: return emptyList()
val recipes by lazy { Starbound.gson.getAdapter(RecipeDefinition::class.java) }
return files.map { listedFile ->
Starbound.EXECUTOR.submit {
try {
val json = JsonPatch.apply(Starbound.ELEMENTS_ADAPTER.read(listedFile.jsonReader()), patchTree[listedFile.computeFullPath()])
val value = recipes.fromJsonTree(json)
tasks.add(Entry(value, json, listedFile))
} catch (err: Throwable) {
LOGGER.error("Loading recipe definition file $listedFile", err)
}
}
}
}
}