Redesigned registry
This commit is contained in:
parent
8cd84a4501
commit
949ed802ad
@ -50,11 +50,14 @@ fun String.sintern(): String = Starbound.STRINGS.intern(this)
|
|||||||
|
|
||||||
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
||||||
|
|
||||||
fun <T : Any> Collection<IStarboundFile>.batch(executor: ForkJoinPool, batchSize: Int = 16, mapper: (IStarboundFile) -> KOptional<RegistryObject<T>>): Stream<RegistryObject<T>> {
|
/**
|
||||||
|
* guarantees even distribution of tasks while also preserving encountered order of elements
|
||||||
|
*/
|
||||||
|
fun <T> Collection<IStarboundFile>.batch(executor: ForkJoinPool, batchSize: Int = 16, mapper: (IStarboundFile) -> KOptional<T>): Stream<T> {
|
||||||
require(batchSize >= 1) { "Invalid batch size: $batchSize" }
|
require(batchSize >= 1) { "Invalid batch size: $batchSize" }
|
||||||
|
|
||||||
if (batchSize == 1 || size <= batchSize) {
|
if (batchSize == 1 || size <= batchSize) {
|
||||||
val tasks = ArrayList<ForkJoinTask<KOptional<RegistryObject<T>>>>()
|
val tasks = ArrayList<ForkJoinTask<KOptional<T>>>()
|
||||||
|
|
||||||
for (listedFile in this) {
|
for (listedFile in this) {
|
||||||
tasks.add(executor.submit(Callable { mapper.invoke(listedFile) }))
|
tasks.add(executor.submit(Callable { mapper.invoke(listedFile) }))
|
||||||
@ -63,7 +66,7 @@ fun <T : Any> Collection<IStarboundFile>.batch(executor: ForkJoinPool, batchSize
|
|||||||
return tasks.stream().map { it.join() }.filter { it.isPresent }.map { it.value }
|
return tasks.stream().map { it.join() }.filter { it.isPresent }.map { it.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
val batches = ArrayList<ForkJoinTask<List<KOptional<RegistryObject<T>>>>>()
|
val batches = ArrayList<ForkJoinTask<List<KOptional<T>>>>()
|
||||||
var batch = ArrayList<IStarboundFile>(batchSize)
|
var batch = ArrayList<IStarboundFile>(batchSize)
|
||||||
|
|
||||||
for (listedFile in this) {
|
for (listedFile in this) {
|
||||||
|
@ -11,7 +11,6 @@ import ru.dbotthepony.kstarbound.player.Avatar
|
|||||||
import ru.dbotthepony.kstarbound.player.QuestDescriptor
|
import ru.dbotthepony.kstarbound.player.QuestDescriptor
|
||||||
import ru.dbotthepony.kstarbound.player.QuestInstance
|
import ru.dbotthepony.kstarbound.player.QuestInstance
|
||||||
import ru.dbotthepony.kstarbound.util.JVMTimeSource
|
import ru.dbotthepony.kstarbound.util.JVMTimeSource
|
||||||
import ru.dbotthepony.kstarbound.world.api.AbstractCell
|
|
||||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||||
import ru.dbotthepony.kstarbound.io.json.VersionedJson
|
import ru.dbotthepony.kstarbound.io.json.VersionedJson
|
||||||
import ru.dbotthepony.kstarbound.io.readVarInt
|
import ru.dbotthepony.kstarbound.io.readVarInt
|
||||||
@ -118,7 +117,7 @@ fun main() {
|
|||||||
val rand = Random()
|
val rand = Random()
|
||||||
|
|
||||||
for (i in 0 .. 128) {
|
for (i in 0 .. 128) {
|
||||||
val item = ItemEntity(client.world!!, Registries.items.values.random().value)
|
val item = ItemEntity(client.world!!, Registries.items.keys.values.random().value)
|
||||||
|
|
||||||
item.position = Vector2d(225.0 - i, 785.0)
|
item.position = Vector2d(225.0 - i, 785.0)
|
||||||
item.spawn()
|
item.spawn()
|
||||||
|
@ -1,185 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonElement
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonPrimitive
|
|
||||||
import com.google.gson.internal.bind.JsonTreeReader
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
|
||||||
import org.apache.logging.log4j.LogManager
|
|
||||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
|
||||||
import ru.dbotthepony.kstarbound.lua.LuaState
|
|
||||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
|
||||||
import ru.dbotthepony.kstarbound.util.set
|
|
||||||
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
inline fun <reified T : Any> ObjectRegistry(name: String, noinline key: ((T) -> String)? = null, noinline intKey: ((T) -> Int)? = null): ObjectRegistry<T> {
|
|
||||||
return ObjectRegistry(T::class, name, key, intKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mergeJsonElements(source: JsonObject, destination: JsonObject): JsonObject {
|
|
||||||
for ((k, v) in source.entrySet()) {
|
|
||||||
if (!destination.has(k)) {
|
|
||||||
destination[k] = v.deepCopy()
|
|
||||||
} else {
|
|
||||||
mergeJsonElements(v, destination[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return destination
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mergeJsonElements(source: JsonArray, destination: JsonArray): JsonArray {
|
|
||||||
for ((i, v) in source.withIndex()) {
|
|
||||||
if (i >= destination.size()) {
|
|
||||||
destination.add(v.deepCopy())
|
|
||||||
} else {
|
|
||||||
destination[i] = mergeJsonElements(v, destination[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return destination
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mergeJsonElements(source: JsonElement, destination: JsonElement): JsonElement {
|
|
||||||
if (destination is JsonPrimitive) {
|
|
||||||
return destination
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destination is JsonObject && source is JsonObject) {
|
|
||||||
return mergeJsonElements(source, destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destination is JsonArray && source is JsonArray) {
|
|
||||||
return mergeJsonElements(source, destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
return destination
|
|
||||||
}
|
|
||||||
|
|
||||||
class RegistryObject<T : Any>(
|
|
||||||
/**
|
|
||||||
* Объект реестра
|
|
||||||
*/
|
|
||||||
val value: T,
|
|
||||||
/**
|
|
||||||
* Оригинальный JSON объекта без каких либо изменений
|
|
||||||
*/
|
|
||||||
val json: JsonElement,
|
|
||||||
/**
|
|
||||||
* Файл, откуда данный объект был загружен
|
|
||||||
*/
|
|
||||||
val file: IStarboundFile,
|
|
||||||
) {
|
|
||||||
val jsonObject get() = json as JsonObject
|
|
||||||
|
|
||||||
fun push(lua: LuaState) {
|
|
||||||
lua.push(toJson())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun push(lua: LuaState.ArgStack) {
|
|
||||||
lua.push(toJson())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает полную (обработанную) структуру [JsonObject] объекта [value]
|
|
||||||
*
|
|
||||||
* Полнота определяется тем, что [value] может иметь свойства по умолчанию, которые не указаны
|
|
||||||
* в оригинальной JSON структуре. [copy] не вернёт данные свойства по умолчанию, а [toJson] вернёт.
|
|
||||||
*/
|
|
||||||
fun toJson(): JsonElement {
|
|
||||||
return mergeJsonElements(json, Starbound.gson.toJsonTree(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun traverseJsonPath(path: String): JsonElement? {
|
|
||||||
return traverseJsonPath(path, mergeJsonElements(json, Starbound.gson.toJsonTree(value)))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
return other === this || other is RegistryObject<*> && other.value == value && other.json == json
|
|
||||||
}
|
|
||||||
|
|
||||||
private var computedHash = false
|
|
||||||
private var hash = 0
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
if (!computedHash) {
|
|
||||||
hash = value.hashCode().rotateRight(13) xor json.hashCode()
|
|
||||||
computedHash = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "RegistryObject[$value from $file]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ObjectRegistry<T : Any>(val clazz: KClass<T>, val name: String, val key: ((T) -> String)? = null, val intKey: ((T) -> Int)? = null) {
|
|
||||||
val objects = Object2ObjectOpenHashMap<String, RegistryObject<T>>()
|
|
||||||
val intObjects = Int2ObjectOpenHashMap<RegistryObject<T>>()
|
|
||||||
|
|
||||||
val values get() = objects.values
|
|
||||||
|
|
||||||
operator fun get(index: String) = objects[index]
|
|
||||||
operator fun get(index: Int): RegistryObject<T>? = intObjects[index]
|
|
||||||
operator fun contains(index: String) = index in objects
|
|
||||||
operator fun contains(index: Int) = index in intObjects
|
|
||||||
|
|
||||||
fun clear() {
|
|
||||||
objects.clear()
|
|
||||||
intObjects.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(file: IStarboundFile): Boolean {
|
|
||||||
return AssetPathStack(file.computeDirectory()) {
|
|
||||||
val elem = Starbound.gson.fromJson(file.reader(), JsonElement::class.java)
|
|
||||||
val value = Starbound.gson.fromJson<T>(JsonTreeReader(elem), clazz.java)
|
|
||||||
add(RegistryObject(value, elem, file), this.key?.invoke(value) ?: throw UnsupportedOperationException("No key mapper"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(value: RegistryObject<T>): Boolean {
|
|
||||||
return add(value, this.key?.invoke(value.value) ?: throw UnsupportedOperationException("No key mapper"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(value: T, json: JsonElement, file: IStarboundFile): Boolean {
|
|
||||||
return add(RegistryObject(value, json, file), this.key?.invoke(value) ?: throw UnsupportedOperationException("No key mapper"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(value: T, json: JsonElement, file: IStarboundFile, key: String): Boolean {
|
|
||||||
return add(RegistryObject(value, json, file), key)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val lock = Any()
|
|
||||||
|
|
||||||
private fun add(value: RegistryObject<T>, key: String): Boolean {
|
|
||||||
synchronized(lock) {
|
|
||||||
val existing = objects.put(key, value)
|
|
||||||
|
|
||||||
if (existing != null) {
|
|
||||||
LOGGER.warn("Registry $name already has object with key $key! Overwriting. (old originated from ${existing.file}, new originate from ${value.file}).")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.intKey == null)
|
|
||||||
return existing != null
|
|
||||||
|
|
||||||
val intKey = this.intKey.invoke(value.value)
|
|
||||||
val intExisting = intObjects.put(intKey, value)
|
|
||||||
|
|
||||||
if (intExisting != null) {
|
|
||||||
LOGGER.warn("Registry $name already has object with ID $intKey (new $key, old ${ objects.entries.firstOrNull { it.value === intExisting }?.key })! Overwriting. (old originated from ${intExisting.file}, new originate from ${value.file}).")
|
|
||||||
}
|
|
||||||
|
|
||||||
return existing != null || intExisting != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +1,66 @@
|
|||||||
package ru.dbotthepony.kstarbound
|
package ru.dbotthepony.kstarbound
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.internal.bind.JsonTreeReader
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||||
import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
||||||
import ru.dbotthepony.kstarbound.util.KOptional
|
import ru.dbotthepony.kstarbound.util.KOptional
|
||||||
import java.util.Collections
|
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
||||||
import java.util.LinkedList
|
import java.util.*
|
||||||
import java.util.concurrent.Callable
|
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.ForkJoinPool
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.ForkJoinTask
|
import java.util.concurrent.ForkJoinTask
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.concurrent.withLock
|
||||||
|
|
||||||
object RecipeRegistry {
|
object RecipeRegistry {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
private val recipesInternal = ArrayList<RegistryObject<RecipeDefinition>>()
|
data class Entry(val value: RecipeDefinition, val json: JsonElement, val file: IStarboundFile)
|
||||||
private val group2recipesInternal = Object2ObjectOpenHashMap<String, LinkedList<RegistryObject<RecipeDefinition>>>()
|
|
||||||
private val group2recipesBacking = Object2ObjectOpenHashMap<String, List<RegistryObject<RecipeDefinition>>>()
|
|
||||||
private val output2recipesInternal = Object2ObjectOpenHashMap<String, LinkedList<RegistryObject<RecipeDefinition>>>()
|
|
||||||
private val output2recipesBacking = Object2ObjectOpenHashMap<String, List<RegistryObject<RecipeDefinition>>>()
|
|
||||||
private val input2recipesInternal = Object2ObjectOpenHashMap<String, LinkedList<RegistryObject<RecipeDefinition>>>()
|
|
||||||
private val input2recipesBacking = Object2ObjectOpenHashMap<String, List<RegistryObject<RecipeDefinition>>>()
|
|
||||||
|
|
||||||
val recipes: List<RegistryObject<RecipeDefinition>> = Collections.unmodifiableList(recipesInternal)
|
private val recipesInternal = ArrayList<Entry>()
|
||||||
val group2recipes: Map<String, List<RegistryObject<RecipeDefinition>>> = Collections.unmodifiableMap(group2recipesBacking)
|
private val group2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
|
||||||
val output2recipes: Map<String, List<RegistryObject<RecipeDefinition>>> = Collections.unmodifiableMap(output2recipesBacking)
|
private val group2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
|
||||||
val input2recipes: Map<String, List<RegistryObject<RecipeDefinition>>> = Collections.unmodifiableMap(input2recipesBacking)
|
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>>()
|
||||||
|
|
||||||
fun add(recipe: RegistryObject<RecipeDefinition>) {
|
val recipes: List<Entry> = Collections.unmodifiableList(recipesInternal)
|
||||||
val value = recipe.value
|
val group2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(group2recipesBacking)
|
||||||
recipesInternal.add(recipe)
|
val output2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(output2recipesBacking)
|
||||||
|
val input2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(input2recipesBacking)
|
||||||
|
|
||||||
for (group in value.groups) {
|
private val lock = ReentrantLock()
|
||||||
group2recipesInternal.computeIfAbsent(group, Object2ObjectFunction { p ->
|
|
||||||
LinkedList<RegistryObject<RecipeDefinition>>().also {
|
|
||||||
group2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
|
||||||
}
|
|
||||||
}).add(recipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
output2recipesInternal.computeIfAbsent(value.output.item.name, Object2ObjectFunction { p ->
|
fun add(recipe: Entry) {
|
||||||
LinkedList<RegistryObject<RecipeDefinition>>().also {
|
lock.withLock {
|
||||||
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
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)
|
||||||
}
|
}
|
||||||
}).add(recipe)
|
|
||||||
|
|
||||||
for (input in value.input) {
|
output2recipesInternal.computeIfAbsent(value.output.item.key.left(), Object2ObjectFunction { p ->
|
||||||
input2recipesInternal.computeIfAbsent(input.item.name, Object2ObjectFunction { p ->
|
ArrayList<Entry>(1).also {
|
||||||
LinkedList<RegistryObject<RecipeDefinition>>().also {
|
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||||
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
|
||||||
}
|
}
|
||||||
}).add(recipe)
|
}).add(recipe)
|
||||||
|
|
||||||
|
for (input in value.input) {
|
||||||
|
input2recipesInternal.computeIfAbsent(input.item.key.left(), Object2ObjectFunction { p ->
|
||||||
|
ArrayList<Entry>(1).also {
|
||||||
|
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||||
|
}
|
||||||
|
}).add(recipe)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,12 +80,12 @@ object RecipeRegistry {
|
|||||||
line.text = ("Loading $listedFile")
|
line.text = ("Loading $listedFile")
|
||||||
val json = elements.read(listedFile.jsonReader())
|
val json = elements.read(listedFile.jsonReader())
|
||||||
val value = recipes.fromJsonTree(json)
|
val value = recipes.fromJsonTree(json)
|
||||||
line.elements.incrementAndGet()
|
KOptional.of(Entry(value, json, listedFile))
|
||||||
KOptional(RegistryObject(value, json, listedFile))
|
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading recipe definition file $listedFile", err)
|
LOGGER.error("Loading recipe definition file $listedFile", err)
|
||||||
line.elements.incrementAndGet()
|
|
||||||
KOptional.empty()
|
KOptional.empty()
|
||||||
|
} finally {
|
||||||
|
line.elements.incrementAndGet()
|
||||||
}
|
}
|
||||||
}.forEach { add(it) }
|
}.forEach { add(it) }
|
||||||
|
|
||||||
|
@ -36,33 +36,64 @@ import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
|||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
import ru.dbotthepony.kstarbound.util.KOptional
|
import ru.dbotthepony.kstarbound.util.KOptional
|
||||||
import java.util.concurrent.Callable
|
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.ForkJoinPool
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.ForkJoinTask
|
import java.util.concurrent.ForkJoinTask
|
||||||
import java.util.concurrent.Future
|
|
||||||
|
|
||||||
object Registries {
|
object Registries {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
val tiles = ObjectRegistry("tiles", TileDefinition::materialName, TileDefinition::materialId)
|
val tiles = Registry<TileDefinition>("tiles")
|
||||||
val tileModifiers = ObjectRegistry("tile modifiers", MaterialModifier::modName, MaterialModifier::modId)
|
val tileModifiers = Registry<MaterialModifier>("tile modifiers")
|
||||||
val liquid = ObjectRegistry("liquid", LiquidDefinition::name, LiquidDefinition::liquidId)
|
val liquid = Registry<LiquidDefinition>("liquid")
|
||||||
val species = ObjectRegistry("species", Species::kind)
|
val species = Registry<Species>("species")
|
||||||
val statusEffects = ObjectRegistry("status effects", StatusEffectDefinition::name)
|
val statusEffects = Registry<StatusEffectDefinition>("status effects")
|
||||||
val particles = ObjectRegistry("particles", ParticleDefinition::kind)
|
val particles = Registry<ParticleDefinition>("particles")
|
||||||
val items = ObjectRegistry("items", IItemDefinition::itemName)
|
val items = Registry<IItemDefinition>("items")
|
||||||
val questTemplates = ObjectRegistry("quest templates", QuestTemplate::id)
|
val questTemplates = Registry<QuestTemplate>("quest templates")
|
||||||
val techs = ObjectRegistry("techs", TechDefinition::name)
|
val techs = Registry<TechDefinition>("techs")
|
||||||
val jsonFunctions = ObjectRegistry<JsonFunction>("json functions")
|
val jsonFunctions = Registry<JsonFunction>("json functions")
|
||||||
val json2Functions = ObjectRegistry<Json2Function>("json 2functions")
|
val json2Functions = Registry<Json2Function>("json 2functions")
|
||||||
val npcTypes = ObjectRegistry("npc types", NpcTypeDefinition::type)
|
val npcTypes = Registry<NpcTypeDefinition>("npc types")
|
||||||
val projectiles = ObjectRegistry("projectiles", ProjectileDefinition::projectileName)
|
val projectiles = Registry<ProjectileDefinition>("projectiles")
|
||||||
val tenants = ObjectRegistry("tenants", TenantDefinition::name)
|
val tenants = Registry<TenantDefinition>("tenants")
|
||||||
val treasurePools = ObjectRegistry("treasure pools", TreasurePoolDefinition::name)
|
val treasurePools = Registry<TreasurePoolDefinition>("treasure pools")
|
||||||
val monsterSkills = ObjectRegistry("monster skills", MonsterSkillDefinition::name)
|
val monsterSkills = Registry<MonsterSkillDefinition>("monster skills")
|
||||||
val monsterTypes = ObjectRegistry("monster types", MonsterTypeDefinition::type)
|
val monsterTypes = Registry<MonsterTypeDefinition>("monster types")
|
||||||
val worldObjects = ObjectRegistry("objects", ObjectDefinition::objectName)
|
val worldObjects = Registry<ObjectDefinition>("objects")
|
||||||
|
|
||||||
|
private fun <T> key(mapper: (T) -> String): (T) -> Pair<String, Int?> {
|
||||||
|
return { mapper.invoke(it) to null }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> key(mapper: (T) -> String, mapperInt: (T) -> Int): (T) -> Pair<String, Int> {
|
||||||
|
return { mapper.invoke(it) to mapperInt.invoke(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun validate(): Boolean {
|
||||||
|
var any = false
|
||||||
|
|
||||||
|
any = !tiles.validate() || any
|
||||||
|
any = !tileModifiers.validate() || any
|
||||||
|
any = !liquid.validate() || any
|
||||||
|
any = !species.validate() || any
|
||||||
|
any = !statusEffects.validate() || any
|
||||||
|
any = !particles.validate() || any
|
||||||
|
any = !items.validate() || any
|
||||||
|
any = !questTemplates.validate() || any
|
||||||
|
any = !techs.validate() || any
|
||||||
|
any = !jsonFunctions.validate() || any
|
||||||
|
any = !json2Functions.validate() || any
|
||||||
|
any = !npcTypes.validate() || any
|
||||||
|
any = !projectiles.validate() || any
|
||||||
|
any = !tenants.validate() || any
|
||||||
|
any = !treasurePools.validate() || any
|
||||||
|
any = !monsterSkills.validate() || any
|
||||||
|
any = !monsterTypes.validate() || any
|
||||||
|
any = !worldObjects.validate() || any
|
||||||
|
|
||||||
|
return !any
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadStage(
|
private fun loadStage(
|
||||||
log: ILoadingLog,
|
log: ILoadingLog,
|
||||||
@ -81,8 +112,9 @@ object Registries {
|
|||||||
private inline fun <reified T : Any> loadStage(
|
private inline fun <reified T : Any> loadStage(
|
||||||
log: ILoadingLog,
|
log: ILoadingLog,
|
||||||
executor: ForkJoinPool,
|
executor: ForkJoinPool,
|
||||||
registry: ObjectRegistry<T>,
|
registry: Registry<T>,
|
||||||
files: List<IStarboundFile>,
|
files: List<IStarboundFile>,
|
||||||
|
noinline keyProvider: (T) -> Pair<String, Int?>,
|
||||||
name: String = registry.name
|
name: String = registry.name
|
||||||
) {
|
) {
|
||||||
val adapter = Starbound.gson.getAdapter(T::class.java)
|
val adapter = Starbound.gson.getAdapter(T::class.java)
|
||||||
@ -95,19 +127,29 @@ object Registries {
|
|||||||
try {
|
try {
|
||||||
it.text = "Loading $listedFile"
|
it.text = "Loading $listedFile"
|
||||||
|
|
||||||
val result = AssetPathStack(listedFile.computeDirectory()) {
|
AssetPathStack(listedFile.computeDirectory()) {
|
||||||
val elem = elementAdapter.read(listedFile.jsonReader())
|
val elem = elementAdapter.read(listedFile.jsonReader())
|
||||||
RegistryObject(adapter.fromJsonTree(elem), elem, listedFile)
|
val read = adapter.fromJsonTree(elem)
|
||||||
}
|
val keys = keyProvider(read);
|
||||||
|
|
||||||
it.elements.incrementAndGet()
|
KOptional.of {
|
||||||
KOptional(result)
|
try {
|
||||||
|
if (keys.second != null)
|
||||||
|
registry.add(keys.first, keys.second!!, read, elem, listedFile)
|
||||||
|
else
|
||||||
|
registry.add(keys.first, read, elem, listedFile)
|
||||||
|
} catch (err: Throwable) {
|
||||||
|
LOGGER.error("Loading ${registry.name} definition file $listedFile", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading ${registry.name} definition file $listedFile", err)
|
LOGGER.error("Loading ${registry.name} definition file $listedFile", err);
|
||||||
it.elements.incrementAndGet()
|
|
||||||
KOptional.empty()
|
KOptional.empty()
|
||||||
|
} finally {
|
||||||
|
it.elements.incrementAndGet()
|
||||||
}
|
}
|
||||||
}.forEach { registry.add(it) }
|
}.forEach { it.invoke() }
|
||||||
}, name)
|
}, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,20 +162,20 @@ object Registries {
|
|||||||
tasks.add(executor.submit { loadStage(log, { loadJson2Functions(it, fileTree["2functions"] ?: listOf()) }, "json 2functions") })
|
tasks.add(executor.submit { loadStage(log, { loadJson2Functions(it, fileTree["2functions"] ?: listOf()) }, "json 2functions") })
|
||||||
tasks.add(executor.submit { loadStage(log, { loadTreasurePools(it, fileTree["treasurepools"] ?: listOf()) }, "treasure pools") })
|
tasks.add(executor.submit { loadStage(log, { loadTreasurePools(it, fileTree["treasurepools"] ?: listOf()) }, "treasure pools") })
|
||||||
|
|
||||||
tasks.add(executor.submit { loadStage(log, executor, tiles, fileTree["material"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, tiles, fileTree["material"] ?: listOf(), key(TileDefinition::materialName, TileDefinition::materialId)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, tileModifiers, fileTree["matmod"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, tileModifiers, fileTree["matmod"] ?: listOf(), key(MaterialModifier::modName, MaterialModifier::modId)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, liquid, fileTree["liquid"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, liquid, fileTree["liquid"] ?: listOf(), key(LiquidDefinition::name, LiquidDefinition::liquidId)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, worldObjects, fileTree["object"] ?: listOf()) })
|
|
||||||
tasks.add(executor.submit { loadStage(log, executor, statusEffects, fileTree["statuseffect"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, worldObjects, fileTree["object"] ?: listOf(), key(ObjectDefinition::objectName)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, species, fileTree["species"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, statusEffects, fileTree["statuseffect"] ?: listOf(), key(StatusEffectDefinition::name)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, particles, fileTree["particle"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, species, fileTree["species"] ?: listOf(), key(Species::kind)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, questTemplates, fileTree["questtemplate"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, particles, fileTree["particle"] ?: listOf(), key(ParticleDefinition::kind)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, techs, fileTree["tech"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, questTemplates, fileTree["questtemplate"] ?: listOf(), key(QuestTemplate::id)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, npcTypes, fileTree["npctype"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, techs, fileTree["tech"] ?: listOf(), key(TechDefinition::name)) })
|
||||||
// tasks.add(executor.submit { loadStage(log, executor, projectiles, ext2files["projectile"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, npcTypes, fileTree["npctype"] ?: listOf(), key(NpcTypeDefinition::type)) })
|
||||||
// tasks.add(executor.submit { loadStage(log, executor, tenants, ext2files["tenant"] ?: listOf()) })
|
// tasks.add(executor.submit { loadStage(log, executor, projectiles, ext2files["projectile"] ?: listOf(), key(ProjectileDefinition::projectileName)) })
|
||||||
tasks.add(executor.submit { loadStage(log, executor, monsterSkills, fileTree["monsterskill"] ?: listOf()) })
|
// tasks.add(executor.submit { loadStage(log, executor, tenants, ext2files["tenant"] ?: listOf(), key(TenantDefinition::name)) })
|
||||||
// tasks.add(executor.submit { loadStage(log, _monsterTypes, ext2files["monstertype"] ?: listOf()) })
|
tasks.add(executor.submit { loadStage(log, executor, monsterSkills, fileTree["monsterskill"] ?: listOf(), key(MonsterSkillDefinition::name)) })
|
||||||
|
|
||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
@ -164,19 +206,18 @@ object Registries {
|
|||||||
line.maxElements = fileList.size
|
line.maxElements = fileList.size
|
||||||
val time = System.nanoTime()
|
val time = System.nanoTime()
|
||||||
|
|
||||||
fileList.batch(executor) { listedFile ->
|
ParallelPerform(fileList.spliterator(), { listedFile ->
|
||||||
try {
|
try {
|
||||||
line.text = "Loading $listedFile"
|
line.text = "Loading $listedFile"
|
||||||
val json = objects.read(listedFile.jsonReader())
|
val json = objects.read(listedFile.jsonReader())
|
||||||
val def = AssetPathStack(listedFile.computeDirectory()) { adapter.fromJsonTree(json) }
|
val def = AssetPathStack(listedFile.computeDirectory()) { adapter.fromJsonTree(json) }
|
||||||
line.elements.incrementAndGet()
|
items.add(def.itemName, def, json, listedFile)
|
||||||
KOptional(RegistryObject(def, json, listedFile))
|
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading item definition file $listedFile", err)
|
LOGGER.error("Loading item definition file $listedFile", err)
|
||||||
|
} finally {
|
||||||
line.elements.incrementAndGet()
|
line.elements.incrementAndGet()
|
||||||
KOptional.empty()
|
|
||||||
}
|
}
|
||||||
}.forEach { items.add(it) }
|
}).fork().join()
|
||||||
|
|
||||||
line.text = "Loaded items '$ext' in ${((System.nanoTime() - time) / 1_000_000.0).toLong()}ms"
|
line.text = "Loaded items '$ext' in ${((System.nanoTime() - time) / 1_000_000.0).toLong()}ms"
|
||||||
})
|
})
|
||||||
@ -196,7 +237,7 @@ object Registries {
|
|||||||
try {
|
try {
|
||||||
line.text = ("Loading $k from $listedFile")
|
line.text = ("Loading $k from $listedFile")
|
||||||
val fn = Starbound.gson.fromJson<JsonFunction>(JsonTreeReader(v), JsonFunction::class.java)
|
val fn = Starbound.gson.fromJson<JsonFunction>(JsonTreeReader(v), JsonFunction::class.java)
|
||||||
jsonFunctions.add(fn, v, listedFile, k)
|
jsonFunctions.add(k, fn, v, listedFile)
|
||||||
} catch (err: Exception) {
|
} catch (err: Exception) {
|
||||||
LOGGER.error("Loading json function definition $k from file $listedFile", err)
|
LOGGER.error("Loading json function definition $k from file $listedFile", err)
|
||||||
}
|
}
|
||||||
@ -222,7 +263,7 @@ object Registries {
|
|||||||
try {
|
try {
|
||||||
line.text = ("Loading $k from $listedFile")
|
line.text = ("Loading $k from $listedFile")
|
||||||
val fn = Starbound.gson.fromJson<Json2Function>(JsonTreeReader(v), Json2Function::class.java)
|
val fn = Starbound.gson.fromJson<Json2Function>(JsonTreeReader(v), Json2Function::class.java)
|
||||||
json2Functions.add(fn, v, listedFile, k)
|
json2Functions.add(k, fn, v, listedFile)
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading json 2function definition $k from file $listedFile", err)
|
LOGGER.error("Loading json 2function definition $k from file $listedFile", err)
|
||||||
}
|
}
|
||||||
@ -249,7 +290,7 @@ object Registries {
|
|||||||
line.text = ("Loading $k from $listedFile")
|
line.text = ("Loading $k from $listedFile")
|
||||||
val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java)
|
val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java)
|
||||||
result.name = k
|
result.name = k
|
||||||
treasurePools.add(result, v, listedFile)
|
treasurePools.add(result.name, result, v, listedFile)
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading treasure pool definition $k from file $listedFile", err)
|
LOGGER.error("Loading treasure pool definition $k from file $listedFile", err)
|
||||||
}
|
}
|
||||||
|
350
src/main/kotlin/ru/dbotthepony/kstarbound/Registry.kt
Normal file
350
src/main/kotlin/ru/dbotthepony/kstarbound/Registry.kt
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
package ru.dbotthepony.kstarbound
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonNull
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonSyntaxException
|
||||||
|
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 it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||||
|
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||||
|
import ru.dbotthepony.kstarbound.util.Either
|
||||||
|
import java.lang.reflect.ParameterizedType
|
||||||
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
import java.util.function.Supplier
|
||||||
|
import kotlin.collections.contains
|
||||||
|
import kotlin.collections.set
|
||||||
|
import kotlin.concurrent.withLock
|
||||||
|
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
||||||
|
|
||||||
|
inline fun <reified S : Any> Registry<S>.adapter(): TypeAdapterFactory {
|
||||||
|
return object : TypeAdapterFactory {
|
||||||
|
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||||
|
val subtype = type.type as? ParameterizedType ?: return null
|
||||||
|
if (subtype.actualTypeArguments.size != 1 || subtype.actualTypeArguments[0] != S::class.java) return null
|
||||||
|
|
||||||
|
return when (type.rawType) {
|
||||||
|
Registry.Entry::class.java -> {
|
||||||
|
object : TypeAdapter<Registry.Entry<S>>() {
|
||||||
|
override fun write(out: JsonWriter, value: Registry.Entry<S>?) {
|
||||||
|
if (value != null) {
|
||||||
|
out.value(value.key)
|
||||||
|
} else {
|
||||||
|
out.nullValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): Registry.Entry<S>? {
|
||||||
|
if (`in`.consumeNull()) {
|
||||||
|
return null
|
||||||
|
} else if (`in`.peek() == JsonToken.STRING) {
|
||||||
|
return this@adapter[`in`.nextString()]
|
||||||
|
} else if (`in`.peek() == JsonToken.NUMBER) {
|
||||||
|
return this@adapter[`in`.nextInt()]
|
||||||
|
} else {
|
||||||
|
throw JsonSyntaxException("Expected registry key or registry id, got ${`in`.peek()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Registry.Ref::class.java -> {
|
||||||
|
object : TypeAdapter<Registry.Ref<S>>() {
|
||||||
|
override fun write(out: JsonWriter, value: Registry.Ref<S>?) {
|
||||||
|
if (value != null) {
|
||||||
|
value.key.map(out::value, out::value)
|
||||||
|
} else {
|
||||||
|
out.nullValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): Registry.Ref<S>? {
|
||||||
|
if (`in`.consumeNull()) {
|
||||||
|
return null
|
||||||
|
} else if (`in`.peek() == JsonToken.STRING) {
|
||||||
|
return this@adapter.ref(`in`.nextString())
|
||||||
|
} else if (`in`.peek() == JsonToken.NUMBER) {
|
||||||
|
return this@adapter.ref(`in`.nextInt())
|
||||||
|
} else {
|
||||||
|
throw JsonSyntaxException("Expected registry key or registry id, got ${`in`.peek()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> null
|
||||||
|
} as TypeAdapter<T>?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Registry<T : Any>(val name: String) {
|
||||||
|
private val keysInternal = Object2ObjectOpenHashMap<String, Impl>()
|
||||||
|
private val idsInternal = Int2ObjectOpenHashMap<Impl>()
|
||||||
|
private val keyRefs = Object2ObjectOpenHashMap<String, RefImpl>()
|
||||||
|
private val idRefs = Int2ObjectOpenHashMap<RefImpl>()
|
||||||
|
|
||||||
|
private val lock = ReentrantLock()
|
||||||
|
|
||||||
|
val keys: Object2ObjectMap<String, out Entry<T>> = Object2ObjectMaps.unmodifiable(keysInternal)
|
||||||
|
val ids: Int2ObjectMap<out Entry<T>> = Int2ObjectMaps.unmodifiable(idsInternal)
|
||||||
|
|
||||||
|
sealed class Ref<T : Any> : Supplier<Entry<T>?> {
|
||||||
|
abstract val key: Either<String, Int>
|
||||||
|
abstract val entry: Entry<T>?
|
||||||
|
abstract val registry: Registry<T>
|
||||||
|
|
||||||
|
val isPresent: Boolean
|
||||||
|
get() = value != null
|
||||||
|
|
||||||
|
val value: T?
|
||||||
|
get() = entry?.value
|
||||||
|
|
||||||
|
fun traverseJsonPath(path: String): JsonElement? {
|
||||||
|
return traverseJsonPath(path, entry?.json ?: return null)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun get(): Entry<T>? {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Entry<T : Any> : Supplier<T> {
|
||||||
|
abstract val key: String
|
||||||
|
abstract val id: Int?
|
||||||
|
abstract val value: T
|
||||||
|
abstract val json: JsonElement
|
||||||
|
abstract val file: IStarboundFile?
|
||||||
|
abstract val registry: Registry<T>
|
||||||
|
abstract val isBuiltin: Boolean
|
||||||
|
|
||||||
|
fun traverseJsonPath(path: String): JsonElement? {
|
||||||
|
return traverseJsonPath(path, json)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun get(): T {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
val jsonObject: JsonObject
|
||||||
|
get() = json as JsonObject
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class Impl(override val key: String, override var value: T, override var id: Int? = null) : Entry<T>() {
|
||||||
|
override var json: JsonElement = JsonNull.INSTANCE
|
||||||
|
override var file: IStarboundFile? = null
|
||||||
|
override var isBuiltin: Boolean = false
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return this === other
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return key.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Registry.Entry[key=$key, id=$id, registry=$name]"
|
||||||
|
}
|
||||||
|
|
||||||
|
override val registry: Registry<T>
|
||||||
|
get() = this@Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class RefImpl(override val key: Either<String, Int>) : Ref<T>() {
|
||||||
|
override var entry: Entry<T>? = null
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return this === other || other is Registry<*>.RefImpl && other.key == key && other.registry == registry
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return key.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Registry.Ref[key=$key, bound=${entry != null}, registry=$name]"
|
||||||
|
}
|
||||||
|
|
||||||
|
override val registry: Registry<T>
|
||||||
|
get() = this@Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(index: String): Entry<T>? = lock.withLock { keysInternal[index] }
|
||||||
|
operator fun get(index: Int): Entry<T>? = lock.withLock { idsInternal[index] }
|
||||||
|
|
||||||
|
fun ref(index: String): Ref<T> = lock.withLock {
|
||||||
|
keyRefs.computeIfAbsent(index, Object2ObjectFunction {
|
||||||
|
val ref = RefImpl(Either.left(it as String))
|
||||||
|
ref.entry = keysInternal[it]
|
||||||
|
ref
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ref(index: Int): Ref<T> = lock.withLock {
|
||||||
|
idRefs.computeIfAbsent(index, Int2ObjectFunction {
|
||||||
|
val ref = RefImpl(Either.right(it))
|
||||||
|
ref.entry = idsInternal[it]
|
||||||
|
ref
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun contains(index: String) = lock.withLock { index in keysInternal }
|
||||||
|
operator fun contains(index: Int) = lock.withLock { index in idsInternal }
|
||||||
|
|
||||||
|
fun validate(): Boolean {
|
||||||
|
var any = true
|
||||||
|
|
||||||
|
keyRefs.values.forEach {
|
||||||
|
if (!it.isPresent) {
|
||||||
|
LOGGER.warn("Registry '$name' reference at '${it.key.left()}' is not bound to value, expect problems")
|
||||||
|
any = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idRefs.values.forEach {
|
||||||
|
if (!it.isPresent) {
|
||||||
|
LOGGER.warn("Registry '$name' reference with ID '${it.key.right()}' is not bound to value, expect problems")
|
||||||
|
any = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return any
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(key: String, value: T, json: JsonElement, file: IStarboundFile): Entry<T> {
|
||||||
|
lock.withLock {
|
||||||
|
if (key in keysInternal) {
|
||||||
|
LOGGER.warn("Overwriting Registry entry at '$key' (new def originate from $file; old def originate from ${keysInternal[key]?.file ?: "<code>"})")
|
||||||
|
}
|
||||||
|
|
||||||
|
val entry = keysInternal.computeIfAbsent(key, Object2ObjectFunction { Impl(key, value) })
|
||||||
|
|
||||||
|
check(!entry.isBuiltin) { "Trying to redefine builtin entry" }
|
||||||
|
|
||||||
|
entry.id?.let {
|
||||||
|
idsInternal.remove(it)
|
||||||
|
idRefs[it]?.entry = null
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.id = null
|
||||||
|
entry.value = value
|
||||||
|
entry.json = json
|
||||||
|
entry.file = file
|
||||||
|
|
||||||
|
keyRefs[key]?.entry = entry
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(key: String, id: Int, value: T, json: JsonElement, file: IStarboundFile): Entry<T> {
|
||||||
|
lock.withLock {
|
||||||
|
if (key in keysInternal) {
|
||||||
|
LOGGER.warn("Overwriting Registry entry at '$key' (new def originate from $file; old def originate from ${keysInternal[key]?.file ?: "<code>"})")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id in idsInternal) {
|
||||||
|
LOGGER.warn("Overwriting Registry entry with ID '$id' (new def originate from $file; old def originate from ${idsInternal[id]?.file ?: "<code>"})")
|
||||||
|
}
|
||||||
|
|
||||||
|
val entry = keysInternal.computeIfAbsent(key, Object2ObjectFunction { Impl(key, value) })
|
||||||
|
|
||||||
|
check(!entry.isBuiltin) { "Trying to redefine builtin entry" }
|
||||||
|
|
||||||
|
entry.id?.let {
|
||||||
|
idsInternal.remove(it)
|
||||||
|
idRefs[it]?.entry = null
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.id = id
|
||||||
|
entry.value = value
|
||||||
|
entry.json = json
|
||||||
|
entry.file = file
|
||||||
|
|
||||||
|
keyRefs[key]?.entry = entry
|
||||||
|
idRefs[id]?.entry = entry
|
||||||
|
idsInternal[id] = entry
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(key: String, value: T, isBuiltin: Boolean = false): Entry<T> {
|
||||||
|
lock.withLock {
|
||||||
|
if (key in keysInternal) {
|
||||||
|
LOGGER.warn("Overwriting Registry entry at '$key' (new def originate from <code>; old def originate from ${keysInternal[key]?.file ?: "<code>"})")
|
||||||
|
}
|
||||||
|
|
||||||
|
val entry = keysInternal.computeIfAbsent(key, Object2ObjectFunction { Impl(key, value) })
|
||||||
|
|
||||||
|
check(!entry.isBuiltin || isBuiltin) { "Trying to redefine builtin entry" }
|
||||||
|
|
||||||
|
entry.id?.let {
|
||||||
|
idsInternal.remove(it)
|
||||||
|
idRefs[it]?.entry = null
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.id = null
|
||||||
|
entry.value = value
|
||||||
|
entry.json = JsonNull.INSTANCE
|
||||||
|
entry.file = null
|
||||||
|
entry.isBuiltin = isBuiltin
|
||||||
|
|
||||||
|
keyRefs[key]?.entry = entry
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(key: String, id: Int, value: T, isBuiltin: Boolean = false): Entry<T> {
|
||||||
|
lock.withLock {
|
||||||
|
if (key in keysInternal) {
|
||||||
|
LOGGER.warn("Overwriting Registry entry at '$key' (new def originate from <code>; old def originate from ${keysInternal[key]?.file ?: "<code>"})")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id in idsInternal) {
|
||||||
|
LOGGER.warn("Overwriting Registry entry with ID '$id' (new def originate from <code>; old def originate from ${idsInternal[id]?.file ?: "<code>"})")
|
||||||
|
}
|
||||||
|
|
||||||
|
val entry = keysInternal.computeIfAbsent(key, Object2ObjectFunction { Impl(key, value) })
|
||||||
|
|
||||||
|
check(!entry.isBuiltin || isBuiltin) { "Trying to redefine builtin entry" }
|
||||||
|
|
||||||
|
entry.id?.let {
|
||||||
|
idsInternal.remove(it)
|
||||||
|
idRefs[it]?.entry = null
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.id = id
|
||||||
|
entry.value = value
|
||||||
|
entry.json = JsonNull.INSTANCE
|
||||||
|
entry.file = null
|
||||||
|
entry.isBuiltin = isBuiltin
|
||||||
|
|
||||||
|
keyRefs[key]?.entry = entry
|
||||||
|
idRefs[id]?.entry = entry
|
||||||
|
idsInternal[id] = entry
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
}
|
||||||
|
}
|
@ -194,40 +194,30 @@ object Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
registerTypeAdapterFactory(Poly.Companion)
|
registerTypeAdapterFactory(Poly.Companion)
|
||||||
|
|
||||||
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
registerTypeAdapterFactory(Registries.tiles.adapter())
|
||||||
add(Registries.tiles)
|
registerTypeAdapterFactory(Registries.tileModifiers.adapter())
|
||||||
add(Registries.tileModifiers)
|
registerTypeAdapterFactory(Registries.liquid.adapter())
|
||||||
add(Registries.liquid)
|
registerTypeAdapterFactory(Registries.items.adapter())
|
||||||
add(Registries.items)
|
registerTypeAdapterFactory(Registries.species.adapter())
|
||||||
add(Registries.species)
|
registerTypeAdapterFactory(Registries.statusEffects.adapter())
|
||||||
add(Registries.statusEffects)
|
registerTypeAdapterFactory(Registries.particles.adapter())
|
||||||
add(Registries.particles)
|
registerTypeAdapterFactory(Registries.questTemplates.adapter())
|
||||||
add(Registries.questTemplates)
|
registerTypeAdapterFactory(Registries.techs.adapter())
|
||||||
add(Registries.techs)
|
registerTypeAdapterFactory(Registries.jsonFunctions.adapter())
|
||||||
add(Registries.jsonFunctions)
|
registerTypeAdapterFactory(Registries.json2Functions.adapter())
|
||||||
add(Registries.json2Functions)
|
registerTypeAdapterFactory(Registries.npcTypes.adapter())
|
||||||
add(Registries.npcTypes)
|
registerTypeAdapterFactory(Registries.projectiles.adapter())
|
||||||
add(Registries.projectiles)
|
registerTypeAdapterFactory(Registries.tenants.adapter())
|
||||||
add(Registries.tenants)
|
registerTypeAdapterFactory(Registries.treasurePools.adapter())
|
||||||
add(Registries.treasurePools)
|
registerTypeAdapterFactory(Registries.monsterSkills.adapter())
|
||||||
add(Registries.monsterSkills)
|
registerTypeAdapterFactory(Registries.monsterTypes.adapter())
|
||||||
add(Registries.monsterTypes)
|
registerTypeAdapterFactory(Registries.worldObjects.adapter())
|
||||||
add(Registries.worldObjects)
|
|
||||||
})
|
|
||||||
|
|
||||||
registerTypeAdapter(LongRangeAdapter)
|
registerTypeAdapter(LongRangeAdapter)
|
||||||
|
|
||||||
create()
|
create()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
val f = NonExistingFile("/metamaterials.config")
|
|
||||||
|
|
||||||
for (material in BuiltinMetaMaterials.MATERIALS) {
|
|
||||||
Registries.tiles.add(material, JsonNull.INSTANCE, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun item(name: String): ItemStack {
|
fun item(name: String): ItemStack {
|
||||||
return ItemStack(Registries.items[name] ?: return ItemStack.EMPTY)
|
return ItemStack(Registries.items[name] ?: return ItemStack.EMPTY)
|
||||||
}
|
}
|
||||||
@ -411,7 +401,7 @@ object Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
state.setTableFunction("recipesForItem", this) { args ->
|
state.setTableFunction("recipesForItem", this) { args ->
|
||||||
args.lua.push(JsonArray().also { a ->
|
args.lua.push(JsonArray().also { a ->
|
||||||
RecipeRegistry.output2recipes[args.getString()]?.stream()?.map { it.toJson() }?.forEach {
|
RecipeRegistry.output2recipes[args.getString()]?.stream()?.map { it.json }?.forEach {
|
||||||
a.add(it)
|
a.add(it)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -449,7 +439,7 @@ object Starbound : ISBFileLocator {
|
|||||||
args.push()
|
args.push()
|
||||||
} else {
|
} else {
|
||||||
args.push(JsonObject().also {
|
args.push(JsonObject().also {
|
||||||
it["directory"] = item.item!!.file.computeDirectory()
|
it["directory"] = item.item?.file?.computeDirectory()?.let(::JsonPrimitive) ?: JsonNull.INSTANCE
|
||||||
it["config"] = item.item!!.json
|
it["config"] = item.item!!.json
|
||||||
it["parameters"] = item.parameters
|
it["parameters"] = item.parameters
|
||||||
})
|
})
|
||||||
@ -481,7 +471,7 @@ object Starbound : ISBFileLocator {
|
|||||||
state.setTableFunction("tenantConfig", this) { args ->
|
state.setTableFunction("tenantConfig", this) { args ->
|
||||||
// Json root.tenantConfig(String tenantName)
|
// Json root.tenantConfig(String tenantName)
|
||||||
val name = args.getString()
|
val name = args.getString()
|
||||||
Registries.tenants[name]?.push(args) ?: throw NoSuchElementException("No such tenant $name")
|
args.push(Registries.tenants[name] ?: throw NoSuchElementException("No such tenant $name"))
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,11 +486,11 @@ object Starbound : ISBFileLocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args.push(Registries.tenants.values
|
args.push(Registries.tenants.keys.values
|
||||||
.stream()
|
.stream()
|
||||||
.filter { it.value.test(actualTags) }
|
.filter { it.value.test(actualTags) }
|
||||||
.sorted { a, b -> b.value.compareTo(a.value) }
|
.sorted { a, b -> b.value.compareTo(a.value) }
|
||||||
.map { it.toJson() }
|
.map { it.json }
|
||||||
.collect(JsonArrayCollector))
|
.collect(JsonArrayCollector))
|
||||||
|
|
||||||
1
|
1
|
||||||
@ -517,7 +507,7 @@ object Starbound : ISBFileLocator {
|
|||||||
liquid = Registries.liquid[id]?.value ?: throw NoSuchElementException("No such liquid with ID $id")
|
liquid = Registries.liquid[id]?.value ?: throw NoSuchElementException("No such liquid with ID $id")
|
||||||
}
|
}
|
||||||
|
|
||||||
args.lua.pushStrings(liquid.statusEffects.stream().map { it.value?.value?.name }.filterNotNull().toList())
|
args.lua.pushStrings(liquid.statusEffects.stream().map { it.value?.name }.filterNotNull().toList())
|
||||||
|
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@ -711,7 +701,7 @@ object Starbound : ISBFileLocator {
|
|||||||
state.setTableFunction("techConfig", this) { args ->
|
state.setTableFunction("techConfig", this) { args ->
|
||||||
val name = args.getString()
|
val name = args.getString()
|
||||||
val tech = Registries.techs[name] ?: throw NoSuchElementException("No such tech $name")
|
val tech = Registries.techs[name] ?: throw NoSuchElementException("No such tech $name")
|
||||||
tech.push(args)
|
args.push(tech)
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,6 +888,8 @@ object Starbound : ISBFileLocator {
|
|||||||
if (!parallel)
|
if (!parallel)
|
||||||
pool.shutdown()
|
pool.shutdown()
|
||||||
|
|
||||||
|
Registries.validate()
|
||||||
|
|
||||||
initializing = false
|
initializing = false
|
||||||
initialized = true
|
initialized = true
|
||||||
log.line("Finished loading in ${System.currentTimeMillis() - time}ms")
|
log.line("Finished loading in ${System.currentTimeMillis() - time}ms")
|
||||||
|
@ -71,9 +71,9 @@ enum class RenderLayer {
|
|||||||
|
|
||||||
fun tileLayer(isBackground: Boolean, isModifier: Boolean, tile: AbstractTileState): Point {
|
fun tileLayer(isBackground: Boolean, isModifier: Boolean, tile: AbstractTileState): Point {
|
||||||
if (isModifier) {
|
if (isModifier) {
|
||||||
return tileLayer(isBackground, true, tile.modifier?.renderParameters?.zLevel ?: 0L, tile.modifier?.modId?.toLong() ?: 0L, tile.modifierHueShift)
|
return tileLayer(isBackground, true, tile.modifier?.value?.renderParameters?.zLevel ?: 0L, tile.modifier?.value?.modId?.toLong() ?: 0L, tile.modifierHueShift)
|
||||||
} else {
|
} else {
|
||||||
return tileLayer(isBackground, false, tile.material.renderParameters.zLevel, tile.material.materialId.toLong(), tile.hueShift)
|
return tileLayer(isBackground, false, tile.material.value.renderParameters.zLevel, tile.material.value.materialId.toLong(), tile.hueShift)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,13 +95,13 @@ class TileRenderers(val client: StarboundClient) {
|
|||||||
|
|
||||||
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
|
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
|
||||||
override fun test(thisTile: AbstractTileState?, otherTile: AbstractTileState?): Boolean {
|
override fun test(thisTile: AbstractTileState?, otherTile: AbstractTileState?): Boolean {
|
||||||
return otherTile?.material == definition && thisTile?.hueShift == otherTile.hueShift
|
return otherTile?.material?.value == definition && thisTile?.hueShift == otherTile.hueShift
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ModifierEqualityTester(val definition: MaterialModifier) : EqualityRuleTester {
|
private class ModifierEqualityTester(val definition: MaterialModifier) : EqualityRuleTester {
|
||||||
override fun test(thisTile: AbstractTileState?, otherTile: AbstractTileState?): Boolean {
|
override fun test(thisTile: AbstractTileState?, otherTile: AbstractTileState?): Boolean {
|
||||||
return otherTile?.modifier == definition
|
return otherTile?.modifier?.value == definition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
|||||||
import it.unimi.dsi.fastutil.longs.LongArraySet
|
import it.unimi.dsi.fastutil.longs.LongArraySet
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh
|
import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh
|
||||||
@ -97,9 +98,9 @@ class ClientWorld(
|
|||||||
val tile = view.getTile(x, y) ?: continue
|
val tile = view.getTile(x, y) ?: continue
|
||||||
val material = tile.material
|
val material = tile.material
|
||||||
|
|
||||||
if (!material.isMeta) {
|
if (!material.value.isMeta) {
|
||||||
client.tileRenderers
|
client.tileRenderers
|
||||||
.getMaterialRenderer(material.materialName)
|
.getMaterialRenderer(material.key)
|
||||||
.tesselate(tile, view, meshes, Vector2i(x, y), isBackground = isBackground)
|
.tesselate(tile, view, meshes, Vector2i(x, y), isBackground = isBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ class ClientWorld(
|
|||||||
|
|
||||||
if (modifier != null) {
|
if (modifier != null) {
|
||||||
client.tileRenderers
|
client.tileRenderers
|
||||||
.getModifierRenderer(modifier.modName)
|
.getModifierRenderer(modifier.key)
|
||||||
.tesselate(tile, view, meshes, Vector2i(x, y), isBackground = isBackground, isModifier = true)
|
.tesselate(tile, view, meshes, Vector2i(x, y), isBackground = isBackground, isModifier = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,11 +135,11 @@ class ClientWorld(
|
|||||||
liquidIsDirty = false
|
liquidIsDirty = false
|
||||||
liquidMesh.clear()
|
liquidMesh.clear()
|
||||||
|
|
||||||
val liquidTypes = ReferenceArraySet<LiquidDefinition>()
|
val liquidTypes = ReferenceArraySet<Registry.Entry<LiquidDefinition>>()
|
||||||
|
|
||||||
for (x in 0 until renderRegionWidth) {
|
for (x in 0 until renderRegionWidth) {
|
||||||
for (y in 0 until renderRegionHeight) {
|
for (y in 0 until renderRegionHeight) {
|
||||||
view.getCell(x, y)?.liquid?.def?.let { liquidTypes.add(it) }
|
view.getCell(x, y).liquid.def?.let { liquidTypes.add(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +152,7 @@ class ClientWorld(
|
|||||||
for (y in 0 until renderRegionHeight) {
|
for (y in 0 until renderRegionHeight) {
|
||||||
val state = view.getCell(x, y)
|
val state = view.getCell(x, y)
|
||||||
|
|
||||||
if (state?.liquid?.def === type) {
|
if (state.liquid.def == type) {
|
||||||
builder.vertex(x.toFloat(), y.toFloat())
|
builder.vertex(x.toFloat(), y.toFloat())
|
||||||
builder.vertex(x.toFloat() + 1f, y.toFloat())
|
builder.vertex(x.toFloat() + 1f, y.toFloat())
|
||||||
builder.vertex(x.toFloat() + 1f, y.toFloat() + 1f)
|
builder.vertex(x.toFloat() + 1f, y.toFloat() + 1f)
|
||||||
@ -160,7 +161,7 @@ class ClientWorld(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
liquidMesh.add(Mesh(builder) to type.color)
|
liquidMesh.add(Mesh(builder) to type.value.color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import com.google.gson.reflect.TypeToken
|
|||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonToken
|
import com.google.gson.stream.JsonToken
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
@ -19,12 +20,16 @@ import ru.dbotthepony.kstarbound.util.ItemStack
|
|||||||
* Прототип [ItemStack] в JSON файлах
|
* Прототип [ItemStack] в JSON файлах
|
||||||
*/
|
*/
|
||||||
data class ItemReference(
|
data class ItemReference(
|
||||||
val item: RegistryReference<IItemDefinition>,
|
val item: Registry.Ref<IItemDefinition>,
|
||||||
val count: Long = 1,
|
val count: Long = 1,
|
||||||
val parameters: JsonObject = JsonObject()
|
val parameters: JsonObject = JsonObject()
|
||||||
) {
|
) {
|
||||||
|
init {
|
||||||
|
require(item.key.isLeft) { "Can't reference item by ID" }
|
||||||
|
}
|
||||||
|
|
||||||
fun makeStack(): ItemStack {
|
fun makeStack(): ItemStack {
|
||||||
return ItemStack(item.value ?: return ItemStack.EMPTY, count, parameters)
|
return ItemStack(item.entry ?: return ItemStack.EMPTY, count, parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Factory(val stringInterner: Interner<String> = Interner { it }) : TypeAdapterFactory {
|
class Factory(val stringInterner: Interner<String> = Interner { it }) : TypeAdapterFactory {
|
||||||
@ -33,7 +38,7 @@ data class ItemReference(
|
|||||||
return object : TypeAdapter<ItemReference>() {
|
return object : TypeAdapter<ItemReference>() {
|
||||||
private val regularObject = FactoryAdapter.createFor(ItemReference::class, JsonFactory(storesJson = false, asList = false), gson, stringInterner)
|
private val regularObject = FactoryAdapter.createFor(ItemReference::class, JsonFactory(storesJson = false, asList = false), gson, stringInterner)
|
||||||
private val regularList = FactoryAdapter.createFor(ItemReference::class, JsonFactory(storesJson = false, asList = true), gson, stringInterner)
|
private val regularList = FactoryAdapter.createFor(ItemReference::class, JsonFactory(storesJson = false, asList = true), gson, stringInterner)
|
||||||
private val references = gson.getAdapter(TypeToken.getParameterized(RegistryReference::class.java, IItemDefinition::class.java)) as TypeAdapter<RegistryReference<IItemDefinition>>
|
private val references = gson.getAdapter(TypeToken.getParameterized(Registry.Ref::class.java, IItemDefinition::class.java)) as TypeAdapter<Registry.Ref<IItemDefinition>>
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: ItemReference?) {
|
override fun write(out: JsonWriter, value: ItemReference?) {
|
||||||
if (value == null)
|
if (value == null)
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs
|
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.JsonSyntaxException
|
|
||||||
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 it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap
|
|
||||||
import org.apache.logging.log4j.LogManager
|
|
||||||
import ru.dbotthepony.kstarbound.ObjectRegistry
|
|
||||||
import ru.dbotthepony.kstarbound.RegistryObject
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
|
||||||
import java.lang.reflect.ParameterizedType
|
|
||||||
import java.util.function.Supplier
|
|
||||||
|
|
||||||
class RegistryReferenceFactory : TypeAdapterFactory {
|
|
||||||
private val types = Reference2ObjectArrayMap<Class<*>, Pair<(String) -> RegistryObject<Nothing>?, String>>()
|
|
||||||
private var isLenient = false
|
|
||||||
|
|
||||||
fun lenient(): RegistryReferenceFactory {
|
|
||||||
isLenient = true
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> add(clazz: Class<T>, resolver: (String) -> RegistryObject<T>?, name: String): RegistryReferenceFactory {
|
|
||||||
check(types.put(clazz, (resolver as (String) -> RegistryObject<Nothing>?) to name) == null) { "Already has resolver for class $clazz!" }
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> add(registry: ObjectRegistry<T>): RegistryReferenceFactory {
|
|
||||||
return add(registry.clazz.java, registry::get, registry.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T: Any> add(noinline resolver: (String) -> RegistryObject<T>?, name: String) = add(T::class.java, resolver, name)
|
|
||||||
|
|
||||||
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
|
||||||
if (type.rawType == RegistryReference::class.java) {
|
|
||||||
val ptype = type.type as? ParameterizedType ?: return null
|
|
||||||
val registryType = ptype.actualTypeArguments[0]
|
|
||||||
val resolver = types[registryType] ?: return if (isLenient) null else throw NoSuchElementException("Can't deserialize registry reference with type $registryType!")
|
|
||||||
return RegistryReferenceTypeAdapter(resolver.first, gson.getAdapter(String::class.java), resolver.second) as TypeAdapter<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RegistryReferenceTypeAdapter<T : Any>(val resolver: (String) -> RegistryObject<T>?, val strings: TypeAdapter<String>, val name: String) : TypeAdapter<RegistryReference<T>>() {
|
|
||||||
override fun write(out: JsonWriter, value: RegistryReference<T>?) {
|
|
||||||
if (value == null)
|
|
||||||
out.nullValue()
|
|
||||||
else
|
|
||||||
strings.write(out, value.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(`in`: JsonReader): RegistryReference<T>? {
|
|
||||||
if (`in`.consumeNull())
|
|
||||||
return null
|
|
||||||
|
|
||||||
if (`in`.peek() == JsonToken.STRING) {
|
|
||||||
return RegistryReference(strings.read(`in`)!!, resolver, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw JsonSyntaxException("Expecting string for registry reference, ${`in`.peek()} given, near ${`in`.path}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class RegistryReference<T : Any>(val name: String, val resolver: (String) -> RegistryObject<T>?, val registryName: String) : Supplier<RegistryObject<T>?>, () -> RegistryObject<T>?, Lazy<RegistryObject<T>?> {
|
|
||||||
private val lazy = lazy {
|
|
||||||
val result = resolver.invoke(name)
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
LOGGER.error("No such object '$name' in registry '$registryName'! Expect stuff being broken!")
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(): RegistryObject<T>? {
|
|
||||||
return lazy.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override val value: RegistryObject<T>?
|
|
||||||
get() = lazy.value
|
|
||||||
|
|
||||||
override fun isInitialized(): Boolean {
|
|
||||||
return lazy.isInitialized()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invoke(): RegistryObject<T>? {
|
|
||||||
return lazy.value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.defs
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.player.BlueprintLearnList
|
import ru.dbotthepony.kstarbound.defs.player.BlueprintLearnList
|
||||||
@ -25,7 +26,7 @@ data class Species(
|
|||||||
val undyColor: ImmutableList<ColorReplacements>,
|
val undyColor: ImmutableList<ColorReplacements>,
|
||||||
val hairColor: ImmutableList<ColorReplacements>,
|
val hairColor: ImmutableList<ColorReplacements>,
|
||||||
val genders: ImmutableList<Gender>,
|
val genders: ImmutableList<Gender>,
|
||||||
val statusEffects: ImmutableSet<RegistryReference<StatusEffectDefinition>> = ImmutableSet.of(),
|
val statusEffects: ImmutableSet<Registry.Ref<StatusEffectDefinition>> = ImmutableSet.of(),
|
||||||
) {
|
) {
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
data class Tooltip(val title: String, val subTitle: String, val description: String)
|
data class Tooltip(val title: String, val subTitle: String, val description: String)
|
||||||
@ -37,8 +38,8 @@ data class Species(
|
|||||||
val characterImage: SpriteReference,
|
val characterImage: SpriteReference,
|
||||||
val hairGroup: String? = null,
|
val hairGroup: String? = null,
|
||||||
val hair: ImmutableSet<String>,
|
val hair: ImmutableSet<String>,
|
||||||
val shirt: ImmutableSet<RegistryReference<IItemDefinition>>,
|
val shirt: ImmutableSet<Registry.Ref<IItemDefinition>>,
|
||||||
val pants: ImmutableSet<RegistryReference<IItemDefinition>>,
|
val pants: ImmutableSet<Registry.Ref<IItemDefinition>>,
|
||||||
val facialHairGroup: String? = null,
|
val facialHairGroup: String? = null,
|
||||||
val facialHair: ImmutableSet<String> = ImmutableSet.of(),
|
val facialHair: ImmutableSet<String> = ImmutableSet.of(),
|
||||||
val facialMaskGroup: String? = null,
|
val facialMaskGroup: String? = null,
|
||||||
|
@ -12,8 +12,8 @@ import com.google.gson.internal.bind.JsonTreeReader
|
|||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.ItemReference
|
import ru.dbotthepony.kstarbound.defs.ItemReference
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||||
import ru.dbotthepony.kstarbound.io.json.stream
|
import ru.dbotthepony.kstarbound.io.json.stream
|
||||||
import ru.dbotthepony.kstarbound.util.Either
|
import ru.dbotthepony.kstarbound.util.Either
|
||||||
@ -49,7 +49,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
|||||||
data class Piece(
|
data class Piece(
|
||||||
val level: Double,
|
val level: Double,
|
||||||
val pool: ImmutableList<PoolEntry> = ImmutableList.of(),
|
val pool: ImmutableList<PoolEntry> = ImmutableList.of(),
|
||||||
val fill: ImmutableList<Either<ItemReference, RegistryReference<TreasurePoolDefinition>>> = ImmutableList.of(),
|
val fill: ImmutableList<Either<ItemReference, Registry.Ref<TreasurePoolDefinition>>> = ImmutableList.of(),
|
||||||
val poolRounds: IPoolRounds = OneRound,
|
val poolRounds: IPoolRounds = OneRound,
|
||||||
// TODO: что оно делает?
|
// TODO: что оно делает?
|
||||||
// оно точно не запрещает ему появляться несколько раз за одну генерацию treasure pool
|
// оно точно не запрещает ему появляться несколько раз за одну генерацию treasure pool
|
||||||
@ -69,7 +69,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
|||||||
val stack = it.makeStack()
|
val stack = it.makeStack()
|
||||||
if (stack.isNotEmpty) result.add(stack)
|
if (stack.isNotEmpty) result.add(stack)
|
||||||
}, {
|
}, {
|
||||||
it.value?.value?.evaluate(random, actualLevel)
|
it.value?.evaluate(random, actualLevel)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
|||||||
val stack = it.makeStack()
|
val stack = it.makeStack()
|
||||||
if (stack.isNotEmpty) result.add(stack)
|
if (stack.isNotEmpty) result.add(stack)
|
||||||
}, {
|
}, {
|
||||||
it.value?.value?.evaluate(random, actualLevel)
|
it.value?.evaluate(random, actualLevel)
|
||||||
})
|
})
|
||||||
|
|
||||||
break
|
break
|
||||||
@ -145,7 +145,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
|||||||
|
|
||||||
data class PoolEntry(
|
data class PoolEntry(
|
||||||
val weight: Double,
|
val weight: Double,
|
||||||
val treasure: Either<ItemReference, RegistryReference<TreasurePoolDefinition>>
|
val treasure: Either<ItemReference, Registry.Ref<TreasurePoolDefinition>>
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
require(weight > 0.0) { "Invalid pool entry weight: $weight" }
|
require(weight > 0.0) { "Invalid pool entry weight: $weight" }
|
||||||
@ -157,7 +157,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
|||||||
if (type.rawType === TreasurePoolDefinition::class.java) {
|
if (type.rawType === TreasurePoolDefinition::class.java) {
|
||||||
return object : TypeAdapter<TreasurePoolDefinition>() {
|
return object : TypeAdapter<TreasurePoolDefinition>() {
|
||||||
private val itemAdapter = gson.getAdapter(ItemReference::class.java)
|
private val itemAdapter = gson.getAdapter(ItemReference::class.java)
|
||||||
private val poolAdapter = gson.getAdapter(TypeToken.getParameterized(RegistryReference::class.java, TreasurePoolDefinition::class.java)) as TypeAdapter<RegistryReference<TreasurePoolDefinition>>
|
private val poolAdapter = gson.getAdapter(TypeToken.getParameterized(Registry.Ref::class.java, TreasurePoolDefinition::class.java)) as TypeAdapter<Registry.Ref<TreasurePoolDefinition>>
|
||||||
private val objReader = gson.getAdapter(JsonObject::class.java)
|
private val objReader = gson.getAdapter(JsonObject::class.java)
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: TreasurePoolDefinition?) {
|
override fun write(out: JsonWriter, value: TreasurePoolDefinition?) {
|
||||||
@ -184,7 +184,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
|||||||
val things = objReader.read(`in`)
|
val things = objReader.read(`in`)
|
||||||
|
|
||||||
val pool = ImmutableList.Builder<PoolEntry>()
|
val pool = ImmutableList.Builder<PoolEntry>()
|
||||||
val fill = ImmutableList.Builder<Either<ItemReference, RegistryReference<TreasurePoolDefinition>>>()
|
val fill = ImmutableList.Builder<Either<ItemReference, Registry.Ref<TreasurePoolDefinition>>>()
|
||||||
var poolRounds: IPoolRounds = OneRound
|
var poolRounds: IPoolRounds = OneRound
|
||||||
val allowDuplication = things["allowDuplication"]?.asBoolean ?: false
|
val allowDuplication = things["allowDuplication"]?.asBoolean ?: false
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.item.api
|
package ru.dbotthepony.kstarbound.defs.item.api
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.IInventoryIcon
|
import ru.dbotthepony.kstarbound.defs.item.IInventoryIcon
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
|
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.ItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.impl.ItemDefinition
|
||||||
@ -46,7 +46,7 @@ interface IItemDefinition : IThingWithDescription {
|
|||||||
/**
|
/**
|
||||||
* При подборе предмета мгновенно заставляет игрока изучить эти рецепты крафта
|
* При подборе предмета мгновенно заставляет игрока изучить эти рецепты крафта
|
||||||
*/
|
*/
|
||||||
val learnBlueprintsOnPickup: List<RegistryReference<IItemDefinition>>
|
val learnBlueprintsOnPickup: List<Registry.Ref<IItemDefinition>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальное количество предмета в стопке
|
* Максимальное количество предмета в стопке
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.item.impl
|
package ru.dbotthepony.kstarbound.defs.item.impl
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||||
import ru.dbotthepony.kstarbound.defs.item.IInventoryIcon
|
import ru.dbotthepony.kstarbound.defs.item.IInventoryIcon
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.item.InventoryIcon
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
|
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
|
||||||
@ -22,7 +21,7 @@ data class ItemDefinition(
|
|||||||
override val category: String? = null,
|
override val category: String? = null,
|
||||||
override val inventoryIcon: ImmutableList<IInventoryIcon>? = null,
|
override val inventoryIcon: ImmutableList<IInventoryIcon>? = null,
|
||||||
override val itemTags: ImmutableList<String> = ImmutableList.of(),
|
override val itemTags: ImmutableList<String> = ImmutableList.of(),
|
||||||
override val learnBlueprintsOnPickup: ImmutableList<RegistryReference<IItemDefinition>> = ImmutableList.of(),
|
override val learnBlueprintsOnPickup: ImmutableList<Registry.Ref<IItemDefinition>> = ImmutableList.of(),
|
||||||
override val maxStack: Long = 9999L,
|
override val maxStack: Long = 9999L,
|
||||||
override val eventCategory: String? = null,
|
override val eventCategory: String? = null,
|
||||||
override val consumeOnPickup: Boolean = false,
|
override val consumeOnPickup: Boolean = false,
|
||||||
|
@ -3,11 +3,11 @@ package ru.dbotthepony.kstarbound.defs.monster
|
|||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||||
import ru.dbotthepony.kstarbound.defs.IScriptable
|
import ru.dbotthepony.kstarbound.defs.IScriptable
|
||||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||||
import ru.dbotthepony.kstarbound.defs.player.PlayerMovementParameters
|
import ru.dbotthepony.kstarbound.defs.player.PlayerMovementParameters
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
@ -24,7 +24,7 @@ data class MonsterTypeDefinition(
|
|||||||
val animation: AssetReference<AnimationDefinition>,
|
val animation: AssetReference<AnimationDefinition>,
|
||||||
// [ { "default" : "poptopTreasure", "bow" : "poptopHunting" } ],
|
// [ { "default" : "poptopTreasure", "bow" : "poptopHunting" } ],
|
||||||
// "dropPools" : [ "smallRobotTreasure" ],
|
// "dropPools" : [ "smallRobotTreasure" ],
|
||||||
val dropPools: Either<ImmutableList<ImmutableMap<String, RegistryReference<TreasurePoolDefinition>>>, ImmutableList<RegistryReference<TreasurePoolDefinition>>>,
|
val dropPools: Either<ImmutableList<ImmutableMap<String, Registry.Ref<TreasurePoolDefinition>>>, ImmutableList<Registry.Ref<TreasurePoolDefinition>>>,
|
||||||
val baseParameters: BaseParameters
|
val baseParameters: BaseParameters
|
||||||
) : IThingWithDescription by desc {
|
) : IThingWithDescription by desc {
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
|
@ -11,14 +11,11 @@ import com.google.gson.JsonSyntaxException
|
|||||||
import com.google.gson.TypeAdapter
|
import com.google.gson.TypeAdapter
|
||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.ItemReference
|
import ru.dbotthepony.kstarbound.defs.ItemReference
|
||||||
import ru.dbotthepony.kstarbound.defs.JsonReference
|
import ru.dbotthepony.kstarbound.defs.JsonReference
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.StatModifier
|
import ru.dbotthepony.kstarbound.defs.StatModifier
|
||||||
import ru.dbotthepony.kstarbound.defs.TouchDamage
|
|
||||||
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDamageConfig
|
import ru.dbotthepony.kstarbound.defs.tile.TileDamageConfig
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
@ -44,10 +41,10 @@ data class ObjectDefinition(
|
|||||||
val hasObjectItem: Boolean = true,
|
val hasObjectItem: Boolean = true,
|
||||||
val scannable: Boolean = true,
|
val scannable: Boolean = true,
|
||||||
val retainObjectParametersInItem: Boolean = false,
|
val retainObjectParametersInItem: Boolean = false,
|
||||||
val breakDropPool: RegistryReference<TreasurePoolDefinition>? = null,
|
val breakDropPool: Registry.Ref<TreasurePoolDefinition>? = null,
|
||||||
// null - not specified, empty list - always drop nothing
|
// null - not specified, empty list - always drop nothing
|
||||||
val breakDropOptions: ImmutableList<ImmutableList<ItemReference>>? = null,
|
val breakDropOptions: ImmutableList<ImmutableList<ItemReference>>? = null,
|
||||||
val smashDropPool: RegistryReference<TreasurePoolDefinition>? = null,
|
val smashDropPool: Registry.Ref<TreasurePoolDefinition>? = null,
|
||||||
val smashDropOptions: ImmutableList<ImmutableList<ItemReference>> = ImmutableList.of(),
|
val smashDropOptions: ImmutableList<ImmutableList<ItemReference>> = ImmutableList.of(),
|
||||||
//val animation: AssetReference<AnimationDefinition>? = null,
|
//val animation: AssetReference<AnimationDefinition>? = null,
|
||||||
val animation: AssetPath? = null,
|
val animation: AssetPath? = null,
|
||||||
@ -97,10 +94,10 @@ data class ObjectDefinition(
|
|||||||
val hasObjectItem: Boolean = true,
|
val hasObjectItem: Boolean = true,
|
||||||
val scannable: Boolean = true,
|
val scannable: Boolean = true,
|
||||||
val retainObjectParametersInItem: Boolean = false,
|
val retainObjectParametersInItem: Boolean = false,
|
||||||
val breakDropPool: RegistryReference<TreasurePoolDefinition>? = null,
|
val breakDropPool: Registry.Ref<TreasurePoolDefinition>? = null,
|
||||||
// null - not specified, empty list - always drop nothing
|
// null - not specified, empty list - always drop nothing
|
||||||
val breakDropOptions: ImmutableList<ImmutableList<ItemReference>>? = null,
|
val breakDropOptions: ImmutableList<ImmutableList<ItemReference>>? = null,
|
||||||
val smashDropPool: RegistryReference<TreasurePoolDefinition>? = null,
|
val smashDropPool: Registry.Ref<TreasurePoolDefinition>? = null,
|
||||||
val smashDropOptions: ImmutableList<ImmutableList<ItemReference>> = ImmutableList.of(),
|
val smashDropOptions: ImmutableList<ImmutableList<ItemReference>> = ImmutableList.of(),
|
||||||
//val animation: AssetReference<AnimationDefinition>? = null,
|
//val animation: AssetReference<AnimationDefinition>? = null,
|
||||||
val animation: AssetPath? = null,
|
val animation: AssetPath? = null,
|
||||||
|
@ -210,8 +210,8 @@ data class ObjectOrientation(
|
|||||||
val builder = ImmutableList.Builder<Pair<Vector2i, String>>()
|
val builder = ImmutableList.Builder<Pair<Vector2i, String>>()
|
||||||
|
|
||||||
when (val collisionType = obj.get("collisionType", "none").lowercase()) {
|
when (val collisionType = obj.get("collisionType", "none").lowercase()) {
|
||||||
"solid" -> collisionSpaces.forEach { builder.add(it to BuiltinMetaMaterials.OBJECT_SOLID.materialName) }
|
"solid" -> collisionSpaces.forEach { builder.add(it to BuiltinMetaMaterials.OBJECT_SOLID.key) }
|
||||||
"platform" -> collisionSpaces.forEach { if (it.y == boundingBox.maxs.y) builder.add(it to BuiltinMetaMaterials.OBJECT_PLATFORM.materialName) }
|
"platform" -> collisionSpaces.forEach { if (it.y == boundingBox.maxs.y) builder.add(it to BuiltinMetaMaterials.OBJECT_PLATFORM.key) }
|
||||||
"none" -> {}
|
"none" -> {}
|
||||||
else -> throw JsonSyntaxException("Unknown collision type $collisionType")
|
else -> throw JsonSyntaxException("Unknown collision type $collisionType")
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.particle
|
package ru.dbotthepony.kstarbound.defs.particle
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
import ru.dbotthepony.kstarbound.util.Either
|
import ru.dbotthepony.kstarbound.util.Either
|
||||||
|
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
data class ParticleCreator(
|
data class ParticleCreator(
|
||||||
val count: Int = 1,
|
val count: Int = 1,
|
||||||
val particle: Either<RegistryReference<ParticleDefinition>, IParticleConfig>,
|
val particle: Either<Registry.Ref<ParticleDefinition>, IParticleConfig>,
|
||||||
|
|
||||||
//override val offset: Vector2d? = null,
|
//override val offset: Vector2d? = null,
|
||||||
//override val position: Vector2d? = null,
|
//override val position: Vector2d? = null,
|
||||||
|
@ -10,7 +10,7 @@ import com.google.gson.stream.JsonReader
|
|||||||
import com.google.gson.stream.JsonToken
|
import com.google.gson.stream.JsonToken
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class BlueprintLearnList private constructor(private val tiers: Int2ObjectArrayM
|
|||||||
constructor(tiers: Map<Int, List<Entry>>) : this(Int2ObjectArrayMap<ImmutableList<Entry>>().also { for ((k, v) in tiers.entries) it.put(k, ImmutableList.copyOf(v)) })
|
constructor(tiers: Map<Int, List<Entry>>) : this(Int2ObjectArrayMap<ImmutableList<Entry>>().also { for ((k, v) in tiers.entries) it.put(k, ImmutableList.copyOf(v)) })
|
||||||
|
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
data class Entry(val item: RegistryReference<IItemDefinition>)
|
data class Entry(val item: Registry.Ref<IItemDefinition>)
|
||||||
|
|
||||||
operator fun get(tier: Int): List<Entry> {
|
operator fun get(tier: Int): List<Entry> {
|
||||||
return tiers.getOrDefault(tier, ImmutableList.of())
|
return tiers.getOrDefault(tier, ImmutableList.of())
|
||||||
|
@ -2,9 +2,9 @@ package ru.dbotthepony.kstarbound.defs.player
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||||
import ru.dbotthepony.kstarbound.defs.IScriptable
|
import ru.dbotthepony.kstarbound.defs.IScriptable
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
|
|
||||||
@ -13,8 +13,8 @@ data class DeploymentConfig(
|
|||||||
override val scripts: ImmutableList<AssetPath>,
|
override val scripts: ImmutableList<AssetPath>,
|
||||||
override val scriptDelta: Int,
|
override val scriptDelta: Int,
|
||||||
|
|
||||||
val starterMechSet: ImmutableMap<String, RegistryReference<IItemDefinition>>,
|
val starterMechSet: ImmutableMap<String, Registry.Ref<IItemDefinition>>,
|
||||||
val speciesStarterMechBody: ImmutableMap<String, RegistryReference<IItemDefinition>>,
|
val speciesStarterMechBody: ImmutableMap<String, Registry.Ref<IItemDefinition>>,
|
||||||
|
|
||||||
val enemyDetectRadius: Double,
|
val enemyDetectRadius: Double,
|
||||||
val enemyDetectTypeNames: ImmutableList<String>,
|
val enemyDetectTypeNames: ImmutableList<String>,
|
||||||
|
@ -4,8 +4,8 @@ import com.google.common.collect.ImmutableList
|
|||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
|
||||||
import ru.dbotthepony.kstarbound.defs.Species
|
import ru.dbotthepony.kstarbound.defs.Species
|
||||||
import ru.dbotthepony.kstarbound.util.SBPattern
|
import ru.dbotthepony.kstarbound.util.SBPattern
|
||||||
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
||||||
@ -22,14 +22,14 @@ data class PlayerDefinition(
|
|||||||
val blueprintAlreadyKnown: SBPattern,
|
val blueprintAlreadyKnown: SBPattern,
|
||||||
val collectableUnlock: SBPattern,
|
val collectableUnlock: SBPattern,
|
||||||
|
|
||||||
val species: ImmutableSet<RegistryReference<Species>>,
|
val species: ImmutableSet<Registry.Ref<Species>>,
|
||||||
val nametagColor: RGBAColor,
|
val nametagColor: RGBAColor,
|
||||||
val ageItemsEvery: Int,
|
val ageItemsEvery: Int,
|
||||||
val defaultItems: ImmutableSet<RegistryReference<IItemDefinition>>,
|
val defaultItems: ImmutableSet<Registry.Ref<IItemDefinition>>,
|
||||||
|
|
||||||
val defaultBlueprints: BlueprintLearnList,
|
val defaultBlueprints: BlueprintLearnList,
|
||||||
|
|
||||||
val defaultCodexes: ImmutableMap<String, ImmutableList<RegistryReference<IItemDefinition>>>,
|
val defaultCodexes: ImmutableMap<String, ImmutableList<Registry.Ref<IItemDefinition>>>,
|
||||||
val metaBoundBox: AABB,
|
val metaBoundBox: AABB,
|
||||||
val movementParameters: PlayerMovementParameters,
|
val movementParameters: PlayerMovementParameters,
|
||||||
val zeroGMovementParameters: PlayerMovementParameters,
|
val zeroGMovementParameters: PlayerMovementParameters,
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.tile
|
package ru.dbotthepony.kstarbound.defs.tile
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||||
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
||||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||||
|
|
||||||
object BuiltinMetaMaterials {
|
object BuiltinMetaMaterials {
|
||||||
private fun make(id: Int, name: String, collisionType: CollisionType) = TileDefinition(
|
private fun make(id: Int, name: String, collisionType: CollisionType) = Registries.tiles.add(name, id, TileDefinition(
|
||||||
materialId = id,
|
materialId = id,
|
||||||
materialName = "metamaterial:$name",
|
materialName = "metamaterial:$name",
|
||||||
descriptionData = ThingDescription.EMPTY,
|
descriptionData = ThingDescription.EMPTY,
|
||||||
@ -15,7 +17,7 @@ object BuiltinMetaMaterials {
|
|||||||
renderParameters = RenderParameters.META,
|
renderParameters = RenderParameters.META,
|
||||||
isMeta = true,
|
isMeta = true,
|
||||||
collisionKind = collisionType
|
collisionKind = collisionType
|
||||||
)
|
))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* air
|
* air
|
||||||
@ -38,7 +40,7 @@ object BuiltinMetaMaterials {
|
|||||||
val OBJECT_SOLID = make(65500, "objectsolid", CollisionType.BLOCK)
|
val OBJECT_SOLID = make(65500, "objectsolid", CollisionType.BLOCK)
|
||||||
val OBJECT_PLATFORM = make(65501, "objectplatform", CollisionType.PLATFORM)
|
val OBJECT_PLATFORM = make(65501, "objectplatform", CollisionType.PLATFORM)
|
||||||
|
|
||||||
val MATERIALS: ImmutableList<TileDefinition> = ImmutableList.of(
|
val MATERIALS: ImmutableList<Registry.Entry<TileDefinition>> = ImmutableList.of(
|
||||||
EMPTY,
|
EMPTY,
|
||||||
NULL,
|
NULL,
|
||||||
STRUCTURE,
|
STRUCTURE,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.tile
|
package ru.dbotthepony.kstarbound.defs.tile
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.StatusEffectDefinition
|
import ru.dbotthepony.kstarbound.defs.StatusEffectDefinition
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
import ru.dbotthepony.kvector.vector.RGBAColor
|
import ru.dbotthepony.kvector.vector.RGBAColor
|
||||||
@ -14,7 +14,7 @@ data class LiquidDefinition(
|
|||||||
val tickDelta: Int = 1,
|
val tickDelta: Int = 1,
|
||||||
val color: RGBAColor,
|
val color: RGBAColor,
|
||||||
val itemDrop: String? = null,
|
val itemDrop: String? = null,
|
||||||
val statusEffects: ImmutableList<RegistryReference<StatusEffectDefinition>> = ImmutableList.of(),
|
val statusEffects: ImmutableList<Registry.Ref<StatusEffectDefinition>> = ImmutableList.of(),
|
||||||
val interactions: ImmutableList<Interaction> = ImmutableList.of(),
|
val interactions: ImmutableList<Interaction> = ImmutableList.of(),
|
||||||
val texture: String,
|
val texture: String,
|
||||||
val bottomLightMix: RGBAColor,
|
val bottomLightMix: RGBAColor,
|
||||||
|
@ -17,7 +17,7 @@ import jnr.ffi.Pointer
|
|||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.system.MemoryStack
|
import org.lwjgl.system.MemoryStack
|
||||||
import org.lwjgl.system.MemoryUtil
|
import org.lwjgl.system.MemoryUtil
|
||||||
import ru.dbotthepony.kstarbound.RegistryObject
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
|
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
|
||||||
import ru.dbotthepony.kvector.api.IStruct2i
|
import ru.dbotthepony.kvector.api.IStruct2i
|
||||||
@ -595,8 +595,8 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
fun push(value: Boolean) = this@LuaState.push(value)
|
fun push(value: Boolean) = this@LuaState.push(value)
|
||||||
fun push(value: String?) = this@LuaState.push(value)
|
fun push(value: String?) = this@LuaState.push(value)
|
||||||
fun push(value: JsonElement?) = this@LuaState.push(value)
|
fun push(value: JsonElement?) = this@LuaState.push(value)
|
||||||
fun push(value: RegistryObject<*>?) = this@LuaState.push(value)
|
fun push(value: Registry.Entry<*>?) = this@LuaState.push(value)
|
||||||
fun pushFull(value: RegistryObject<*>?) = this@LuaState.pushFull(value)
|
fun pushFull(value: Registry.Entry<*>?) = this@LuaState.pushFull(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -902,7 +902,8 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
this.setTableValue(table)
|
this.setTableValue(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTableValue(key: String, value: String) {
|
fun setTableValue(key: String, value: String?) {
|
||||||
|
value ?: return
|
||||||
val table = this.stackTop
|
val table = this.stackTop
|
||||||
this.push(key)
|
this.push(key)
|
||||||
this.push(value)
|
this.push(value)
|
||||||
@ -1058,20 +1059,20 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun push(value: RegistryObject<*>?) {
|
fun push(value: Registry.Entry<*>?) {
|
||||||
if (value == null)
|
if (value == null)
|
||||||
push()
|
push()
|
||||||
else
|
else
|
||||||
push(value.toJson())
|
push(value.json)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushFull(value: RegistryObject<*>?) {
|
fun pushFull(value: Registry.Entry<*>?) {
|
||||||
if (value == null)
|
if (value == null)
|
||||||
push()
|
push()
|
||||||
else {
|
else {
|
||||||
pushTable(hashSize = 2)
|
pushTable(hashSize = 2)
|
||||||
setTableValue("path", value.file.computeFullPath())
|
setTableValue("path", value.file?.computeFullPath())
|
||||||
setTableValue("config", value.toJson())
|
setTableValue("config", value.json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
import ru.dbotthepony.kstarbound.RegistryObject
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.player.TechDefinition
|
import ru.dbotthepony.kstarbound.defs.player.TechDefinition
|
||||||
import ru.dbotthepony.kstarbound.lua.LuaState
|
import ru.dbotthepony.kstarbound.lua.LuaState
|
||||||
@ -48,9 +48,9 @@ class Avatar(val uniqueId: UUID) {
|
|||||||
|
|
||||||
var cursorItem = ItemStack.EMPTY
|
var cursorItem = ItemStack.EMPTY
|
||||||
|
|
||||||
private val availableTechs = ObjectOpenHashSet<RegistryObject<TechDefinition>>()
|
private val availableTechs = ObjectOpenHashSet<Registry.Entry<TechDefinition>>()
|
||||||
private val enabledTechs = ObjectOpenHashSet<RegistryObject<TechDefinition>>()
|
private val enabledTechs = ObjectOpenHashSet<Registry.Entry<TechDefinition>>()
|
||||||
private val equippedTechs = Object2ObjectOpenHashMap<String, RegistryObject<TechDefinition>>()
|
private val equippedTechs = Object2ObjectOpenHashMap<String, Registry.Entry<TechDefinition>>()
|
||||||
|
|
||||||
private val knownBlueprints = ObjectOpenHashSet<ItemStack>()
|
private val knownBlueprints = ObjectOpenHashSet<ItemStack>()
|
||||||
// С подписью NEW
|
// С подписью NEW
|
||||||
|
@ -51,6 +51,22 @@ class Either<L, R> private constructor(val left: KOptional<L>, val right: KOptio
|
|||||||
return orElse.invoke()
|
return orElse.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return other === this || other is Either<*, *> && other.left == left && other.right == right
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return left.hashCode() * 31 + right.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
if (isLeft) {
|
||||||
|
return "Either.left[${left.value}]"
|
||||||
|
} else {
|
||||||
|
return "Either.right[${right.value}]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun <L, R> left(value: L): Either<L, R> {
|
fun <L, R> left(value: L): Either<L, R> {
|
||||||
|
@ -5,17 +5,16 @@ import com.google.gson.JsonPrimitive
|
|||||||
import com.google.gson.TypeAdapter
|
import com.google.gson.TypeAdapter
|
||||||
import com.google.gson.internal.bind.TypeAdapters
|
import com.google.gson.internal.bind.TypeAdapters
|
||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonToken
|
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
import ru.dbotthepony.kstarbound.RegistryObject
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||||
|
|
||||||
class ItemStack private constructor(item: RegistryObject<IItemDefinition>?, count: Long, val parameters: JsonObject, marker: Unit) {
|
class ItemStack private constructor(item: Registry.Entry<IItemDefinition>?, count: Long, val parameters: JsonObject, marker: Unit) {
|
||||||
constructor(item: RegistryObject<IItemDefinition>, count: Long = 1L, parameters: JsonObject = JsonObject()) : this(item, count, parameters, Unit)
|
constructor(item: Registry.Entry<IItemDefinition>, count: Long = 1L, parameters: JsonObject = JsonObject()) : this(item, count, parameters, Unit)
|
||||||
|
|
||||||
var item: RegistryObject<IItemDefinition>? = item
|
var item: Registry.Entry<IItemDefinition>? = item
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var size = count
|
var size = count
|
||||||
|
@ -67,7 +67,7 @@ class KOptional<T> private constructor(private val _value: T, val isPresent: Boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return _value.hashCode()
|
return _value.hashCode() + 43839429
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
@ -64,7 +64,7 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
|
|||||||
val parent = this@LightCalculator.parent.getCell(x, y) ?: return@lazy 0f
|
val parent = this@LightCalculator.parent.getCell(x, y) ?: return@lazy 0f
|
||||||
val lightBlockStrength: Float
|
val lightBlockStrength: Float
|
||||||
|
|
||||||
if (parent.foreground.material.renderParameters.lightTransparent) {
|
if (parent.foreground.material.value.renderParameters.lightTransparent) {
|
||||||
lightBlockStrength = 0f
|
lightBlockStrength = 0f
|
||||||
} else {
|
} else {
|
||||||
lightBlockStrength = 1f
|
lightBlockStrength = 1f
|
||||||
|
@ -47,7 +47,7 @@ fun interface TileRayFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val NeverFilter = TileRayFilter { state, fraction, x, y, normal, borderX, borderY -> RayFilterResult.CONTINUE }
|
val NeverFilter = TileRayFilter { state, fraction, x, y, normal, borderX, borderY -> RayFilterResult.CONTINUE }
|
||||||
val NonEmptyFilter = TileRayFilter { state, fraction, x, y, normal, borderX, borderY -> RayFilterResult.of(!state.foreground.material.collisionKind.isEmpty) }
|
val NonEmptyFilter = TileRayFilter { state, fraction, x, y, normal, borderX, borderY -> RayFilterResult.of(!state.foreground.material.value.collisionKind.isEmpty) }
|
||||||
|
|
||||||
fun ICellAccess.castRay(startPos: Vector2d, direction: Vector2d, length: Double, filter: TileRayFilter) = castRay(startPos, startPos + direction * length, filter)
|
fun ICellAccess.castRay(startPos: Vector2d, direction: Vector2d, length: Double, filter: TileRayFilter) = castRay(startPos, startPos + direction * length, filter)
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
|
|
||||||
result.add(CollisionPoly(
|
result.add(CollisionPoly(
|
||||||
BLOCK_POLY + Vector2d(x.toDouble(), y.toDouble()),
|
BLOCK_POLY + Vector2d(x.toDouble(), y.toDouble()),
|
||||||
cell.foreground.material.collisionKind,
|
cell.foreground.material.value.collisionKind,
|
||||||
//velocity = Vector2d(EARTH_FREEFALL_ACCELERATION, 0.0)
|
//velocity = Vector2d(EARTH_FREEFALL_ACCELERATION, 0.0)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package ru.dbotthepony.kstarbound.world.api
|
package ru.dbotthepony.kstarbound.world.api
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||||
import ru.dbotthepony.kstarbound.util.HashTableInterner
|
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
|
||||||
sealed class AbstractLiquidState {
|
sealed class AbstractLiquidState {
|
||||||
abstract val def: LiquidDefinition?
|
abstract val def: Registry.Entry<LiquidDefinition>?
|
||||||
abstract val level: Float
|
abstract val level: Float
|
||||||
abstract val pressure: Float
|
abstract val pressure: Float
|
||||||
abstract val isInfinite: Boolean
|
abstract val isInfinite: Boolean
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package ru.dbotthepony.kstarbound.world.api
|
package ru.dbotthepony.kstarbound.world.api
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
|
||||||
sealed class AbstractTileState {
|
sealed class AbstractTileState {
|
||||||
abstract val material: TileDefinition
|
abstract val material: Registry.Entry<TileDefinition>
|
||||||
abstract val modifier: MaterialModifier?
|
abstract val modifier: Registry.Entry<MaterialModifier>?
|
||||||
abstract val color: TileColor
|
abstract val color: TileColor
|
||||||
abstract val hueShift: Float
|
abstract val hueShift: Float
|
||||||
abstract val modifierHueShift: Float
|
abstract val modifierHueShift: Float
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package ru.dbotthepony.kstarbound.world.api
|
package ru.dbotthepony.kstarbound.world.api
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||||
|
|
||||||
data class ImmutableLiquidState(
|
data class ImmutableLiquidState(
|
||||||
override val def: LiquidDefinition? = null,
|
override val def: Registry.Entry<LiquidDefinition>? = null,
|
||||||
override val level: Float = 0f,
|
override val level: Float = 0f,
|
||||||
override val pressure: Float = 0f,
|
override val pressure: Float = 0f,
|
||||||
override val isInfinite: Boolean = false,
|
override val isInfinite: Boolean = false,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package ru.dbotthepony.kstarbound.world.api
|
package ru.dbotthepony.kstarbound.world.api
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||||
|
|
||||||
data class ImmutableTileState(
|
data class ImmutableTileState(
|
||||||
override var material: TileDefinition = BuiltinMetaMaterials.NULL,
|
override var material: Registry.Entry<TileDefinition> = BuiltinMetaMaterials.NULL,
|
||||||
override var modifier: MaterialModifier? = null,
|
override var modifier: Registry.Entry<MaterialModifier>? = null,
|
||||||
override var color: TileColor = TileColor.DEFAULT,
|
override var color: TileColor = TileColor.DEFAULT,
|
||||||
override var hueShift: Float = 0f,
|
override var hueShift: Float = 0f,
|
||||||
override var modifierHueShift: Float = 0f,
|
override var modifierHueShift: Float = 0f,
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
package ru.dbotthepony.kstarbound.world.api
|
package ru.dbotthepony.kstarbound.world.api
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
|
||||||
data class MutableLiquidState(
|
data class MutableLiquidState(
|
||||||
override var def: LiquidDefinition? = null,
|
override var def: Registry.Entry<LiquidDefinition>? = null,
|
||||||
override var level: Float = 0f,
|
override var level: Float = 0f,
|
||||||
override var pressure: Float = 0f,
|
override var pressure: Float = 0f,
|
||||||
override var isInfinite: Boolean = false,
|
override var isInfinite: Boolean = false,
|
||||||
) : AbstractLiquidState() {
|
) : AbstractLiquidState() {
|
||||||
fun read(stream: DataInputStream): MutableLiquidState {
|
fun read(stream: DataInputStream): MutableLiquidState {
|
||||||
def = Registries.liquid[stream.readUnsignedByte()]?.value
|
def = Registries.liquid[stream.readUnsignedByte()]
|
||||||
level = stream.readFloat()
|
level = stream.readFloat()
|
||||||
pressure = stream.readFloat()
|
pressure = stream.readFloat()
|
||||||
isInfinite = stream.readBoolean()
|
isInfinite = stream.readBoolean()
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package ru.dbotthepony.kstarbound.world.api
|
package ru.dbotthepony.kstarbound.world.api
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
|
||||||
data class MutableTileState(
|
data class MutableTileState(
|
||||||
override var material: TileDefinition = BuiltinMetaMaterials.NULL,
|
override var material: Registry.Entry<TileDefinition> = BuiltinMetaMaterials.NULL,
|
||||||
override var modifier: MaterialModifier? = null,
|
override var modifier: Registry.Entry<MaterialModifier>? = null,
|
||||||
override var color: TileColor = TileColor.DEFAULT,
|
override var color: TileColor = TileColor.DEFAULT,
|
||||||
override var hueShift: Float = 0f,
|
override var hueShift: Float = 0f,
|
||||||
override var modifierHueShift: Float = 0f,
|
override var modifierHueShift: Float = 0f,
|
||||||
@ -49,10 +50,10 @@ data class MutableTileState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun read(stream: DataInputStream): MutableTileState {
|
fun read(stream: DataInputStream): MutableTileState {
|
||||||
material = Registries.tiles[stream.readUnsignedShort()]?.value ?: BuiltinMetaMaterials.EMPTY
|
material = Registries.tiles[stream.readUnsignedShort()] ?: BuiltinMetaMaterials.EMPTY
|
||||||
setHueShift(stream.read())
|
setHueShift(stream.read())
|
||||||
color = TileColor.of(stream.read())
|
color = TileColor.of(stream.read())
|
||||||
modifier = Registries.tileModifiers[stream.readUnsignedShort()]?.value
|
modifier = Registries.tileModifiers[stream.readUnsignedShort()]
|
||||||
setModHueShift(stream.read())
|
setModHueShift(stream.read())
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import com.google.gson.TypeAdapter
|
|||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
import ru.dbotthepony.kstarbound.RegistryObject
|
import ru.dbotthepony.kstarbound.Registry
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.client.world.ClientWorld
|
import ru.dbotthepony.kstarbound.client.world.ClientWorld
|
||||||
import ru.dbotthepony.kstarbound.defs.Drawable
|
import ru.dbotthepony.kstarbound.defs.Drawable
|
||||||
@ -26,9 +26,9 @@ import ru.dbotthepony.kvector.vector.Vector2i
|
|||||||
|
|
||||||
open class WorldObject(
|
open class WorldObject(
|
||||||
val world: World<*, *>,
|
val world: World<*, *>,
|
||||||
val prototype: RegistryObject<ObjectDefinition>,
|
val prototype: Registry.Entry<ObjectDefinition>,
|
||||||
val pos: Vector2i,
|
val pos: Vector2i,
|
||||||
) : JsonDriven(prototype.file.computeDirectory()) {
|
) : JsonDriven(prototype.file?.computeDirectory() ?: "/") {
|
||||||
constructor(world: World<*, *>, data: JsonObject) : this(
|
constructor(world: World<*, *>, data: JsonObject) : this(
|
||||||
world,
|
world,
|
||||||
Registries.worldObjects[data["name"]?.asString ?: throw IllegalArgumentException("Missing object name")] ?: throw IllegalArgumentException("No such object defined for '${data["name"]}'"),
|
Registries.worldObjects[data["name"]?.asString ?: throw IllegalArgumentException("Missing object name")] ?: throw IllegalArgumentException("No such object defined for '${data["name"]}'"),
|
||||||
|
Loading…
Reference in New Issue
Block a user