diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt index 2df232ef..9f0cbffc 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt @@ -437,7 +437,7 @@ object Starbound { } private fun loadItemDefinitions(callback: (String) -> Unit) { - val files = listOf(".item", ".currency") + val files = listOf(".item", ".currency", ".head", ".chest", ".legs") for (fs in fileSystems) { for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.any { f.name.endsWith(it) } }) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt index 18b881c2..0fc84c81 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt @@ -172,6 +172,61 @@ data class ItemDefinition( * Lua скрипты для выполнения */ val scripts: List = listOf(), + val animationScripts: List = listOf(), + + // ---------------- + // Броня + // ---------------- + + /** + * это где либо ещё применяется кроме брони? + */ + val tooltipKind: String? = null, + + /** + * Изначальный уровень, может быть изменён позднее чем угодно + */ + val level: Int? = null, + + /** + * Эффекты предмета, растущие с уровнем + */ + val leveledStatusEffects: List = listOf(), + + /** + * Варианты покраски (???) + */ + // val colorOptions: Map = mapOf(), + + /** + * Визуальные кадры анимации, когда надето на гуманоида мужского пола + */ + val maleFrames: ArmorFrames? = null, + + /** + * Визуальные кадры анимации, когда надето на гуманоида женского пола + */ + val femaleFrames: ArmorFrames? = null, + + // ---------------- + // /Броня + // ---------------- + + // ---------------- + // activeitem + // ---------------- + + // TODO: это указатель на структуру + val animation: String? = null, + + /** + * Занимает ли предмет обе руки + */ + val twoHanded: Boolean = false, + + // ---------------- + // /activeitem + // ---------------- /** * Прототип данного предмета, как JSON структура @@ -186,6 +241,18 @@ data class ItemDefinition( val description: String = "..." ) + data class ArmorFrames( + val body: String, + val backSleeve: String, + val frontSleeve: String, + ) + + data class StatusEffect( + val levelFunction: String, + val stat: String, + val baseMultiplier: Double, + ) + companion object { val ADAPTER = KConcreteTypeAdapter.Builder(ItemDefinition::class) .plain(ItemDefinition::itemName) @@ -205,7 +272,7 @@ data class ItemDefinition( .list(ItemDefinition::pickupQuestTemplates) .plain(ItemDefinition::race) - .plain(ItemDefinition::displayImage, Starbound::readingFolderTransformerNullable) + .plain(ItemDefinition::displayImage, transformer = Starbound::readingFolderTransformerNullable) .plain(ItemDefinition::displayoffset) .plain(ItemDefinition::fossilSetName) .plain(ItemDefinition::setIndex) @@ -227,6 +294,17 @@ data class ItemDefinition( .plain(ItemDefinition::value) .list(ItemDefinition::scripts, transformer = Starbound::readingFolderListTransformer) + .list(ItemDefinition::animationScripts, transformer = Starbound::readingFolderListTransformer) + + .plain(ItemDefinition::tooltipKind) + .plain(ItemDefinition::level) + .list(ItemDefinition::leveledStatusEffects) + // .map(ItemDefinition::colorOptions) + .plain(ItemDefinition::maleFrames) + .plain(ItemDefinition::femaleFrames) + + .plain(ItemDefinition::animation, transformer = Starbound::readingFolderTransformerNullable) + .plain(ItemDefinition::twoHanded) .storesJson() @@ -239,9 +317,23 @@ data class ItemDefinition( .specifyStringInterner(ADAPTER.stringInterner) .build() + val ARMOR_FRAMES_ADAPTER = KConcreteTypeAdapter.Builder(ArmorFrames::class) + .plain(ArmorFrames::body, transformer = Starbound::readingFolderTransformer) + .plain(ArmorFrames::backSleeve, transformer = Starbound::readingFolderTransformer) + .plain(ArmorFrames::frontSleeve, transformer = Starbound::readingFolderTransformer) + .build() + + val STATUS_EFFECT_ADAPTER = KConcreteTypeAdapter.Builder(StatusEffect::class) + .plain(StatusEffect::levelFunction) + .plain(StatusEffect::stat) + .plain(StatusEffect::baseMultiplier) + .build() + fun registerGson(gsonBuilder: GsonBuilder) { gsonBuilder.registerTypeAdapter(ADAPTER) gsonBuilder.registerTypeAdapter(FOSSIL_ADAPTER) + gsonBuilder.registerTypeAdapter(ARMOR_FRAMES_ADAPTER) + gsonBuilder.registerTypeAdapter(STATUS_EFFECT_ADAPTER) } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt index 0b6dad23..b5efc66e 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt @@ -338,19 +338,11 @@ class KConcreteTypeAdapter private constructor( if (!iterator.hasNext()) { val name = fieldId.toString() - if (loggedMisses.add(name)) { - if (storesJson) { - if (currentSymbolicName == null) { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field, it will be only visible to Lua scripts") - } else { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field, it will be only visible to Lua scripts (reading: $currentSymbolicName)") - } + if (!storesJson && loggedMisses.add(name)) { + if (currentSymbolicName == null) { + LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field") } else { - if (currentSymbolicName == null) { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field") - } else { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field (reading: $currentSymbolicName)") - } + LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field (reading: $currentSymbolicName)") } } @@ -392,19 +384,11 @@ class KConcreteTypeAdapter private constructor( val fieldId = mapped.getInt(name) if (fieldId == -1) { - if (loggedMisses.add(name)) { - if (storesJson) { - if (currentSymbolicName == null) { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field, it will be only visible to Lua scripts") - } else { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field, it will be only visible to Lua scripts (reading: $currentSymbolicName)") - } + if (!storesJson && loggedMisses.add(name)) { + if (currentSymbolicName == null) { + LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field") } else { - if (currentSymbolicName == null) { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field") - } else { - LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field (reading: $currentSymbolicName)") - } + LOGGER.warn("Skipping JSON field with name $name because ${bound.simpleName} has no such field (reading: $currentSymbolicName)") } } @@ -636,6 +620,20 @@ class KConcreteTypeAdapter private constructor( return this } + /** + * Добавляет поле-таблицу, кодирование зависит от контекста: + * * Если [K] является [String], кодирование происходит как Json Object + * * Иначе кодирование происходит как Json Array + * + * Таблица неизменяема (создаётся объект [ImmutableMap]) + */ + inline fun map(field: KProperty1>): Builder { + if (K::class == String::class) + return this.map(field as KProperty1?>, V::class.java) + + return this.map(field, K::class.java, V::class.java) + } + /** * Добавляет поле-таблицу, которое кодируется как [[key, value], [key, value], ...] *