root.recipesForItem и подгрузка описания рецептов
This commit is contained in:
parent
046698ddc5
commit
89180a6664
47
src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt
Normal file
47
src/main/kotlin/ru/dbotthepony/kstarbound/RecipeRegistry.kt
Normal file
@ -0,0 +1,47 @@
|
||||
package ru.dbotthepony.kstarbound
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||
import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
||||
import java.util.Collections
|
||||
|
||||
class RecipeRegistry {
|
||||
private val recipesInternal = ArrayList<RecipeDefinition>()
|
||||
private val group2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<RecipeDefinition>>()
|
||||
private val group2recipesBacking = Object2ObjectOpenHashMap<String, List<RecipeDefinition>>()
|
||||
private val output2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<RecipeDefinition>>()
|
||||
private val output2recipesBacking = Object2ObjectOpenHashMap<String, List<RecipeDefinition>>()
|
||||
private val input2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<RecipeDefinition>>()
|
||||
private val input2recipesBacking = Object2ObjectOpenHashMap<String, List<RecipeDefinition>>()
|
||||
|
||||
val recipes: List<RecipeDefinition> = Collections.unmodifiableList(recipesInternal)
|
||||
val group2recipes: Map<String, List<RecipeDefinition>> = Collections.unmodifiableMap(group2recipesBacking)
|
||||
val output2recipes: Map<String, List<RecipeDefinition>> = Collections.unmodifiableMap(output2recipesBacking)
|
||||
val input2recipes: Map<String, List<RecipeDefinition>> = Collections.unmodifiableMap(input2recipesBacking)
|
||||
|
||||
fun add(recipe: RecipeDefinition) {
|
||||
recipesInternal.add(recipe)
|
||||
|
||||
for (group in recipe.groups) {
|
||||
group2recipesInternal.computeIfAbsent(group, Object2ObjectFunction { p ->
|
||||
ArrayList<RecipeDefinition>().also {
|
||||
group2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
}
|
||||
}).add(recipe)
|
||||
}
|
||||
|
||||
output2recipesInternal.computeIfAbsent(recipe.output.item.name, Object2ObjectFunction { p ->
|
||||
ArrayList<RecipeDefinition>().also {
|
||||
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
}
|
||||
}).add(recipe)
|
||||
|
||||
for (input in recipe.input) {
|
||||
input2recipesInternal.computeIfAbsent(input.item.name, Object2ObjectFunction { p ->
|
||||
ArrayList<RecipeDefinition>().also {
|
||||
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
}
|
||||
}).add(recipe)
|
||||
}
|
||||
}
|
||||
}
|
@ -35,7 +35,9 @@ import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.particle.ParticleDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.player.BlueprintLearnList
|
||||
import ru.dbotthepony.kstarbound.defs.player.PlayerDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.player.TechDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.projectile.ProjectileDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.quest.QuestTemplate
|
||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||
@ -120,9 +122,14 @@ class Starbound : ISBFileLocator {
|
||||
private val _json2Functions = ObjectRegistry<Json2Function>("json 2functions")
|
||||
val json2Functions = _json2Functions.view
|
||||
|
||||
private val _npcTypes = ObjectRegistry<NpcTypeDefinition>("npc types")
|
||||
private val _npcTypes = ObjectRegistry("npc types", NpcTypeDefinition::type)
|
||||
val npcTypes = _npcTypes.view
|
||||
|
||||
private val _projectiles = ObjectRegistry("projectiles", ProjectileDefinition::projectileName)
|
||||
val projectiles = _projectiles.view
|
||||
|
||||
val recipeRegistry = RecipeRegistry()
|
||||
|
||||
val gson: Gson = with(GsonBuilder()) {
|
||||
serializeNulls()
|
||||
setDateFormat(DateFormat.LONG)
|
||||
@ -197,6 +204,8 @@ class Starbound : ISBFileLocator {
|
||||
|
||||
registerTypeAdapter(ItemDescriptor.Adapter(this@Starbound))
|
||||
|
||||
registerTypeAdapterFactory(ItemReference.Factory(STRINGS))
|
||||
|
||||
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
||||
add(tiles::get)
|
||||
add(tileModifiers::get)
|
||||
@ -410,6 +419,28 @@ class Starbound : ISBFileLocator {
|
||||
TODO()
|
||||
}
|
||||
|
||||
state.setTableFunction("projectileGravityMultiplier", this) { args ->
|
||||
// float root.projectileGravityMultiplier(String projectileName)
|
||||
TODO()
|
||||
}
|
||||
|
||||
state.setTableFunction("projectileConfig", this) { args ->
|
||||
// Json root.projectileConfig(String projectileName)
|
||||
val name = args.getString()
|
||||
args.lua.push(projectiles[name]?.copy() ?: throw kotlin.NoSuchElementException("No such Projectile type $name"))
|
||||
1
|
||||
}
|
||||
|
||||
state.setTableFunction("recipesForItem", this) { args ->
|
||||
args.lua.push(JsonArray().also { a ->
|
||||
recipeRegistry.output2recipes[args.getString()]?.stream()?.map { gson.toJsonTree(it) }?.forEach {
|
||||
a.add(it)
|
||||
}
|
||||
})
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
state.pop()
|
||||
|
||||
state.load(polyfill, "@starbound.jar!/scripts/polyfill.lua")
|
||||
@ -606,6 +637,7 @@ class Starbound : ISBFileLocator {
|
||||
loadStage(callback, { loadItemDefinitions(it, ext2files) }, "item definitions")
|
||||
loadStage(callback, { loadJsonFunctions(it, ext2files["functions"] ?: listOf()) }, "json functions")
|
||||
loadStage(callback, { loadJson2Functions(it, ext2files["2functions"] ?: listOf()) }, "json 2functions")
|
||||
loadStage(callback, { loadRecipes(it, ext2files["recipe"] ?: listOf()) }, "recipes")
|
||||
|
||||
loadStage(callback, _tiles, ext2files["material"] ?: listOf())
|
||||
loadStage(callback, _tileModifiers, ext2files["matmod"] ?: listOf())
|
||||
@ -616,6 +648,7 @@ class Starbound : ISBFileLocator {
|
||||
loadStage(callback, _questTemplates, ext2files["questtemplate"] ?: listOf())
|
||||
loadStage(callback, _techs, ext2files["tech"] ?: listOf())
|
||||
loadStage(callback, _npcTypes, ext2files["npctype"] ?: listOf())
|
||||
loadStage(callback, _projectiles, ext2files["projectile"] ?: listOf())
|
||||
|
||||
pathStack.block("/") {
|
||||
//playerDefinition = gson.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java)
|
||||
@ -731,6 +764,21 @@ class Starbound : ISBFileLocator {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadRecipes(callback: (String) -> Unit, files: Collection<IStarboundFile>) {
|
||||
for (listedFile in files) {
|
||||
try {
|
||||
callback("Loading $listedFile")
|
||||
recipeRegistry.add(gson.fromJson(listedFile.reader(), RecipeDefinition::class.java))
|
||||
} catch (err: Throwable) {
|
||||
logger.error("Loading recipe definition file $listedFile", err)
|
||||
}
|
||||
|
||||
if (terminateLoading) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Глобальный [Interner] для [String]
|
||||
|
@ -0,0 +1,60 @@
|
||||
package ru.dbotthepony.kstarbound.defs
|
||||
|
||||
import com.google.common.collect.Interner
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.defs.item.IItemDefinition
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||
import ru.dbotthepony.kstarbound.util.ItemDescriptor
|
||||
|
||||
/**
|
||||
* Прототип [ItemDescriptor] в JSON файлах
|
||||
*/
|
||||
data class ItemReference(
|
||||
val item: RegistryReference<IItemDefinition>,
|
||||
val count: Long = 1,
|
||||
val parameters: JsonObject = JsonObject()
|
||||
) {
|
||||
fun makeStack(): ItemDescriptor {
|
||||
return ItemDescriptor(item.value ?: return ItemDescriptor.EMPTY, count, parameters)
|
||||
}
|
||||
|
||||
class Factory(val stringInterner: Interner<String> = Interner { it }) : TypeAdapterFactory {
|
||||
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||
if (type.rawType == ItemReference::class.java) {
|
||||
return object : TypeAdapter<ItemReference>() {
|
||||
private val regular = FactoryAdapter.createFor(ItemReference::class, JsonFactory(storesJson = false, logMisses = true, asList = false), gson, stringInterner)
|
||||
private val references = gson.getAdapter(TypeToken.getParameterized(RegistryReference::class.java, IItemDefinition::class.java)) as TypeAdapter<RegistryReference<IItemDefinition>>
|
||||
|
||||
override fun write(out: JsonWriter, value: ItemReference?) {
|
||||
if (value == null)
|
||||
out.nullValue()
|
||||
else
|
||||
regular.write(out, value)
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): ItemReference? {
|
||||
if (`in`.consumeNull())
|
||||
return null
|
||||
|
||||
if (`in`.peek() == JsonToken.STRING) {
|
||||
return ItemReference(references.read(`in`))
|
||||
} else {
|
||||
return regular.read(`in`)
|
||||
}
|
||||
}
|
||||
} as TypeAdapter<T>
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package ru.dbotthepony.kstarbound.defs.player
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import ru.dbotthepony.kstarbound.defs.ItemReference
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
|
||||
@JsonFactory
|
||||
data class RecipeDefinition(
|
||||
val input: ImmutableList<ItemReference>,
|
||||
val output: ItemReference,
|
||||
val groups: ImmutableSet<String> = ImmutableSet.of(),
|
||||
val matchInputParameters: Boolean = false,
|
||||
val duration: Double = 0.5,
|
||||
val currencyInputs: ImmutableMap<String, Long> = ImmutableMap.of()
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package ru.dbotthepony.kstarbound.defs.projectile
|
||||
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
|
||||
@JsonFactory
|
||||
data class ProjectileDefinition(
|
||||
val projectileName: String
|
||||
)
|
@ -84,3 +84,12 @@ fun TypeAdapterFactory.ifString(reader: (String) -> Any): TypeAdapterFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonReader.consumeNull(): Boolean {
|
||||
if (peek() == JsonToken.NULL) {
|
||||
nextNull()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -19,13 +19,11 @@ import com.google.gson.stream.JsonWriter
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.util.enrollList
|
||||
import ru.dbotthepony.kstarbound.defs.util.enrollMap
|
||||
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
|
||||
import ru.dbotthepony.kstarbound.getValue
|
||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||
import ru.dbotthepony.kstarbound.io.json.ifString
|
||||
import ru.dbotthepony.kstarbound.setValue
|
||||
import java.lang.reflect.Constructor
|
||||
import kotlin.jvm.internal.DefaultConstructorMarker
|
||||
import kotlin.properties.Delegates
|
||||
@ -152,7 +150,12 @@ class FactoryAdapter<T : Any> private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun write(out: JsonWriter, value: T) {
|
||||
override fun write(out: JsonWriter, value: T?) {
|
||||
if (value == null) {
|
||||
out.nullValue()
|
||||
return
|
||||
}
|
||||
|
||||
out.beginObject()
|
||||
|
||||
for ((field, adapter) in types) {
|
||||
@ -164,7 +167,10 @@ class FactoryAdapter<T : Any> private constructor(
|
||||
out.endObject()
|
||||
}
|
||||
|
||||
override fun read(reader: JsonReader): T {
|
||||
override fun read(reader: JsonReader): T? {
|
||||
if (reader.consumeNull())
|
||||
return null
|
||||
|
||||
// таблица присутствия значений (если значение true то на i было значение внутри json)
|
||||
val presentValues = BooleanArray(types.size + (if (storesJson) 1 else 0))
|
||||
val readValues = arrayOfNulls<Any>(types.size + (if (storesJson) 1 else 0))
|
||||
@ -526,6 +532,44 @@ class FactoryAdapter<T : Any> private constructor(
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
fun <T : Any> createFor(kclass: KClass<T>, config: JsonFactory, gson: Gson, stringInterner: Interner<String> = Interner { it }): TypeAdapter<T> {
|
||||
val builder = Builder(kclass)
|
||||
val properties = kclass.declaredMembers.filterIsInstance<KProperty1<T, *>>()
|
||||
|
||||
if (config.asList) {
|
||||
builder.inputAsList()
|
||||
}
|
||||
|
||||
builder.storesJson(config.storesJson)
|
||||
builder.logMisses(config.logMisses)
|
||||
builder.stringInterner = stringInterner
|
||||
|
||||
if (properties.isEmpty()) {
|
||||
throw IllegalArgumentException("${kclass.qualifiedName} has no valid members")
|
||||
}
|
||||
|
||||
val foundConstructor = kclass.primaryConstructor ?: throw NoSuchElementException("Can't determine primary constructor for ${kclass.qualifiedName}")
|
||||
|
||||
if (!config.storesJson) {
|
||||
for (argument in foundConstructor.parameters) {
|
||||
val property = properties.first { it.name == argument.name && it.returnType.isSupertypeOf(argument.type) }
|
||||
val config = property.annotations.firstOrNull { it.annotationClass == JsonPropertyConfig::class } as JsonPropertyConfig?
|
||||
builder.auto(property, isFlat = config?.isFlat ?: false)
|
||||
}
|
||||
} else {
|
||||
val params = foundConstructor.parameters
|
||||
|
||||
for (i in 0 until params.size - 1) {
|
||||
val argument = params[i]
|
||||
val property = properties.first { it.name == argument.name && it.returnType.isSupertypeOf(argument.type) }
|
||||
val config = property.annotations.firstOrNull { it.annotationClass == JsonPropertyConfig::class } as JsonPropertyConfig?
|
||||
builder.auto(property, isFlat = config?.isFlat ?: false)
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build(gson)
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(val stringInterner: Interner<String> = Interner { it }) : TypeAdapterFactory {
|
||||
@ -538,41 +582,7 @@ class FactoryAdapter<T : Any> private constructor(
|
||||
|
||||
val bconfig = first[0] as JsonFactory
|
||||
val kclass = raw.kotlin as KClass<T>
|
||||
val builder = Builder(kclass)
|
||||
val properties = kclass.declaredMembers.filterIsInstance<KProperty1<T, *>>()
|
||||
|
||||
if (bconfig.asList) {
|
||||
builder.inputAsList()
|
||||
}
|
||||
|
||||
builder.storesJson(bconfig.storesJson)
|
||||
builder.logMisses(bconfig.logMisses)
|
||||
builder.stringInterner = stringInterner
|
||||
|
||||
if (properties.isEmpty()) {
|
||||
throw IllegalArgumentException("${kclass.qualifiedName} has no valid members")
|
||||
}
|
||||
|
||||
val foundConstructor = kclass.primaryConstructor ?: throw NoSuchElementException("Can't determine primary constructor for ${kclass.qualifiedName}")
|
||||
|
||||
if (!bconfig.storesJson) {
|
||||
for (argument in foundConstructor.parameters) {
|
||||
val property = properties.first { it.name == argument.name && it.returnType.isSupertypeOf(argument.type) }
|
||||
val config = property.annotations.firstOrNull { it.annotationClass == JsonPropertyConfig::class } as JsonPropertyConfig?
|
||||
builder.auto(property, isFlat = config?.isFlat ?: false)
|
||||
}
|
||||
} else {
|
||||
val params = foundConstructor.parameters
|
||||
|
||||
for (i in 0 until params.size - 1) {
|
||||
val argument = params[i]
|
||||
val property = properties.first { it.name == argument.name && it.returnType.isSupertypeOf(argument.type) }
|
||||
val config = property.annotations.firstOrNull { it.annotationClass == JsonPropertyConfig::class } as JsonPropertyConfig?
|
||||
builder.auto(property, isFlat = config?.isFlat ?: false)
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build(gson)
|
||||
return createFor(kclass, bconfig, gson, stringInterner)
|
||||
}
|
||||
|
||||
return null
|
||||
|
Loading…
Reference in New Issue
Block a user