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)
|
||||
|
||||
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" }
|
||||
|
||||
if (batchSize == 1 || size <= batchSize) {
|
||||
val tasks = ArrayList<ForkJoinTask<KOptional<RegistryObject<T>>>>()
|
||||
val tasks = ArrayList<ForkJoinTask<KOptional<T>>>()
|
||||
|
||||
for (listedFile in this) {
|
||||
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 }
|
||||
}
|
||||
|
||||
val batches = ArrayList<ForkJoinTask<List<KOptional<RegistryObject<T>>>>>()
|
||||
val batches = ArrayList<ForkJoinTask<List<KOptional<T>>>>()
|
||||
var batch = ArrayList<IStarboundFile>(batchSize)
|
||||
|
||||
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.QuestInstance
|
||||
import ru.dbotthepony.kstarbound.util.JVMTimeSource
|
||||
import ru.dbotthepony.kstarbound.world.api.AbstractCell
|
||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||
import ru.dbotthepony.kstarbound.io.json.VersionedJson
|
||||
import ru.dbotthepony.kstarbound.io.readVarInt
|
||||
@ -118,7 +117,7 @@ fun main() {
|
||||
val rand = Random()
|
||||
|
||||
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.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
|
||||
|
||||
import com.google.gson.Gson
|
||||
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.Object2ObjectOpenHashMap
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||
import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
||||
import ru.dbotthepony.kstarbound.util.KOptional
|
||||
import java.util.Collections
|
||||
import java.util.LinkedList
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ExecutorService
|
||||
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
||||
import java.util.*
|
||||
import java.util.concurrent.ForkJoinPool
|
||||
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 {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
private val recipesInternal = ArrayList<RegistryObject<RecipeDefinition>>()
|
||||
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>>>()
|
||||
data class Entry(val value: RecipeDefinition, val json: JsonElement, val file: IStarboundFile)
|
||||
|
||||
val recipes: List<RegistryObject<RecipeDefinition>> = Collections.unmodifiableList(recipesInternal)
|
||||
val group2recipes: Map<String, List<RegistryObject<RecipeDefinition>>> = Collections.unmodifiableMap(group2recipesBacking)
|
||||
val output2recipes: Map<String, List<RegistryObject<RecipeDefinition>>> = Collections.unmodifiableMap(output2recipesBacking)
|
||||
val input2recipes: Map<String, List<RegistryObject<RecipeDefinition>>> = Collections.unmodifiableMap(input2recipesBacking)
|
||||
private val recipesInternal = ArrayList<Entry>()
|
||||
private val group2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
|
||||
private val group2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
|
||||
private val output2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
|
||||
private val output2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
|
||||
private val input2recipesInternal = Object2ObjectOpenHashMap<String, ArrayList<Entry>>()
|
||||
private val input2recipesBacking = Object2ObjectOpenHashMap<String, List<Entry>>()
|
||||
|
||||
fun add(recipe: RegistryObject<RecipeDefinition>) {
|
||||
val value = recipe.value
|
||||
recipesInternal.add(recipe)
|
||||
val recipes: List<Entry> = Collections.unmodifiableList(recipesInternal)
|
||||
val group2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(group2recipesBacking)
|
||||
val output2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(output2recipesBacking)
|
||||
val input2recipes: Map<String, List<Entry>> = Collections.unmodifiableMap(input2recipesBacking)
|
||||
|
||||
for (group in value.groups) {
|
||||
group2recipesInternal.computeIfAbsent(group, Object2ObjectFunction { p ->
|
||||
LinkedList<RegistryObject<RecipeDefinition>>().also {
|
||||
group2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
}
|
||||
}).add(recipe)
|
||||
}
|
||||
private val lock = ReentrantLock()
|
||||
|
||||
output2recipesInternal.computeIfAbsent(value.output.item.name, Object2ObjectFunction { p ->
|
||||
LinkedList<RegistryObject<RecipeDefinition>>().also {
|
||||
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
fun add(recipe: Entry) {
|
||||
lock.withLock {
|
||||
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) {
|
||||
input2recipesInternal.computeIfAbsent(input.item.name, Object2ObjectFunction { p ->
|
||||
LinkedList<RegistryObject<RecipeDefinition>>().also {
|
||||
input2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
output2recipesInternal.computeIfAbsent(value.output.item.key.left(), Object2ObjectFunction { p ->
|
||||
ArrayList<Entry>(1).also {
|
||||
output2recipesBacking[p as String] = Collections.unmodifiableList(it)
|
||||
}
|
||||
}).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")
|
||||
val json = elements.read(listedFile.jsonReader())
|
||||
val value = recipes.fromJsonTree(json)
|
||||
line.elements.incrementAndGet()
|
||||
KOptional(RegistryObject(value, json, listedFile))
|
||||
KOptional.of(Entry(value, json, listedFile))
|
||||
} catch (err: Throwable) {
|
||||
LOGGER.error("Loading recipe definition file $listedFile", err)
|
||||
line.elements.incrementAndGet()
|
||||
KOptional.empty()
|
||||
} finally {
|
||||
line.elements.incrementAndGet()
|
||||
}
|
||||
}.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.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.KOptional
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ExecutorService
|
||||
import ru.dbotthepony.kstarbound.util.ParallelPerform
|
||||
import java.util.concurrent.ForkJoinPool
|
||||
import java.util.concurrent.ForkJoinTask
|
||||
import java.util.concurrent.Future
|
||||
|
||||
object Registries {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
val tiles = ObjectRegistry("tiles", TileDefinition::materialName, TileDefinition::materialId)
|
||||
val tileModifiers = ObjectRegistry("tile modifiers", MaterialModifier::modName, MaterialModifier::modId)
|
||||
val liquid = ObjectRegistry("liquid", LiquidDefinition::name, LiquidDefinition::liquidId)
|
||||
val species = ObjectRegistry("species", Species::kind)
|
||||
val statusEffects = ObjectRegistry("status effects", StatusEffectDefinition::name)
|
||||
val particles = ObjectRegistry("particles", ParticleDefinition::kind)
|
||||
val items = ObjectRegistry("items", IItemDefinition::itemName)
|
||||
val questTemplates = ObjectRegistry("quest templates", QuestTemplate::id)
|
||||
val techs = ObjectRegistry("techs", TechDefinition::name)
|
||||
val jsonFunctions = ObjectRegistry<JsonFunction>("json functions")
|
||||
val json2Functions = ObjectRegistry<Json2Function>("json 2functions")
|
||||
val npcTypes = ObjectRegistry("npc types", NpcTypeDefinition::type)
|
||||
val projectiles = ObjectRegistry("projectiles", ProjectileDefinition::projectileName)
|
||||
val tenants = ObjectRegistry("tenants", TenantDefinition::name)
|
||||
val treasurePools = ObjectRegistry("treasure pools", TreasurePoolDefinition::name)
|
||||
val monsterSkills = ObjectRegistry("monster skills", MonsterSkillDefinition::name)
|
||||
val monsterTypes = ObjectRegistry("monster types", MonsterTypeDefinition::type)
|
||||
val worldObjects = ObjectRegistry("objects", ObjectDefinition::objectName)
|
||||
val tiles = Registry<TileDefinition>("tiles")
|
||||
val tileModifiers = Registry<MaterialModifier>("tile modifiers")
|
||||
val liquid = Registry<LiquidDefinition>("liquid")
|
||||
val species = Registry<Species>("species")
|
||||
val statusEffects = Registry<StatusEffectDefinition>("status effects")
|
||||
val particles = Registry<ParticleDefinition>("particles")
|
||||
val items = Registry<IItemDefinition>("items")
|
||||
val questTemplates = Registry<QuestTemplate>("quest templates")
|
||||
val techs = Registry<TechDefinition>("techs")
|
||||
val jsonFunctions = Registry<JsonFunction>("json functions")
|
||||
val json2Functions = Registry<Json2Function>("json 2functions")
|
||||
val npcTypes = Registry<NpcTypeDefinition>("npc types")
|
||||
val projectiles = Registry<ProjectileDefinition>("projectiles")
|
||||
val tenants = Registry<TenantDefinition>("tenants")
|
||||
val treasurePools = Registry<TreasurePoolDefinition>("treasure pools")
|
||||
val monsterSkills = Registry<MonsterSkillDefinition>("monster skills")
|
||||
val monsterTypes = Registry<MonsterTypeDefinition>("monster types")
|
||||
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(
|
||||
log: ILoadingLog,
|
||||
@ -81,8 +112,9 @@ object Registries {
|
||||
private inline fun <reified T : Any> loadStage(
|
||||
log: ILoadingLog,
|
||||
executor: ForkJoinPool,
|
||||
registry: ObjectRegistry<T>,
|
||||
registry: Registry<T>,
|
||||
files: List<IStarboundFile>,
|
||||
noinline keyProvider: (T) -> Pair<String, Int?>,
|
||||
name: String = registry.name
|
||||
) {
|
||||
val adapter = Starbound.gson.getAdapter(T::class.java)
|
||||
@ -95,19 +127,29 @@ object Registries {
|
||||
try {
|
||||
it.text = "Loading $listedFile"
|
||||
|
||||
val result = AssetPathStack(listedFile.computeDirectory()) {
|
||||
AssetPathStack(listedFile.computeDirectory()) {
|
||||
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(result)
|
||||
KOptional.of {
|
||||
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) {
|
||||
LOGGER.error("Loading ${registry.name} definition file $listedFile", err)
|
||||
it.elements.incrementAndGet()
|
||||
LOGGER.error("Loading ${registry.name} definition file $listedFile", err);
|
||||
KOptional.empty()
|
||||
} finally {
|
||||
it.elements.incrementAndGet()
|
||||
}
|
||||
}.forEach { registry.add(it) }
|
||||
}.forEach { it.invoke() }
|
||||
}, 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, { 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, tileModifiers, fileTree["matmod"] ?: listOf()) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, liquid, fileTree["liquid"] ?: listOf()) })
|
||||
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, species, fileTree["species"] ?: listOf()) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, particles, fileTree["particle"] ?: listOf()) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, questTemplates, fileTree["questtemplate"] ?: listOf()) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, techs, fileTree["tech"] ?: listOf()) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, npcTypes, fileTree["npctype"] ?: listOf()) })
|
||||
// tasks.add(executor.submit { loadStage(log, executor, projectiles, ext2files["projectile"] ?: listOf()) })
|
||||
// tasks.add(executor.submit { loadStage(log, executor, tenants, ext2files["tenant"] ?: listOf()) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, monsterSkills, fileTree["monsterskill"] ?: listOf()) })
|
||||
// tasks.add(executor.submit { loadStage(log, _monsterTypes, ext2files["monstertype"] ?: 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(), key(MaterialModifier::modName, MaterialModifier::modId)) })
|
||||
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(), key(ObjectDefinition::objectName)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, statusEffects, fileTree["statuseffect"] ?: listOf(), key(StatusEffectDefinition::name)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, species, fileTree["species"] ?: listOf(), key(Species::kind)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, particles, fileTree["particle"] ?: listOf(), key(ParticleDefinition::kind)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, questTemplates, fileTree["questtemplate"] ?: listOf(), key(QuestTemplate::id)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, techs, fileTree["tech"] ?: listOf(), key(TechDefinition::name)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, npcTypes, fileTree["npctype"] ?: listOf(), key(NpcTypeDefinition::type)) })
|
||||
// tasks.add(executor.submit { loadStage(log, executor, projectiles, ext2files["projectile"] ?: listOf(), key(ProjectileDefinition::projectileName)) })
|
||||
// tasks.add(executor.submit { loadStage(log, executor, tenants, ext2files["tenant"] ?: listOf(), key(TenantDefinition::name)) })
|
||||
tasks.add(executor.submit { loadStage(log, executor, monsterSkills, fileTree["monsterskill"] ?: listOf(), key(MonsterSkillDefinition::name)) })
|
||||
|
||||
return tasks
|
||||
}
|
||||
@ -164,19 +206,18 @@ object Registries {
|
||||
line.maxElements = fileList.size
|
||||
val time = System.nanoTime()
|
||||
|
||||
fileList.batch(executor) { listedFile ->
|
||||
ParallelPerform(fileList.spliterator(), { listedFile ->
|
||||
try {
|
||||
line.text = "Loading $listedFile"
|
||||
val json = objects.read(listedFile.jsonReader())
|
||||
val def = AssetPathStack(listedFile.computeDirectory()) { adapter.fromJsonTree(json) }
|
||||
line.elements.incrementAndGet()
|
||||
KOptional(RegistryObject(def, json, listedFile))
|
||||
items.add(def.itemName, def, json, listedFile)
|
||||
} catch (err: Throwable) {
|
||||
LOGGER.error("Loading item definition file $listedFile", err)
|
||||
} finally {
|
||||
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"
|
||||
})
|
||||
@ -196,7 +237,7 @@ object Registries {
|
||||
try {
|
||||
line.text = ("Loading $k from $listedFile")
|
||||
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) {
|
||||
LOGGER.error("Loading json function definition $k from file $listedFile", err)
|
||||
}
|
||||
@ -222,7 +263,7 @@ object Registries {
|
||||
try {
|
||||
line.text = ("Loading $k from $listedFile")
|
||||
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) {
|
||||
LOGGER.error("Loading json 2function definition $k from file $listedFile", err)
|
||||
}
|
||||
@ -249,7 +290,7 @@ object Registries {
|
||||
line.text = ("Loading $k from $listedFile")
|
||||
val result = Starbound.gson.fromJson<TreasurePoolDefinition>(JsonTreeReader(v), TreasurePoolDefinition::class.java)
|
||||
result.name = k
|
||||
treasurePools.add(result, v, listedFile)
|
||||
treasurePools.add(result.name, result, v, listedFile)
|
||||
} catch (err: Throwable) {
|
||||
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(with(RegistryReferenceFactory()) {
|
||||
add(Registries.tiles)
|
||||
add(Registries.tileModifiers)
|
||||
add(Registries.liquid)
|
||||
add(Registries.items)
|
||||
add(Registries.species)
|
||||
add(Registries.statusEffects)
|
||||
add(Registries.particles)
|
||||
add(Registries.questTemplates)
|
||||
add(Registries.techs)
|
||||
add(Registries.jsonFunctions)
|
||||
add(Registries.json2Functions)
|
||||
add(Registries.npcTypes)
|
||||
add(Registries.projectiles)
|
||||
add(Registries.tenants)
|
||||
add(Registries.treasurePools)
|
||||
add(Registries.monsterSkills)
|
||||
add(Registries.monsterTypes)
|
||||
add(Registries.worldObjects)
|
||||
})
|
||||
registerTypeAdapterFactory(Registries.tiles.adapter())
|
||||
registerTypeAdapterFactory(Registries.tileModifiers.adapter())
|
||||
registerTypeAdapterFactory(Registries.liquid.adapter())
|
||||
registerTypeAdapterFactory(Registries.items.adapter())
|
||||
registerTypeAdapterFactory(Registries.species.adapter())
|
||||
registerTypeAdapterFactory(Registries.statusEffects.adapter())
|
||||
registerTypeAdapterFactory(Registries.particles.adapter())
|
||||
registerTypeAdapterFactory(Registries.questTemplates.adapter())
|
||||
registerTypeAdapterFactory(Registries.techs.adapter())
|
||||
registerTypeAdapterFactory(Registries.jsonFunctions.adapter())
|
||||
registerTypeAdapterFactory(Registries.json2Functions.adapter())
|
||||
registerTypeAdapterFactory(Registries.npcTypes.adapter())
|
||||
registerTypeAdapterFactory(Registries.projectiles.adapter())
|
||||
registerTypeAdapterFactory(Registries.tenants.adapter())
|
||||
registerTypeAdapterFactory(Registries.treasurePools.adapter())
|
||||
registerTypeAdapterFactory(Registries.monsterSkills.adapter())
|
||||
registerTypeAdapterFactory(Registries.monsterTypes.adapter())
|
||||
registerTypeAdapterFactory(Registries.worldObjects.adapter())
|
||||
|
||||
registerTypeAdapter(LongRangeAdapter)
|
||||
|
||||
create()
|
||||
}
|
||||
|
||||
init {
|
||||
val f = NonExistingFile("/metamaterials.config")
|
||||
|
||||
for (material in BuiltinMetaMaterials.MATERIALS) {
|
||||
Registries.tiles.add(material, JsonNull.INSTANCE, f)
|
||||
}
|
||||
}
|
||||
|
||||
fun item(name: String): ItemStack {
|
||||
return ItemStack(Registries.items[name] ?: return ItemStack.EMPTY)
|
||||
}
|
||||
@ -411,7 +401,7 @@ object Starbound : ISBFileLocator {
|
||||
|
||||
state.setTableFunction("recipesForItem", this) { args ->
|
||||
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)
|
||||
}
|
||||
})
|
||||
@ -449,7 +439,7 @@ object Starbound : ISBFileLocator {
|
||||
args.push()
|
||||
} else {
|
||||
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["parameters"] = item.parameters
|
||||
})
|
||||
@ -481,7 +471,7 @@ object Starbound : ISBFileLocator {
|
||||
state.setTableFunction("tenantConfig", this) { args ->
|
||||
// Json root.tenantConfig(String tenantName)
|
||||
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
|
||||
}
|
||||
|
||||
@ -496,11 +486,11 @@ object Starbound : ISBFileLocator {
|
||||
}
|
||||
}
|
||||
|
||||
args.push(Registries.tenants.values
|
||||
args.push(Registries.tenants.keys.values
|
||||
.stream()
|
||||
.filter { it.value.test(actualTags) }
|
||||
.sorted { a, b -> b.value.compareTo(a.value) }
|
||||
.map { it.toJson() }
|
||||
.map { it.json }
|
||||
.collect(JsonArrayCollector))
|
||||
|
||||
1
|
||||
@ -517,7 +507,7 @@ object Starbound : ISBFileLocator {
|
||||
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
|
||||
}
|
||||
@ -711,7 +701,7 @@ object Starbound : ISBFileLocator {
|
||||
state.setTableFunction("techConfig", this) { args ->
|
||||
val name = args.getString()
|
||||
val tech = Registries.techs[name] ?: throw NoSuchElementException("No such tech $name")
|
||||
tech.push(args)
|
||||
args.push(tech)
|
||||
1
|
||||
}
|
||||
|
||||
@ -898,6 +888,8 @@ object Starbound : ISBFileLocator {
|
||||
if (!parallel)
|
||||
pool.shutdown()
|
||||
|
||||
Registries.validate()
|
||||
|
||||
initializing = false
|
||||
initialized = true
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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.objects.ObjectArrayList
|
||||
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.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh
|
||||
@ -97,9 +98,9 @@ class ClientWorld(
|
||||
val tile = view.getTile(x, y) ?: continue
|
||||
val material = tile.material
|
||||
|
||||
if (!material.isMeta) {
|
||||
if (!material.value.isMeta) {
|
||||
client.tileRenderers
|
||||
.getMaterialRenderer(material.materialName)
|
||||
.getMaterialRenderer(material.key)
|
||||
.tesselate(tile, view, meshes, Vector2i(x, y), isBackground = isBackground)
|
||||
}
|
||||
|
||||
@ -107,7 +108,7 @@ class ClientWorld(
|
||||
|
||||
if (modifier != null) {
|
||||
client.tileRenderers
|
||||
.getModifierRenderer(modifier.modName)
|
||||
.getModifierRenderer(modifier.key)
|
||||
.tesselate(tile, view, meshes, Vector2i(x, y), isBackground = isBackground, isModifier = true)
|
||||
}
|
||||
}
|
||||
@ -134,11 +135,11 @@ class ClientWorld(
|
||||
liquidIsDirty = false
|
||||
liquidMesh.clear()
|
||||
|
||||
val liquidTypes = ReferenceArraySet<LiquidDefinition>()
|
||||
val liquidTypes = ReferenceArraySet<Registry.Entry<LiquidDefinition>>()
|
||||
|
||||
for (x in 0 until renderRegionWidth) {
|
||||
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) {
|
||||
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() + 1f, y.toFloat())
|
||||
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.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
@ -19,12 +20,16 @@ import ru.dbotthepony.kstarbound.util.ItemStack
|
||||
* Прототип [ItemStack] в JSON файлах
|
||||
*/
|
||||
data class ItemReference(
|
||||
val item: RegistryReference<IItemDefinition>,
|
||||
val item: Registry.Ref<IItemDefinition>,
|
||||
val count: Long = 1,
|
||||
val parameters: JsonObject = JsonObject()
|
||||
) {
|
||||
init {
|
||||
require(item.key.isLeft) { "Can't reference item by ID" }
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -33,7 +38,7 @@ data class ItemReference(
|
||||
return object : TypeAdapter<ItemReference>() {
|
||||
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 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?) {
|
||||
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.ImmutableSet
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.player.BlueprintLearnList
|
||||
@ -25,7 +26,7 @@ data class Species(
|
||||
val undyColor: ImmutableList<ColorReplacements>,
|
||||
val hairColor: ImmutableList<ColorReplacements>,
|
||||
val genders: ImmutableList<Gender>,
|
||||
val statusEffects: ImmutableSet<RegistryReference<StatusEffectDefinition>> = ImmutableSet.of(),
|
||||
val statusEffects: ImmutableSet<Registry.Ref<StatusEffectDefinition>> = ImmutableSet.of(),
|
||||
) {
|
||||
@JsonFactory
|
||||
data class Tooltip(val title: String, val subTitle: String, val description: String)
|
||||
@ -37,8 +38,8 @@ data class Species(
|
||||
val characterImage: SpriteReference,
|
||||
val hairGroup: String? = null,
|
||||
val hair: ImmutableSet<String>,
|
||||
val shirt: ImmutableSet<RegistryReference<IItemDefinition>>,
|
||||
val pants: ImmutableSet<RegistryReference<IItemDefinition>>,
|
||||
val shirt: ImmutableSet<Registry.Ref<IItemDefinition>>,
|
||||
val pants: ImmutableSet<Registry.Ref<IItemDefinition>>,
|
||||
val facialHairGroup: String? = null,
|
||||
val facialHair: ImmutableSet<String> = ImmutableSet.of(),
|
||||
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.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
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.stream
|
||||
import ru.dbotthepony.kstarbound.util.Either
|
||||
@ -49,7 +49,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
||||
data class Piece(
|
||||
val level: Double,
|
||||
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,
|
||||
// TODO: что оно делает?
|
||||
// оно точно не запрещает ему появляться несколько раз за одну генерацию treasure pool
|
||||
@ -69,7 +69,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
||||
val stack = it.makeStack()
|
||||
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()
|
||||
if (stack.isNotEmpty) result.add(stack)
|
||||
}, {
|
||||
it.value?.value?.evaluate(random, actualLevel)
|
||||
it.value?.evaluate(random, actualLevel)
|
||||
})
|
||||
|
||||
break
|
||||
@ -145,7 +145,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
||||
|
||||
data class PoolEntry(
|
||||
val weight: Double,
|
||||
val treasure: Either<ItemReference, RegistryReference<TreasurePoolDefinition>>
|
||||
val treasure: Either<ItemReference, Registry.Ref<TreasurePoolDefinition>>
|
||||
) {
|
||||
init {
|
||||
require(weight > 0.0) { "Invalid pool entry weight: $weight" }
|
||||
@ -157,7 +157,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
||||
if (type.rawType === TreasurePoolDefinition::class.java) {
|
||||
return object : TypeAdapter<TreasurePoolDefinition>() {
|
||||
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)
|
||||
|
||||
override fun write(out: JsonWriter, value: TreasurePoolDefinition?) {
|
||||
@ -184,7 +184,7 @@ class TreasurePoolDefinition(pieces: List<Piece>) {
|
||||
val things = objReader.read(`in`)
|
||||
|
||||
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
|
||||
val allowDuplication = things["allowDuplication"]?.asBoolean ?: false
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package ru.dbotthepony.kstarbound.defs.item.api
|
||||
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
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.ItemRarity
|
||||
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
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||
import ru.dbotthepony.kstarbound.defs.item.IInventoryIcon
|
||||
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.io.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
|
||||
@ -22,7 +21,7 @@ data class ItemDefinition(
|
||||
override val category: String? = null,
|
||||
override val inventoryIcon: ImmutableList<IInventoryIcon>? = null,
|
||||
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 eventCategory: String? = null,
|
||||
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.ImmutableMap
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.IScriptable
|
||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||
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.item.TreasurePoolDefinition
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
@ -24,7 +24,7 @@ data class MonsterTypeDefinition(
|
||||
val animation: AssetReference<AnimationDefinition>,
|
||||
// [ { "default" : "poptopTreasure", "bow" : "poptopHunting" } ],
|
||||
// "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
|
||||
) : IThingWithDescription by desc {
|
||||
@JsonFactory
|
||||
|
@ -11,14 +11,11 @@ import com.google.gson.JsonSyntaxException
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.ItemReference
|
||||
import ru.dbotthepony.kstarbound.defs.JsonReference
|
||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
||||
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.tile.TileDamageConfig
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
@ -44,10 +41,10 @@ data class ObjectDefinition(
|
||||
val hasObjectItem: Boolean = true,
|
||||
val scannable: Boolean = true,
|
||||
val retainObjectParametersInItem: Boolean = false,
|
||||
val breakDropPool: RegistryReference<TreasurePoolDefinition>? = null,
|
||||
val breakDropPool: Registry.Ref<TreasurePoolDefinition>? = null,
|
||||
// null - not specified, empty list - always drop nothing
|
||||
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 animation: AssetReference<AnimationDefinition>? = null,
|
||||
val animation: AssetPath? = null,
|
||||
@ -97,10 +94,10 @@ data class ObjectDefinition(
|
||||
val hasObjectItem: Boolean = true,
|
||||
val scannable: Boolean = true,
|
||||
val retainObjectParametersInItem: Boolean = false,
|
||||
val breakDropPool: RegistryReference<TreasurePoolDefinition>? = null,
|
||||
val breakDropPool: Registry.Ref<TreasurePoolDefinition>? = null,
|
||||
// null - not specified, empty list - always drop nothing
|
||||
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 animation: AssetReference<AnimationDefinition>? = null,
|
||||
val animation: AssetPath? = null,
|
||||
|
@ -210,8 +210,8 @@ data class ObjectOrientation(
|
||||
val builder = ImmutableList.Builder<Pair<Vector2i, String>>()
|
||||
|
||||
when (val collisionType = obj.get("collisionType", "none").lowercase()) {
|
||||
"solid" -> collisionSpaces.forEach { builder.add(it to BuiltinMetaMaterials.OBJECT_SOLID.materialName) }
|
||||
"platform" -> collisionSpaces.forEach { if (it.y == boundingBox.maxs.y) builder.add(it to BuiltinMetaMaterials.OBJECT_PLATFORM.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.key) }
|
||||
"none" -> {}
|
||||
else -> throw JsonSyntaxException("Unknown collision type $collisionType")
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
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.util.Either
|
||||
|
||||
@JsonFactory
|
||||
data class ParticleCreator(
|
||||
val count: Int = 1,
|
||||
val particle: Either<RegistryReference<ParticleDefinition>, IParticleConfig>,
|
||||
val particle: Either<Registry.Ref<ParticleDefinition>, IParticleConfig>,
|
||||
|
||||
//override val offset: 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.JsonWriter
|
||||
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.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)) })
|
||||
|
||||
@JsonFactory
|
||||
data class Entry(val item: RegistryReference<IItemDefinition>)
|
||||
data class Entry(val item: Registry.Ref<IItemDefinition>)
|
||||
|
||||
operator fun get(tier: Int): List<Entry> {
|
||||
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.ImmutableMap
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||
import ru.dbotthepony.kstarbound.defs.IScriptable
|
||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
|
||||
@ -13,8 +13,8 @@ data class DeploymentConfig(
|
||||
override val scripts: ImmutableList<AssetPath>,
|
||||
override val scriptDelta: Int,
|
||||
|
||||
val starterMechSet: ImmutableMap<String, RegistryReference<IItemDefinition>>,
|
||||
val speciesStarterMechBody: ImmutableMap<String, RegistryReference<IItemDefinition>>,
|
||||
val starterMechSet: ImmutableMap<String, Registry.Ref<IItemDefinition>>,
|
||||
val speciesStarterMechBody: ImmutableMap<String, Registry.Ref<IItemDefinition>>,
|
||||
|
||||
val enemyDetectRadius: Double,
|
||||
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.ImmutableSet
|
||||
import com.google.gson.JsonObject
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
||||
import ru.dbotthepony.kstarbound.defs.Species
|
||||
import ru.dbotthepony.kstarbound.util.SBPattern
|
||||
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
||||
@ -22,14 +22,14 @@ data class PlayerDefinition(
|
||||
val blueprintAlreadyKnown: SBPattern,
|
||||
val collectableUnlock: SBPattern,
|
||||
|
||||
val species: ImmutableSet<RegistryReference<Species>>,
|
||||
val species: ImmutableSet<Registry.Ref<Species>>,
|
||||
val nametagColor: RGBAColor,
|
||||
val ageItemsEvery: Int,
|
||||
val defaultItems: ImmutableSet<RegistryReference<IItemDefinition>>,
|
||||
val defaultItems: ImmutableSet<Registry.Ref<IItemDefinition>>,
|
||||
|
||||
val defaultBlueprints: BlueprintLearnList,
|
||||
|
||||
val defaultCodexes: ImmutableMap<String, ImmutableList<RegistryReference<IItemDefinition>>>,
|
||||
val defaultCodexes: ImmutableMap<String, ImmutableList<Registry.Ref<IItemDefinition>>>,
|
||||
val metaBoundBox: AABB,
|
||||
val movementParameters: PlayerMovementParameters,
|
||||
val zeroGMovementParameters: PlayerMovementParameters,
|
||||
|
@ -1,12 +1,14 @@
|
||||
package ru.dbotthepony.kstarbound.defs.tile
|
||||
|
||||
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.world.physics.CollisionType
|
||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||
|
||||
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,
|
||||
materialName = "metamaterial:$name",
|
||||
descriptionData = ThingDescription.EMPTY,
|
||||
@ -15,7 +17,7 @@ object BuiltinMetaMaterials {
|
||||
renderParameters = RenderParameters.META,
|
||||
isMeta = true,
|
||||
collisionKind = collisionType
|
||||
)
|
||||
))
|
||||
|
||||
/**
|
||||
* air
|
||||
@ -38,7 +40,7 @@ object BuiltinMetaMaterials {
|
||||
val OBJECT_SOLID = make(65500, "objectsolid", CollisionType.BLOCK)
|
||||
val OBJECT_PLATFORM = make(65501, "objectplatform", CollisionType.PLATFORM)
|
||||
|
||||
val MATERIALS: ImmutableList<TileDefinition> = ImmutableList.of(
|
||||
val MATERIALS: ImmutableList<Registry.Entry<TileDefinition>> = ImmutableList.of(
|
||||
EMPTY,
|
||||
NULL,
|
||||
STRUCTURE,
|
||||
|
@ -1,7 +1,7 @@
|
||||
package ru.dbotthepony.kstarbound.defs.tile
|
||||
|
||||
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.io.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kvector.vector.RGBAColor
|
||||
@ -14,7 +14,7 @@ data class LiquidDefinition(
|
||||
val tickDelta: Int = 1,
|
||||
val color: RGBAColor,
|
||||
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 texture: String,
|
||||
val bottomLightMix: RGBAColor,
|
||||
|
@ -17,7 +17,7 @@ import jnr.ffi.Pointer
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.system.MemoryStack
|
||||
import org.lwjgl.system.MemoryUtil
|
||||
import ru.dbotthepony.kstarbound.RegistryObject
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
|
||||
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: String?) = this@LuaState.push(value)
|
||||
fun push(value: JsonElement?) = this@LuaState.push(value)
|
||||
fun push(value: RegistryObject<*>?) = this@LuaState.push(value)
|
||||
fun pushFull(value: RegistryObject<*>?) = this@LuaState.pushFull(value)
|
||||
fun push(value: Registry.Entry<*>?) = this@LuaState.push(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)
|
||||
}
|
||||
|
||||
fun setTableValue(key: String, value: String) {
|
||||
fun setTableValue(key: String, value: String?) {
|
||||
value ?: return
|
||||
val table = this.stackTop
|
||||
this.push(key)
|
||||
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)
|
||||
push()
|
||||
else
|
||||
push(value.toJson())
|
||||
push(value.json)
|
||||
}
|
||||
|
||||
fun pushFull(value: RegistryObject<*>?) {
|
||||
fun pushFull(value: Registry.Entry<*>?) {
|
||||
if (value == null)
|
||||
push()
|
||||
else {
|
||||
pushTable(hashSize = 2)
|
||||
setTableValue("path", value.file.computeFullPath())
|
||||
setTableValue("config", value.toJson())
|
||||
setTableValue("path", value.file?.computeFullPath())
|
||||
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.ObjectOpenHashSet
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.RegistryObject
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.player.TechDefinition
|
||||
import ru.dbotthepony.kstarbound.lua.LuaState
|
||||
@ -48,9 +48,9 @@ class Avatar(val uniqueId: UUID) {
|
||||
|
||||
var cursorItem = ItemStack.EMPTY
|
||||
|
||||
private val availableTechs = ObjectOpenHashSet<RegistryObject<TechDefinition>>()
|
||||
private val enabledTechs = ObjectOpenHashSet<RegistryObject<TechDefinition>>()
|
||||
private val equippedTechs = Object2ObjectOpenHashMap<String, RegistryObject<TechDefinition>>()
|
||||
private val availableTechs = ObjectOpenHashSet<Registry.Entry<TechDefinition>>()
|
||||
private val enabledTechs = ObjectOpenHashSet<Registry.Entry<TechDefinition>>()
|
||||
private val equippedTechs = Object2ObjectOpenHashMap<String, Registry.Entry<TechDefinition>>()
|
||||
|
||||
private val knownBlueprints = ObjectOpenHashSet<ItemStack>()
|
||||
// С подписью NEW
|
||||
|
@ -51,6 +51,22 @@ class Either<L, R> private constructor(val left: KOptional<L>, val right: KOptio
|
||||
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 {
|
||||
@JvmStatic
|
||||
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.internal.bind.TypeAdapters
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
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.defs.item.api.IItemDefinition
|
||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||
|
||||
class ItemStack private constructor(item: RegistryObject<IItemDefinition>?, count: Long, val parameters: JsonObject, marker: Unit) {
|
||||
constructor(item: RegistryObject<IItemDefinition>, count: Long = 1L, parameters: JsonObject = JsonObject()) : this(item, count, parameters, Unit)
|
||||
class ItemStack private constructor(item: Registry.Entry<IItemDefinition>?, count: Long, val parameters: JsonObject, marker: 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
|
||||
|
||||
var size = count
|
||||
|
@ -67,7 +67,7 @@ class KOptional<T> private constructor(private val _value: T, val isPresent: Boo
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return _value.hashCode()
|
||||
return _value.hashCode() + 43839429
|
||||
}
|
||||
|
||||
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 lightBlockStrength: Float
|
||||
|
||||
if (parent.foreground.material.renderParameters.lightTransparent) {
|
||||
if (parent.foreground.material.value.renderParameters.lightTransparent) {
|
||||
lightBlockStrength = 0f
|
||||
} else {
|
||||
lightBlockStrength = 1f
|
||||
|
@ -47,7 +47,7 @@ fun interface TileRayFilter {
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
|
@ -226,7 +226,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
result.add(CollisionPoly(
|
||||
BLOCK_POLY + Vector2d(x.toDouble(), y.toDouble()),
|
||||
cell.foreground.material.collisionKind,
|
||||
cell.foreground.material.value.collisionKind,
|
||||
//velocity = Vector2d(EARTH_FREEFALL_ACCELERATION, 0.0)
|
||||
))
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
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.util.HashTableInterner
|
||||
import java.io.DataInputStream
|
||||
|
||||
sealed class AbstractLiquidState {
|
||||
abstract val def: LiquidDefinition?
|
||||
abstract val def: Registry.Entry<LiquidDefinition>?
|
||||
abstract val level: Float
|
||||
abstract val pressure: Float
|
||||
abstract val isInfinite: Boolean
|
||||
|
@ -1,13 +1,14 @@
|
||||
package ru.dbotthepony.kstarbound.world.api
|
||||
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||
import java.io.DataInputStream
|
||||
|
||||
sealed class AbstractTileState {
|
||||
abstract val material: TileDefinition
|
||||
abstract val modifier: MaterialModifier?
|
||||
abstract val material: Registry.Entry<TileDefinition>
|
||||
abstract val modifier: Registry.Entry<MaterialModifier>?
|
||||
abstract val color: TileColor
|
||||
abstract val hueShift: Float
|
||||
abstract val modifierHueShift: Float
|
||||
|
@ -1,9 +1,10 @@
|
||||
package ru.dbotthepony.kstarbound.world.api
|
||||
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||
|
||||
data class ImmutableLiquidState(
|
||||
override val def: LiquidDefinition? = null,
|
||||
override val def: Registry.Entry<LiquidDefinition>? = null,
|
||||
override val level: Float = 0f,
|
||||
override val pressure: Float = 0f,
|
||||
override val isInfinite: Boolean = false,
|
||||
|
@ -1,12 +1,13 @@
|
||||
package ru.dbotthepony.kstarbound.world.api
|
||||
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||
|
||||
data class ImmutableTileState(
|
||||
override var material: TileDefinition = BuiltinMetaMaterials.NULL,
|
||||
override var modifier: MaterialModifier? = null,
|
||||
override var material: Registry.Entry<TileDefinition> = BuiltinMetaMaterials.NULL,
|
||||
override var modifier: Registry.Entry<MaterialModifier>? = null,
|
||||
override var color: TileColor = TileColor.DEFAULT,
|
||||
override var hueShift: Float = 0f,
|
||||
override var modifierHueShift: Float = 0f,
|
||||
|
@ -1,17 +1,18 @@
|
||||
package ru.dbotthepony.kstarbound.world.api
|
||||
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||
import java.io.DataInputStream
|
||||
|
||||
data class MutableLiquidState(
|
||||
override var def: LiquidDefinition? = null,
|
||||
override var def: Registry.Entry<LiquidDefinition>? = null,
|
||||
override var level: Float = 0f,
|
||||
override var pressure: Float = 0f,
|
||||
override var isInfinite: Boolean = false,
|
||||
) : AbstractLiquidState() {
|
||||
fun read(stream: DataInputStream): MutableLiquidState {
|
||||
def = Registries.liquid[stream.readUnsignedByte()]?.value
|
||||
def = Registries.liquid[stream.readUnsignedByte()]
|
||||
level = stream.readFloat()
|
||||
pressure = stream.readFloat()
|
||||
isInfinite = stream.readBoolean()
|
||||
|
@ -1,14 +1,15 @@
|
||||
package ru.dbotthepony.kstarbound.world.api
|
||||
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||
import java.io.DataInputStream
|
||||
|
||||
data class MutableTileState(
|
||||
override var material: TileDefinition = BuiltinMetaMaterials.NULL,
|
||||
override var modifier: MaterialModifier? = null,
|
||||
override var material: Registry.Entry<TileDefinition> = BuiltinMetaMaterials.NULL,
|
||||
override var modifier: Registry.Entry<MaterialModifier>? = null,
|
||||
override var color: TileColor = TileColor.DEFAULT,
|
||||
override var hueShift: Float = 0f,
|
||||
override var modifierHueShift: Float = 0f,
|
||||
@ -49,10 +50,10 @@ data class MutableTileState(
|
||||
}
|
||||
|
||||
fun read(stream: DataInputStream): MutableTileState {
|
||||
material = Registries.tiles[stream.readUnsignedShort()]?.value ?: BuiltinMetaMaterials.EMPTY
|
||||
material = Registries.tiles[stream.readUnsignedShort()] ?: BuiltinMetaMaterials.EMPTY
|
||||
setHueShift(stream.read())
|
||||
color = TileColor.of(stream.read())
|
||||
modifier = Registries.tileModifiers[stream.readUnsignedShort()]?.value
|
||||
modifier = Registries.tileModifiers[stream.readUnsignedShort()]
|
||||
setModHueShift(stream.read())
|
||||
return this
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import com.google.gson.TypeAdapter
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.RegistryObject
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.world.ClientWorld
|
||||
import ru.dbotthepony.kstarbound.defs.Drawable
|
||||
@ -26,9 +26,9 @@ import ru.dbotthepony.kvector.vector.Vector2i
|
||||
|
||||
open class WorldObject(
|
||||
val world: World<*, *>,
|
||||
val prototype: RegistryObject<ObjectDefinition>,
|
||||
val prototype: Registry.Entry<ObjectDefinition>,
|
||||
val pos: Vector2i,
|
||||
) : JsonDriven(prototype.file.computeDirectory()) {
|
||||
) : JsonDriven(prototype.file?.computeDirectory() ?: "/") {
|
||||
constructor(world: World<*, *>, data: JsonObject) : this(
|
||||
world,
|
||||
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