160 lines
4.8 KiB
Kotlin
160 lines
4.8 KiB
Kotlin
package ru.dbotthepony.kstarbound.item
|
|
|
|
import com.google.common.collect.ImmutableSet
|
|
import com.google.gson.JsonObject
|
|
import com.google.gson.JsonPrimitive
|
|
import org.apache.logging.log4j.LogManager
|
|
import ru.dbotthepony.kommons.gson.contains
|
|
import ru.dbotthepony.kommons.gson.get
|
|
import ru.dbotthepony.kommons.gson.set
|
|
import ru.dbotthepony.kstarbound.Globals
|
|
import ru.dbotthepony.kstarbound.IStarboundFile
|
|
import ru.dbotthepony.kstarbound.Registries
|
|
import ru.dbotthepony.kstarbound.Registry
|
|
import ru.dbotthepony.kstarbound.Starbound
|
|
import ru.dbotthepony.kstarbound.defs.AssetPath
|
|
import ru.dbotthepony.kstarbound.defs.item.ItemType
|
|
import ru.dbotthepony.kstarbound.defs.`object`.ObjectDefinition
|
|
import ru.dbotthepony.kstarbound.fromJson
|
|
import ru.dbotthepony.kstarbound.json.JsonPatch
|
|
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
|
import java.util.concurrent.ConcurrentLinkedQueue
|
|
import java.util.concurrent.Future
|
|
|
|
object ItemRegistry {
|
|
class Entry(
|
|
val name: String,
|
|
val type: ItemType,
|
|
val json: JsonObject,
|
|
val isEmpty: Boolean,
|
|
val friendlyName: String,
|
|
val itemTags: ImmutableSet<String>,
|
|
val itemAgingScripts: ImmutableSet<AssetPath>,
|
|
val file: IStarboundFile?
|
|
) {
|
|
val isNotEmpty: Boolean
|
|
get() = !isEmpty
|
|
|
|
val directory = file?.computeDirectory() ?: "/"
|
|
}
|
|
|
|
private val LOGGER = LogManager.getLogger()
|
|
private val entries = HashMap<String, Entry>()
|
|
private val tasks = ConcurrentLinkedQueue<Runnable>()
|
|
|
|
val AIR = Entry("", ItemType.GENERIC, JsonObject(), true, "air", ImmutableSet.of(), ImmutableSet.of(), null)
|
|
|
|
init {
|
|
entries[""] = AIR
|
|
}
|
|
|
|
operator fun get(name: String): Entry {
|
|
return entries[name] ?: AIR
|
|
}
|
|
|
|
@JsonFactory
|
|
data class ReadData(
|
|
val itemName: String,
|
|
val shortdescription: String = "...",
|
|
val itemTags: ImmutableSet<String> = ImmutableSet.of(),
|
|
val itemAgingScripts: ImmutableSet<AssetPath> = ImmutableSet.of(),
|
|
)
|
|
|
|
@JsonFactory
|
|
data class ReadDataObj(
|
|
val shortdescription: String = "...",
|
|
val itemTags: ImmutableSet<String> = ImmutableSet.of(),
|
|
val itemAgingScripts: ImmutableSet<AssetPath> = ImmutableSet.of(),
|
|
)
|
|
|
|
private fun addObjectItem(obj: Registry.Entry<ObjectDefinition>) {
|
|
if (obj.key in entries) {
|
|
LOGGER.error("Refusing to overwrite item ${obj.key} with generated item for object (old def originate from ${entries[obj.key]!!.file}; new from ${obj.file})")
|
|
return
|
|
}
|
|
|
|
val config = obj.jsonObject.deepCopy()
|
|
|
|
if ("inventoryIcon" !in config) {
|
|
config["inventoryIcon"] = Globals.itemParameters.missingIcon.fullPath
|
|
LOGGER.warn("inventoryIcon is missing for object item ${obj.key}, using default ${Globals.itemParameters.missingIcon.fullPath}")
|
|
}
|
|
|
|
config["itemName"] = obj.key
|
|
|
|
if ("tooltipKind" !in config)
|
|
config["tooltipKind"] = "object"
|
|
|
|
// this is required for Lua call to "get item config"
|
|
config["printable"] = obj.value.printable
|
|
|
|
// Don't inherit object scripts. this is kind of a crappy solution to prevent
|
|
// ObjectItems (which are firable and therefore scripted) from trying to
|
|
// execute scripts intended for objects
|
|
config.remove("scripts")
|
|
|
|
val readData = Starbound.gson.fromJson(config, ReadDataObj::class.java)
|
|
|
|
entries[obj.key] = Entry(
|
|
name = obj.key,
|
|
type = ItemType.OBJECT,
|
|
json = config,
|
|
isEmpty = false,
|
|
friendlyName = readData.shortdescription,
|
|
itemTags = readData.itemTags,
|
|
itemAgingScripts = readData.itemAgingScripts,
|
|
file = obj.file,
|
|
)
|
|
}
|
|
|
|
fun finishLoad() {
|
|
tasks.forEach { it.run() }
|
|
tasks.clear()
|
|
|
|
for (obj in Registries.worldObjects.keys.values) {
|
|
if (obj.value.hasObjectItem) {
|
|
addObjectItem(obj)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun load(fileTree: Map<String, Collection<IStarboundFile>>, patches: Map<String, Collection<IStarboundFile>>): Collection<Future<*>> {
|
|
val futures = ArrayList<Future<*>>()
|
|
val data by lazy { Starbound.gson.getAdapter(ReadData::class.java) }
|
|
|
|
for (type in ItemType.entries) {
|
|
val files = fileTree[type.extension ?: continue] ?: continue
|
|
|
|
for (file in files) {
|
|
futures.add(Starbound.EXECUTOR.submit {
|
|
try {
|
|
val read = JsonPatch.apply(Starbound.ELEMENTS_ADAPTER.read(file.jsonReader()), patches[file.computeFullPath()]) as JsonObject
|
|
val readData = data.fromJsonTree(read)
|
|
|
|
tasks.add {
|
|
if (readData.itemName in entries) {
|
|
LOGGER.warn("Overwriting item definition at ${readData.itemName} (old def originate from ${entries[readData.itemName]!!.file}; new from $file)")
|
|
}
|
|
|
|
entries[readData.itemName] = Entry(
|
|
name = readData.itemName,
|
|
type = type,
|
|
json = read,
|
|
isEmpty = false,
|
|
friendlyName = readData.shortdescription,
|
|
itemTags = readData.itemTags,
|
|
itemAgingScripts = readData.itemAgingScripts,
|
|
file = file,
|
|
)
|
|
}
|
|
} catch (err: Throwable) {
|
|
LOGGER.error("Reading item definition $file", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
return futures
|
|
}
|
|
}
|