AssetReference, AssetPathStack и корректировка существующих адаптеров
This commit is contained in:
parent
c57558af20
commit
6584087842
@ -1,6 +1,5 @@
|
|||||||
package ru.dbotthepony.kstarbound
|
package ru.dbotthepony.kstarbound
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
|
||||||
import com.google.common.collect.Interner
|
import com.google.common.collect.Interner
|
||||||
import com.google.common.collect.Interners
|
import com.google.common.collect.Interners
|
||||||
import com.google.gson.*
|
import com.google.gson.*
|
||||||
@ -15,10 +14,8 @@ import ru.dbotthepony.kstarbound.api.NonExistingFile
|
|||||||
import ru.dbotthepony.kstarbound.api.PhysicalFile
|
import ru.dbotthepony.kstarbound.api.PhysicalFile
|
||||||
import ru.dbotthepony.kstarbound.api.explore
|
import ru.dbotthepony.kstarbound.api.explore
|
||||||
import ru.dbotthepony.kstarbound.defs.*
|
import ru.dbotthepony.kstarbound.defs.*
|
||||||
import ru.dbotthepony.kstarbound.defs.image.AtlasConfiguration
|
import ru.dbotthepony.kstarbound.defs.image.ImageReference
|
||||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ArmorItemPrototype
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ArmorPieceType
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.BackArmorItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.BackArmorItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ChestArmorItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.ChestArmorItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.CurrencyItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.CurrencyItemPrototype
|
||||||
@ -26,14 +23,9 @@ import ru.dbotthepony.kstarbound.defs.item.FlashlightPrototype
|
|||||||
import ru.dbotthepony.kstarbound.defs.item.HarvestingToolPrototype
|
import ru.dbotthepony.kstarbound.defs.item.HarvestingToolPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.HeadArmorItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.HeadArmorItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.IArmorItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.IArmorItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.item.IFossilItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.IItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.IItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.ItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemTooltipKind
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.LegsArmorItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.LegsArmorItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.LeveledStatusEffect
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.LiquidItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.LiquidItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.item.MaterialItemPrototype
|
import ru.dbotthepony.kstarbound.defs.item.MaterialItemPrototype
|
||||||
import ru.dbotthepony.kstarbound.defs.liquid.LiquidDefinition
|
import ru.dbotthepony.kstarbound.defs.liquid.LiquidDefinition
|
||||||
@ -41,25 +33,16 @@ import ru.dbotthepony.kstarbound.defs.parallax.ParallaxPrototype
|
|||||||
import ru.dbotthepony.kstarbound.defs.player.PlayerDefinition
|
import ru.dbotthepony.kstarbound.defs.player.PlayerDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.projectile.*
|
import ru.dbotthepony.kstarbound.defs.projectile.*
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.RenderParameters
|
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.RenderTemplate
|
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.world.SkyParameters
|
|
||||||
import ru.dbotthepony.kstarbound.defs.world.dungeon.DungeonWorldDef
|
|
||||||
import ru.dbotthepony.kstarbound.io.*
|
import ru.dbotthepony.kstarbound.io.*
|
||||||
import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.AABBiTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.EnumAdapter
|
import ru.dbotthepony.kstarbound.io.json.builder.EnumAdapter
|
||||||
import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.Vector2fTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.Vector2iTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.Vector4iTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter
|
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementationTypeFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementationTypeFactory
|
||||||
import ru.dbotthepony.kstarbound.io.json.factory.ArrayListAdapterFactory
|
import ru.dbotthepony.kstarbound.io.json.factory.ArrayListAdapterFactory
|
||||||
import ru.dbotthepony.kstarbound.io.json.factory.ImmutableCollectionAdapterFactory
|
import ru.dbotthepony.kstarbound.io.json.factory.ImmutableCollectionAdapterFactory
|
||||||
import ru.dbotthepony.kstarbound.math.*
|
import ru.dbotthepony.kstarbound.math.*
|
||||||
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
import ru.dbotthepony.kstarbound.util.WriteOnce
|
import ru.dbotthepony.kstarbound.util.WriteOnce
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
@ -80,36 +63,11 @@ fun String.sbIntern(): String = Starbound.STRING_INTERNER.intern(this)
|
|||||||
object Starbound {
|
object Starbound {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
/**
|
val STRING_INTERNER: Interner<String> = Interners.newWeakInterner()
|
||||||
* Служит переменной для указания из какой папки происходит чтение asset'а в данном потоке
|
val pathStack = AssetPathStack(STRING_INTERNER)
|
||||||
*/
|
|
||||||
var assetFolder by ThreadLocal<String>()
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun assetFolder(input: String): String {
|
fun assetFolder(input: String): String {
|
||||||
val assetFolder = assetFolder
|
return pathStack.remap(input)
|
||||||
require(assetFolder != null) { "Not reading an asset on current thread" }
|
|
||||||
|
|
||||||
if (input[0] == '/')
|
|
||||||
return input
|
|
||||||
|
|
||||||
return STRING_INTERNER.intern("$assetFolder/$input")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assetFolderNullable(input: String?): String? {
|
|
||||||
require(assetFolder != null) { "Not reading an asset on current thread" }
|
|
||||||
|
|
||||||
if (input != null)
|
|
||||||
return assetFolder(input)
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readingFolderListTransformer(input: List<String>?): List<String>? {
|
|
||||||
if (input == null)
|
|
||||||
return null
|
|
||||||
|
|
||||||
return input.stream().map { assetFolder(it) }.collect(ImmutableList.toImmutableList())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tiles = Object2ObjectOpenHashMap<String, TileDefinition>()
|
private val tiles = Object2ObjectOpenHashMap<String, TileDefinition>()
|
||||||
@ -125,6 +83,7 @@ object Starbound {
|
|||||||
private val parallax = Object2ObjectOpenHashMap<String, ParallaxPrototype>()
|
private val parallax = Object2ObjectOpenHashMap<String, ParallaxPrototype>()
|
||||||
private val functions = Object2ObjectOpenHashMap<String, JsonFunction>()
|
private val functions = Object2ObjectOpenHashMap<String, JsonFunction>()
|
||||||
private val species = Object2ObjectOpenHashMap<String, Species>()
|
private val species = Object2ObjectOpenHashMap<String, Species>()
|
||||||
|
private val statusEffects = Object2ObjectOpenHashMap<String, StatusEffectDefinition>()
|
||||||
|
|
||||||
private val items = Object2ObjectOpenHashMap<String, IItemDefinition>()
|
private val items = Object2ObjectOpenHashMap<String, IItemDefinition>()
|
||||||
|
|
||||||
@ -139,8 +98,6 @@ object Starbound {
|
|||||||
val FUNCTION: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
val FUNCTION: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
||||||
val ITEM: Map<String, IItemDefinition> = Collections.unmodifiableMap(items)
|
val ITEM: Map<String, IItemDefinition> = Collections.unmodifiableMap(items)
|
||||||
|
|
||||||
val STRING_INTERNER: Interner<String> = Interners.newWeakInterner()
|
|
||||||
|
|
||||||
val STRING_ADAPTER: TypeAdapter<String> = object : TypeAdapter<String>() {
|
val STRING_ADAPTER: TypeAdapter<String> = object : TypeAdapter<String>() {
|
||||||
override fun write(out: JsonWriter, value: String?) {
|
override fun write(out: JsonWriter, value: String?) {
|
||||||
if (value == null)
|
if (value == null)
|
||||||
@ -184,6 +141,20 @@ object Starbound {
|
|||||||
|
|
||||||
.also(::addStarboundJsonAdapters)
|
.also(::addStarboundJsonAdapters)
|
||||||
|
|
||||||
|
.registerTypeAdapterFactory(IItemDefinition.InventoryIcon.Factory(pathStack))
|
||||||
|
.registerTypeAdapter(SpriteReference.Adapter(pathStack))
|
||||||
|
.registerTypeAdapterFactory(IArmorItemDefinition.ArmorFrames.Factory(pathStack))
|
||||||
|
.registerTypeAdapter(ImageReference.Adapter(pathStack))
|
||||||
|
|
||||||
|
.registerTypeAdapterFactory(AssetReferenceFactory(pathStack) {
|
||||||
|
val file = locate(it)
|
||||||
|
|
||||||
|
if (file.exists && file.isFile)
|
||||||
|
file.reader()
|
||||||
|
else
|
||||||
|
null
|
||||||
|
})
|
||||||
|
|
||||||
.registerTypeAdapterFactory(RegistryReferenceFactory()
|
.registerTypeAdapterFactory(RegistryReferenceFactory()
|
||||||
.add(tiles::get)
|
.add(tiles::get)
|
||||||
.add(tileModifiers::get)
|
.add(tileModifiers::get)
|
||||||
@ -193,6 +164,7 @@ object Starbound {
|
|||||||
.add(functions::get)
|
.add(functions::get)
|
||||||
.add(items::get)
|
.add(items::get)
|
||||||
.add(species::get)
|
.add(species::get)
|
||||||
|
.add(statusEffects::get)
|
||||||
)
|
)
|
||||||
|
|
||||||
.create()
|
.create()
|
||||||
@ -352,9 +324,9 @@ object Starbound {
|
|||||||
loadStage(callback, this::loadItemDefinitions, "item definitions")
|
loadStage(callback, this::loadItemDefinitions, "item definitions")
|
||||||
loadStage(callback, this::loadSpecies, "species")
|
loadStage(callback, this::loadSpecies, "species")
|
||||||
|
|
||||||
assetFolder = "/"
|
pathStack.block("/") {
|
||||||
playerDefinition = GSON.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java)
|
playerDefinition = GSON.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java)
|
||||||
assetFolder = null
|
}
|
||||||
|
|
||||||
initializing = false
|
initializing = false
|
||||||
initialized = true
|
initialized = true
|
||||||
@ -381,16 +353,12 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadTileMaterials(callback: (String) -> Unit) {
|
private fun loadTileMaterials(callback: (String) -> Unit) {
|
||||||
assetFolder = "/tiles/materials"
|
|
||||||
|
|
||||||
for (fs in fileSystems) {
|
for (fs in fileSystems) {
|
||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".material") }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".material") }) {
|
||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
|
||||||
assetFolder = listedFile.computeDirectory()
|
val tileDef = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), TileDefinition::class.java) }
|
||||||
val tileDef = GSON.fromJson(listedFile.reader(), TileDefinition::class.java)
|
|
||||||
|
|
||||||
check(tiles[tileDef.materialName] == null) { "Already has material with name ${tileDef.materialName} loaded!" }
|
check(tiles[tileDef.materialName] == null) { "Already has material with name ${tileDef.materialName} loaded!" }
|
||||||
check(tilesByMaterialID[tileDef.materialId] == null) { "Already has material with ID ${tileDef.materialId} loaded!" }
|
check(tilesByMaterialID[tileDef.materialId] == null) { "Already has material with ID ${tileDef.materialId} loaded!" }
|
||||||
tilesByMaterialID[tileDef.materialId] = tileDef
|
tilesByMaterialID[tileDef.materialId] = tileDef
|
||||||
@ -405,8 +373,6 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadProjectiles(callback: (String) -> Unit) {
|
private fun loadProjectiles(callback: (String) -> Unit) {
|
||||||
@ -415,8 +381,7 @@ object Starbound {
|
|||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
|
||||||
assetFolder = listedFile.computeDirectory()
|
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), ConfigurableProjectile::class.java).assemble(it) }
|
||||||
val def = GSON.fromJson(listedFile.reader(), ConfigurableProjectile::class.java).assemble(listedFile.computeDirectory())
|
|
||||||
check(projectiles[def.projectileName] == null) { "Already has projectile with ID ${def.projectileName} loaded!" }
|
check(projectiles[def.projectileName] == null) { "Already has projectile with ID ${def.projectileName} loaded!" }
|
||||||
projectiles[def.projectileName] = def
|
projectiles[def.projectileName] = def
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
@ -429,8 +394,6 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadFunctions(callback: (String) -> Unit) {
|
private fun loadFunctions(callback: (String) -> Unit) {
|
||||||
@ -439,11 +402,10 @@ object Starbound {
|
|||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
|
||||||
assetFolder = listedFile.computeDirectory()
|
|
||||||
val readObject = JsonParser.parseReader(listedFile.reader()) as JsonObject
|
val readObject = JsonParser.parseReader(listedFile.reader()) as JsonObject
|
||||||
|
|
||||||
for (key in readObject.keySet()) {
|
for (key in readObject.keySet()) {
|
||||||
val def = GSON.fromJson(readObject[key], JsonFunction::class.java)
|
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(readObject[key], JsonFunction::class.java) }
|
||||||
functions[key] = def
|
functions[key] = def
|
||||||
}
|
}
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
@ -455,8 +417,6 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadParallax(callback: (String) -> Unit) {
|
private fun loadParallax(callback: (String) -> Unit) {
|
||||||
@ -464,9 +424,7 @@ object Starbound {
|
|||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".parallax") }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".parallax") }) {
|
||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), ParallaxPrototype::class.java) }
|
||||||
assetFolder = listedFile.computeDirectory()
|
|
||||||
val def = GSON.fromJson(listedFile.reader(), ParallaxPrototype::class.java)
|
|
||||||
parallax[listedFile.name.substringBefore('.')] = def
|
parallax[listedFile.name.substringBefore('.')] = def
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
LOGGER.error("Loading parallax file $listedFile", err)
|
LOGGER.error("Loading parallax file $listedFile", err)
|
||||||
@ -477,21 +435,14 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadMaterialModifiers(callback: (String) -> Unit) {
|
private fun loadMaterialModifiers(callback: (String) -> Unit) {
|
||||||
assetFolder = "/tiles/materials"
|
|
||||||
|
|
||||||
for (fs in fileSystems) {
|
for (fs in fileSystems) {
|
||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".matmod") }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".matmod") }) {
|
||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
val tileDef = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), MaterialModifier::class.java) }
|
||||||
assetFolder = listedFile.computeDirectory()
|
|
||||||
val tileDef = GSON.fromJson(listedFile.reader(), MaterialModifier::class.java)
|
|
||||||
|
|
||||||
check(tileModifiers[tileDef.modName] == null) { "Already has material with name ${tileDef.modName} loaded!" }
|
check(tileModifiers[tileDef.modName] == null) { "Already has material with name ${tileDef.modName} loaded!" }
|
||||||
check(tileModifiersByID[tileDef.modId] == null) { "Already has material with ID ${tileDef.modId} loaded!" }
|
check(tileModifiersByID[tileDef.modId] == null) { "Already has material with ID ${tileDef.modId} loaded!" }
|
||||||
tileModifiersByID[tileDef.modId] = tileDef
|
tileModifiersByID[tileDef.modId] = tileDef
|
||||||
@ -506,8 +457,6 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
|
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
|
||||||
@ -515,10 +464,7 @@ object Starbound {
|
|||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".liquid") }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".liquid") }) {
|
||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
val liquidDef = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), LiquidDefinition::class.java) }
|
||||||
assetFolder = listedFile.computeDirectory()
|
|
||||||
val liquidDef = GSON.fromJson(listedFile.reader(), LiquidDefinition::class.java)
|
|
||||||
|
|
||||||
check(liquid.put(liquidDef.name, liquidDef) == null) { "Already has liquid with name ${liquidDef.name} loaded!" }
|
check(liquid.put(liquidDef.name, liquidDef) == null) { "Already has liquid with name ${liquidDef.name} loaded!" }
|
||||||
check(liquidByID.put(liquidDef.liquidId, liquidDef) == null) { "Already has liquid with ID ${liquidDef.liquidId} loaded!" }
|
check(liquidByID.put(liquidDef.liquidId, liquidDef) == null) { "Already has liquid with ID ${liquidDef.liquidId} loaded!" }
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
@ -531,8 +477,6 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadSpecies(callback: (String) -> Unit) {
|
private fun loadSpecies(callback: (String) -> Unit) {
|
||||||
@ -540,9 +484,7 @@ object Starbound {
|
|||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".species") }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".species") }) {
|
||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
val def = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), Species::class.java) }
|
||||||
assetFolder = listedFile.computeDirectory()
|
|
||||||
val def = GSON.fromJson(listedFile.reader(), Species::class.java)
|
|
||||||
check(species.put(def.kind, def) == null) { "Already has liquid with name ${def.kind} loaded!" }
|
check(species.put(def.kind, def) == null) { "Already has liquid with name ${def.kind} loaded!" }
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading species definition file $listedFile", err)
|
LOGGER.error("Loading species definition file $listedFile", err)
|
||||||
@ -553,8 +495,6 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadItemDefinitions(callback: (String) -> Unit) {
|
private fun loadItemDefinitions(callback: (String) -> Unit) {
|
||||||
@ -575,10 +515,7 @@ object Starbound {
|
|||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.keys.any { f.name.endsWith(it) } }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.keys.any { f.name.endsWith(it) } }) {
|
||||||
try {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
val def: ItemPrototype = pathStack(listedFile.computeDirectory()) { GSON.fromJson(listedFile.reader(), files.entries.first { listedFile.name.endsWith(it.key) }.value) }
|
||||||
assetFolder = listedFile.computeDirectory()
|
|
||||||
|
|
||||||
val def: ItemPrototype = GSON.fromJson(listedFile.reader(), files.entries.first { listedFile.name.endsWith(it.key) }.value)
|
|
||||||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Loading item definition file $listedFile", err)
|
LOGGER.error("Loading item definition file $listedFile", err)
|
||||||
@ -589,7 +526,5 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assetFolder = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,17 +75,12 @@ fun addStarboundJsonAdapters(builder: GsonBuilder) {
|
|||||||
registerTypeAdapterFactory(ParallaxPrototypeLayer.ADAPTER)
|
registerTypeAdapterFactory(ParallaxPrototypeLayer.ADAPTER)
|
||||||
registerTypeAdapter(ParallaxPrototypeLayer.LAYER_PARALLAX_ADAPTER)
|
registerTypeAdapter(ParallaxPrototypeLayer.LAYER_PARALLAX_ADAPTER)
|
||||||
|
|
||||||
// Предметы
|
|
||||||
registerTypeAdapterFactory(IItemDefinition.InventoryIcon.ADAPTER)
|
|
||||||
registerTypeAdapterFactory(IArmorItemDefinition.ArmorFrames.ADAPTER)
|
|
||||||
|
|
||||||
// Функции
|
// Функции
|
||||||
registerTypeAdapter(JsonFunction.CONSTRAINT_ADAPTER)
|
registerTypeAdapter(JsonFunction.CONSTRAINT_ADAPTER)
|
||||||
registerTypeAdapter(JsonFunction.INTERPOLATION_ADAPTER)
|
registerTypeAdapter(JsonFunction.INTERPOLATION_ADAPTER)
|
||||||
registerTypeAdapter(JsonFunction.Companion)
|
registerTypeAdapter(JsonFunction.Companion)
|
||||||
|
|
||||||
// Общее
|
// Общее
|
||||||
registerTypeAdapter(SpriteReference.Companion)
|
|
||||||
registerTypeAdapterFactory(AtlasConfiguration.Companion)
|
registerTypeAdapterFactory(AtlasConfiguration.Companion)
|
||||||
|
|
||||||
registerTypeAdapterFactory(LeveledStatusEffect.ADAPTER)
|
registerTypeAdapterFactory(LeveledStatusEffect.ADAPTER)
|
||||||
|
@ -183,7 +183,7 @@ private class ModifierEqualityTester(val definition: MaterialModifier) : Equalit
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TileRenderer(val state: GLStateTracker, val def: IRenderableTile) {
|
class TileRenderer(val state: GLStateTracker, val def: IRenderableTile) {
|
||||||
val texture = state.loadNamedTexture(def.renderParameters.absoluteTexturePath).also {
|
val texture = state.loadNamedTexture(def.renderParameters.texture.image).also {
|
||||||
it.textureMagFilter = GL_NEAREST
|
it.textureMagFilter = GL_NEAREST
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ class TileRenderer(val state: GLStateTracker, val def: IRenderableTile) {
|
|||||||
fun tesselate(self: ITileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
|
fun tesselate(self: ITileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
|
||||||
// если у нас нет renderTemplate
|
// если у нас нет renderTemplate
|
||||||
// то мы просто не можем его отрисовать
|
// то мы просто не можем его отрисовать
|
||||||
val template = def.renderTemplate
|
val template = def.renderTemplate.value ?: return
|
||||||
|
|
||||||
val vertexBuilder = layers.computeIfAbsent(if (background) bakedBackgroundProgramState else bakedProgramState, def.renderParameters.zLevel, ::vertexTextureBuilder)
|
val vertexBuilder = layers.computeIfAbsent(if (background) bakedBackgroundProgramState else bakedProgramState, def.renderParameters.zLevel, ::vertexTextureBuilder)
|
||||||
|
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.defs
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
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.ObjectOpenHashSet
|
||||||
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
|
import java.io.Reader
|
||||||
|
import java.lang.reflect.ParameterizedType
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Данный [AssetReferenceFactory] реализует возможности чтения данных по "ссылке" на файл.
|
||||||
|
*
|
||||||
|
* Созданный [TypeAdapter] имеет встроенный кеш.
|
||||||
|
*/
|
||||||
|
class AssetReferenceFactory(val remapper: AssetPathStack, val reader: (String) -> Reader?) : TypeAdapterFactory {
|
||||||
|
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||||
|
if (type.rawType == AssetReference::class.java) {
|
||||||
|
val param = type.type as? ParameterizedType ?: return null
|
||||||
|
|
||||||
|
return object : TypeAdapter<AssetReference<Any>>() {
|
||||||
|
private val cache = ConcurrentHashMap<String, Any>()
|
||||||
|
private val adapter = gson.getAdapter(TypeToken.get(param.actualTypeArguments[0])) as TypeAdapter<Any>
|
||||||
|
private val strings = gson.getAdapter(String::class.java)
|
||||||
|
private val missing = Collections.synchronizedSet(ObjectOpenHashSet<String>())
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: AssetReference<Any>?) {
|
||||||
|
if (value == null)
|
||||||
|
out.nullValue()
|
||||||
|
else
|
||||||
|
out.value(value.fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): AssetReference<Any>? {
|
||||||
|
if (`in`.peek() == JsonToken.NULL) {
|
||||||
|
return null
|
||||||
|
} else if (`in`.peek() == JsonToken.STRING) {
|
||||||
|
val path = strings.read(`in`)!!
|
||||||
|
val fullPath = remapper.remap(path)
|
||||||
|
val get = cache[fullPath]
|
||||||
|
|
||||||
|
if (get != null)
|
||||||
|
return AssetReference(path, fullPath, get)
|
||||||
|
|
||||||
|
if (fullPath in missing)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val reader = reader.invoke(fullPath)
|
||||||
|
|
||||||
|
if (reader == null) {
|
||||||
|
missing.add(fullPath)
|
||||||
|
return AssetReference(path, fullPath, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val value = remapper(fullPath) {
|
||||||
|
adapter.read(JsonReader(reader).also {
|
||||||
|
it.isLenient = true
|
||||||
|
}) ?: return AssetReference(path, fullPath, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
cache[fullPath] = value
|
||||||
|
return AssetReference(path, fullPath, value)
|
||||||
|
} else {
|
||||||
|
val value = adapter.read(`in`) ?: return null
|
||||||
|
return AssetReference(null, null, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as TypeAdapter<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AssetReference<V>(val path: String?, val fullPath: String?, val value: V?)
|
@ -25,6 +25,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(),
|
||||||
) {
|
) {
|
||||||
@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)
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.defs
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList
|
||||||
|
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
||||||
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
|
|
||||||
|
@JsonFactory
|
||||||
|
data class StatusEffectDefinition(
|
||||||
|
val name: String,
|
||||||
|
val defaultDuration: Double,
|
||||||
|
val scripts: ImmutableList<String>,
|
||||||
|
val animationConfig: AssetReference<AnimationDefinition>,
|
||||||
|
)
|
@ -6,7 +6,7 @@ import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
|||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||||
|
|
||||||
@JsonFactory(asReference = true)
|
@JsonFactory
|
||||||
data class AnimationDefinition(
|
data class AnimationDefinition(
|
||||||
val animatedParts: AnimatedParts,
|
val animatedParts: AnimatedParts,
|
||||||
val sounds: ImmutableMap<String, Sound> = ImmutableMap.of(),
|
val sounds: ImmutableMap<String, Sound> = ImmutableMap.of(),
|
||||||
|
@ -6,6 +6,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 ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Хранит данные (пару) вида "/example/animated.png" у которого, вероятнее всего, есть "/example/animated.frames"
|
* Хранит данные (пару) вида "/example/animated.png" у которого, вероятнее всего, есть "/example/animated.frames"
|
||||||
@ -23,23 +24,28 @@ data class ImageReference(
|
|||||||
*/
|
*/
|
||||||
constructor(image: String) : this(image, AtlasConfiguration.get(image))
|
constructor(image: String) : this(image, AtlasConfiguration.get(image))
|
||||||
|
|
||||||
companion object : TypeAdapter<ImageReference>() {
|
class Adapter(val remapper: AssetPathStack) : TypeAdapter<ImageReference>() {
|
||||||
override fun write(out: JsonWriter, value: ImageReference) {
|
override fun write(out: JsonWriter, value: ImageReference?) {
|
||||||
out.value(value.image)
|
if (value == null)
|
||||||
|
out.nullValue()
|
||||||
|
else
|
||||||
|
out.value(value.image)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(`in`: JsonReader): ImageReference {
|
override fun read(`in`: JsonReader): ImageReference? {
|
||||||
if (`in`.peek() == JsonToken.STRING) {
|
if (`in`.peek() == JsonToken.NULL)
|
||||||
val image = Starbound.assetFolder(`in`.nextString())
|
return null
|
||||||
|
|
||||||
if (image.contains(':')) {
|
if (`in`.peek() == JsonToken.STRING) {
|
||||||
|
val image = remapper.remap(`in`.nextString())
|
||||||
|
|
||||||
|
if (image.contains(':'))
|
||||||
throw JsonSyntaxException("Expected atlas/image reference, but got sprite reference: $image")
|
throw JsonSyntaxException("Expected atlas/image reference, but got sprite reference: $image")
|
||||||
}
|
|
||||||
|
|
||||||
return ImageReference(image, AtlasConfiguration.get(image))
|
return ImageReference(image, AtlasConfiguration.get(image))
|
||||||
}
|
}
|
||||||
|
|
||||||
throw JsonSyntaxException("Expected atlas/image reference, but got: ${`in`.peek()}")
|
throw JsonSyntaxException("Expected atlas/image reference, but got: ${`in`.peek()} near ${`in`.path}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ 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.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
import ru.dbotthepony.kstarbound.util.SBPattern
|
import ru.dbotthepony.kstarbound.util.SBPattern
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,7 +22,17 @@ data class SpriteReference(
|
|||||||
return atlas[resolved] ?: atlas.any()
|
return atlas[resolved] ?: atlas.any()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : TypeAdapter<SpriteReference>() {
|
class Adapter(val remapper: AssetPathStack) : TypeAdapter<SpriteReference>() {
|
||||||
|
override fun write(out: JsonWriter, value: SpriteReference) {
|
||||||
|
out.value(value.image + ":" + value.sprite.raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): SpriteReference {
|
||||||
|
return parse(remapper.remap(`in`.nextString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
fun parse(input: String): SpriteReference {
|
fun parse(input: String): SpriteReference {
|
||||||
val grid = AtlasConfiguration.get(input.substringBefore(':'))
|
val grid = AtlasConfiguration.get(input.substringBefore(':'))
|
||||||
|
|
||||||
@ -31,13 +42,5 @@ data class SpriteReference(
|
|||||||
else -> throw IllegalArgumentException("Invalid sprite reference: $input")
|
else -> throw IllegalArgumentException("Invalid sprite reference: $input")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: SpriteReference) {
|
|
||||||
out.value(value.image + ":" + value.sprite.raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(`in`: JsonReader): SpriteReference {
|
|
||||||
return parse(Starbound.assetFolder(`in`.nextString()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.item
|
package ru.dbotthepony.kstarbound.defs.item
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
|
import com.google.gson.TypeAdapterFactory
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonToken
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.defs.image.AtlasConfiguration
|
||||||
|
import ru.dbotthepony.kstarbound.defs.image.ImageReference
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
|
||||||
import ru.dbotthepony.kstarbound.io.json.ifString
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
|
|
||||||
interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefinition {
|
interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefinition {
|
||||||
/**
|
/**
|
||||||
@ -28,23 +36,50 @@ interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefiniti
|
|||||||
|
|
||||||
@JsonImplementation(ArmorFrames::class)
|
@JsonImplementation(ArmorFrames::class)
|
||||||
interface IArmorFrames {
|
interface IArmorFrames {
|
||||||
val body: String
|
val body: ImageReference
|
||||||
val backSleeve: String?
|
val backSleeve: ImageReference?
|
||||||
val frontSleeve: String?
|
val frontSleeve: ImageReference?
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ArmorFrames(
|
data class ArmorFrames(
|
||||||
override val body: String,
|
override val body: ImageReference,
|
||||||
override val backSleeve: String?,
|
override val backSleeve: ImageReference? = null,
|
||||||
override val frontSleeve: String?,
|
override val frontSleeve: ImageReference? = null,
|
||||||
) : IArmorFrames {
|
) : IArmorFrames {
|
||||||
companion object {
|
class Factory(private val remapper: AssetPathStack) : TypeAdapterFactory {
|
||||||
val ADAPTER = FactoryAdapter.Builder(
|
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||||
ArmorFrames::class,
|
if (type.rawType == ArmorFrames::class.java) {
|
||||||
ArmorFrames::body,
|
return object : TypeAdapter<ArmorFrames>() {
|
||||||
ArmorFrames::backSleeve,
|
private val adapter = FactoryAdapter.Builder(
|
||||||
ArmorFrames::frontSleeve,
|
ArmorFrames::class,
|
||||||
).ifString { ArmorFrames(Starbound.assetFolder(it), null, null) }
|
ArmorFrames::body,
|
||||||
|
ArmorFrames::backSleeve,
|
||||||
|
ArmorFrames::frontSleeve,
|
||||||
|
).build(gson)
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: ArmorFrames?) {
|
||||||
|
if (value == null)
|
||||||
|
out.nullValue()
|
||||||
|
else
|
||||||
|
adapter.write(out, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): ArmorFrames? {
|
||||||
|
if (`in`.peek() == JsonToken.NULL)
|
||||||
|
return null
|
||||||
|
|
||||||
|
if (`in`.peek() == JsonToken.STRING) {
|
||||||
|
val path = remapper.remap(`in`.nextString())
|
||||||
|
return ArmorFrames(ImageReference(path, AtlasConfiguration.get(path)), null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapter.read(`in`)
|
||||||
|
}
|
||||||
|
} as TypeAdapter<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.item
|
package ru.dbotthepony.kstarbound.defs.item
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
|
import com.google.gson.TypeAdapterFactory
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonToken
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
|
||||||
import ru.dbotthepony.kstarbound.io.json.ifString
|
import ru.dbotthepony.kstarbound.io.json.ifString
|
||||||
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||||
|
|
||||||
interface IItemDefinition : IThingWithDescription {
|
interface IItemDefinition : IThingWithDescription {
|
||||||
/**
|
/**
|
||||||
@ -45,8 +53,34 @@ interface IItemDefinition : IThingWithDescription {
|
|||||||
data class InventoryIcon(
|
data class InventoryIcon(
|
||||||
override val image: SpriteReference
|
override val image: SpriteReference
|
||||||
) : IInventoryIcon {
|
) : IInventoryIcon {
|
||||||
companion object {
|
class Factory(val remapper: AssetPathStack) : TypeAdapterFactory {
|
||||||
val ADAPTER = FactoryAdapter.Builder(InventoryIcon::class, InventoryIcon::image).ifString { InventoryIcon(SpriteReference.parse(Starbound.assetFolder(it))) }
|
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||||
|
if (type.rawType == InventoryIcon::class.java) {
|
||||||
|
return object : TypeAdapter<InventoryIcon>() {
|
||||||
|
private val adapter = FactoryAdapter.Builder(InventoryIcon::class, InventoryIcon::image).build(gson)
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: InventoryIcon?) {
|
||||||
|
if (value == null)
|
||||||
|
out.nullValue()
|
||||||
|
else
|
||||||
|
adapter.write(out, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): InventoryIcon? {
|
||||||
|
if (`in`.peek() == JsonToken.NULL)
|
||||||
|
return null
|
||||||
|
|
||||||
|
if (`in`.peek() == JsonToken.STRING) {
|
||||||
|
return InventoryIcon(SpriteReference.parse(remapper.remap(`in`.nextString())))
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapter.read(`in`)
|
||||||
|
}
|
||||||
|
} as TypeAdapter<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ 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.defs.AssetReference
|
||||||
import ru.dbotthepony.kstarbound.defs.RegistryReference
|
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
|
||||||
@ -58,7 +59,7 @@ data class PlayerDefinition(
|
|||||||
|
|
||||||
val splashConfig: SplashConfig,
|
val splashConfig: SplashConfig,
|
||||||
|
|
||||||
val effectsAnimator: AnimationDefinition,
|
val effectsAnimator: AssetReference<AnimationDefinition>,
|
||||||
|
|
||||||
val teleportInTime: Double,
|
val teleportInTime: Double,
|
||||||
val teleportOutTime: Double,
|
val teleportOutTime: Double,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.tile
|
package ru.dbotthepony.kstarbound.defs.tile
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||||
|
|
||||||
sealed interface IRenderableTile {
|
sealed interface IRenderableTile {
|
||||||
val renderTemplate: RenderTemplate
|
val renderTemplate: AssetReference<RenderTemplate>
|
||||||
val renderParameters: RenderParameters
|
val renderParameters: RenderParameters
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.defs.tile
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
|
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||||
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
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ data class MaterialModifier(
|
|||||||
val grass: Boolean = false,
|
val grass: Boolean = false,
|
||||||
val miningSounds: ImmutableList<String> = ImmutableList.of(),
|
val miningSounds: ImmutableList<String> = ImmutableList.of(),
|
||||||
val miningParticle: String? = null,
|
val miningParticle: String? = null,
|
||||||
override val renderTemplate: RenderTemplate,
|
override val renderTemplate: AssetReference<RenderTemplate>,
|
||||||
override val renderParameters: RenderParameters
|
override val renderParameters: RenderParameters
|
||||||
) : IRenderableTile {
|
) : IRenderableTile {
|
||||||
init {
|
init {
|
||||||
|
@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.defs.tile
|
|||||||
|
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
import ru.dbotthepony.kstarbound.defs.image.ImageReference
|
||||||
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
|
||||||
|
|
||||||
@ -9,22 +10,10 @@ const val TILE_COLOR_VARIANTS = 9
|
|||||||
|
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
data class RenderParameters(
|
data class RenderParameters(
|
||||||
val texture: String,
|
val texture: ImageReference,
|
||||||
val variants: Int = 0,
|
val variants: Int = 0,
|
||||||
val multiColored: Boolean = false,
|
val multiColored: Boolean = false,
|
||||||
val occludesBelow: Boolean = false,
|
val occludesBelow: Boolean = false,
|
||||||
val lightTransparent: Boolean = false,
|
val lightTransparent: Boolean = false,
|
||||||
val zLevel: Int,
|
val zLevel: Int,
|
||||||
) {
|
)
|
||||||
val absoluteTexturePath: String
|
|
||||||
|
|
||||||
init {
|
|
||||||
val dir = Starbound.assetFolder
|
|
||||||
|
|
||||||
if (dir == null || texture[0] == '/') {
|
|
||||||
absoluteTexturePath = texture
|
|
||||||
} else {
|
|
||||||
absoluteTexturePath = "$dir/$texture"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,26 +2,13 @@ package ru.dbotthepony.kstarbound.defs.tile
|
|||||||
|
|
||||||
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.gson.GsonBuilder
|
|
||||||
import com.google.gson.JsonSyntaxException
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import com.google.gson.stream.JsonReader
|
|
||||||
import com.google.gson.stream.JsonToken
|
|
||||||
import com.google.gson.stream.JsonWriter
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.EnumAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.asReference
|
|
||||||
import ru.dbotthepony.kstarbound.registerTypeAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.util.WriteOnce
|
import ru.dbotthepony.kstarbound.util.WriteOnce
|
||||||
import ru.dbotthepony.kstarbound.world.ITileGetter
|
import ru.dbotthepony.kstarbound.world.ITileGetter
|
||||||
import ru.dbotthepony.kstarbound.world.ITileState
|
import ru.dbotthepony.kstarbound.world.ITileState
|
||||||
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
@JsonFactory
|
@JsonFactory
|
||||||
data class RenderPiece(
|
data class RenderPiece(
|
||||||
@ -202,7 +189,7 @@ data class RenderMatchList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonFactory(asReference = true)
|
@JsonFactory
|
||||||
data class RenderTemplate(
|
data class RenderTemplate(
|
||||||
val pieces: ImmutableMap<String, RenderPiece>,
|
val pieces: ImmutableMap<String, RenderPiece>,
|
||||||
val representativePiece: String,
|
val representativePiece: String,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.tile
|
package ru.dbotthepony.kstarbound.defs.tile
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
|
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||||
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
|
||||||
import ru.dbotthepony.kstarbound.registerTypeAdapter
|
import ru.dbotthepony.kstarbound.registerTypeAdapter
|
||||||
@ -22,6 +23,6 @@ data class TileDefinition(
|
|||||||
val health: Double = 0.0,
|
val health: Double = 0.0,
|
||||||
val category: String,
|
val category: String,
|
||||||
|
|
||||||
override val renderTemplate: RenderTemplate,
|
override val renderTemplate: AssetReference<RenderTemplate>,
|
||||||
override val renderParameters: RenderParameters,
|
override val renderParameters: RenderParameters,
|
||||||
) : IRenderableTile
|
) : IRenderableTile
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package ru.dbotthepony.kstarbound.io.json.builder
|
package ru.dbotthepony.kstarbound.io.json.builder
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.ReferenceAdapter
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.TypeAdapter
|
import com.google.gson.TypeAdapter
|
||||||
import com.google.gson.TypeAdapterFactory
|
import com.google.gson.TypeAdapterFactory
|
||||||
@ -42,11 +41,6 @@ annotation class JsonBuilder(
|
|||||||
* Включать ли свойства родительского класса в данный [BuilderAdapter]
|
* Включать ли свойства родительского класса в данный [BuilderAdapter]
|
||||||
*/
|
*/
|
||||||
val includeSuperclassProperties: Boolean = true,
|
val includeSuperclassProperties: Boolean = true,
|
||||||
|
|
||||||
/**
|
|
||||||
* Оборачивает созданный [BuilderAdapter] в [ReferenceAdapter]
|
|
||||||
*/
|
|
||||||
val asReference: Boolean = false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val JsonBuilder.realLogMisses get() = logMisses.toBool()
|
val JsonBuilder.realLogMisses get() = logMisses.toBool()
|
||||||
@ -102,11 +96,6 @@ annotation class JsonFactory(
|
|||||||
* @see FactoryAdapter.Builder.inputAsMap
|
* @see FactoryAdapter.Builder.inputAsMap
|
||||||
*/
|
*/
|
||||||
val asList: Boolean = false,
|
val asList: Boolean = false,
|
||||||
|
|
||||||
/**
|
|
||||||
* Оборачивает созданный [FactoryAdapter] в [ReferenceAdapter]
|
|
||||||
*/
|
|
||||||
val asReference: Boolean = false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,11 +20,9 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
|||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
|
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.asReference
|
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter.Builder
|
||||||
import ru.dbotthepony.kstarbound.util.NotNullVar
|
import ru.dbotthepony.kstarbound.util.NotNullVar
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
import kotlin.reflect.KCallable
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KMutableProperty1
|
import kotlin.reflect.KMutableProperty1
|
||||||
import kotlin.reflect.full.declaredMembers
|
import kotlin.reflect.full.declaredMembers
|
||||||
@ -423,10 +421,6 @@ class BuilderAdapter<T : Any> private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bconfig.asReference) {
|
|
||||||
return builder.build(gson).asReference()
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build(gson)
|
return builder.build(gson)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,20 +24,13 @@ import ru.dbotthepony.kstarbound.defs.util.enrollMap
|
|||||||
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
|
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
|
||||||
import ru.dbotthepony.kstarbound.getValue
|
import ru.dbotthepony.kstarbound.getValue
|
||||||
import ru.dbotthepony.kstarbound.io.json.ifString
|
import ru.dbotthepony.kstarbound.io.json.ifString
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.LazyTypeProvider
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.ListAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.MapAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.String2ObjectAdapter
|
|
||||||
import ru.dbotthepony.kstarbound.io.json.util.asReference
|
|
||||||
import ru.dbotthepony.kstarbound.setValue
|
import ru.dbotthepony.kstarbound.setValue
|
||||||
import java.lang.reflect.Constructor
|
import java.lang.reflect.Constructor
|
||||||
import kotlin.jvm.internal.DefaultConstructorMarker
|
import kotlin.jvm.internal.DefaultConstructorMarker
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
import kotlin.reflect.*
|
import kotlin.reflect.*
|
||||||
import kotlin.reflect.full.declaredMembers
|
import kotlin.reflect.full.declaredMembers
|
||||||
import kotlin.reflect.full.hasAnnotation
|
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
import kotlin.reflect.full.isSubtypeOf
|
|
||||||
import kotlin.reflect.full.isSupertypeOf
|
import kotlin.reflect.full.isSupertypeOf
|
||||||
import kotlin.reflect.full.primaryConstructor
|
import kotlin.reflect.full.primaryConstructor
|
||||||
|
|
||||||
@ -572,10 +565,6 @@ class FactoryAdapter<T : Any> private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bconfig.asReference) {
|
|
||||||
return builder.build(gson).asReference()
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build(gson)
|
return builder.build(gson)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.io.json.util
|
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import com.google.gson.TypeAdapterFactory
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import com.google.gson.stream.JsonReader
|
|
||||||
import com.google.gson.stream.JsonToken
|
|
||||||
import com.google.gson.stream.JsonWriter
|
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Данный [TypeAdapter] реализует возможности чтения данных по "ссылке" на файл.
|
|
||||||
*
|
|
||||||
* К примеру, если в оригинальной структуре может (или обычно) встречаться такое:
|
|
||||||
*
|
|
||||||
* ```json
|
|
||||||
* {
|
|
||||||
* "thing": { ... },
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* и такое:
|
|
||||||
*
|
|
||||||
* ```json
|
|
||||||
* {
|
|
||||||
* "thing": "/path/to/thing.config"
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* То второй вариант будет прочитан из указанного пути и закеширован внутри [ReferenceAdapter]
|
|
||||||
*/
|
|
||||||
class ReferenceAdapter<T>(val parent: TypeAdapter<T>) : TypeAdapter<T>() {
|
|
||||||
private val cache = ConcurrentHashMap<String, T>()
|
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: T) {
|
|
||||||
parent.write(out, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(reader: JsonReader): T {
|
|
||||||
if (reader.peek() != JsonToken.STRING) {
|
|
||||||
return parent.read(reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = reader.nextString()
|
|
||||||
|
|
||||||
if (path[0] != '/') {
|
|
||||||
// относительный путь
|
|
||||||
|
|
||||||
val readingFolder = Starbound.assetFolder ?: throw NullPointerException("Currently read folder is not specified")
|
|
||||||
path = "$readingFolder/$path"
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache.computeIfAbsent(path) {
|
|
||||||
return@computeIfAbsent parent.read(JsonReader(Starbound.locate(it).reader()).also { it.isLenient = true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReferenceAdapterFactory(val parent: TypeAdapterFactory) : TypeAdapterFactory {
|
|
||||||
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
|
||||||
val candidate = parent.create(gson, type)
|
|
||||||
|
|
||||||
if (candidate != null) {
|
|
||||||
return ReferenceAdapter(candidate)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> TypeAdapter<T>.asReference(): TypeAdapter<T> {
|
|
||||||
return ReferenceAdapter(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun TypeAdapterFactory.asReference(): TypeAdapterFactory {
|
|
||||||
return ReferenceAdapterFactory(this)
|
|
||||||
}
|
|
@ -0,0 +1,46 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.util
|
||||||
|
|
||||||
|
import com.google.common.collect.Interner
|
||||||
|
import kotlin.concurrent.getOrSet
|
||||||
|
|
||||||
|
class AssetPathStack(private val interner: Interner<String>? = null) {
|
||||||
|
private val _stack = ThreadLocal<ArrayDeque<String>>()
|
||||||
|
private val stack: ArrayDeque<String> get() = _stack.getOrSet { ArrayDeque() }
|
||||||
|
|
||||||
|
fun push(value: String) {
|
||||||
|
stack.addLast(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pushFilename(value: String) {
|
||||||
|
push(value.substringBefore(':').substringBeforeLast('/'))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun last() = stack.lastOrNull()
|
||||||
|
fun pop() = stack.removeLast()
|
||||||
|
|
||||||
|
inline fun <T> block(path: String, block: (String) -> T): T {
|
||||||
|
try {
|
||||||
|
push(path)
|
||||||
|
return block.invoke(path)
|
||||||
|
} finally {
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator fun <T> invoke(path: String, block: (String) -> T) = block(path, block)
|
||||||
|
|
||||||
|
private fun remap(a: String, b: String): String {
|
||||||
|
if (b[0] == '/')
|
||||||
|
return b
|
||||||
|
|
||||||
|
return interner?.intern("$a/$b") ?: "$a/$b"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remap(path: String): String {
|
||||||
|
return remap(checkNotNull(last()) { "Not reading an asset on current thread" }, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remapSafe(path: String): String? {
|
||||||
|
return remap(last() ?: return null, path)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user