хз, всё равно надо что то другое

This commit is contained in:
DBotThePony 2023-02-08 14:51:15 +07:00
parent c3756b259a
commit bd690ee56c
Signed by: DBot
GPG Key ID: DCC23B5715498507
28 changed files with 273 additions and 582 deletions

View File

@ -162,8 +162,6 @@ class Starbound : ISBFileLocator {
registerTypeAdapter(JsonFunction.Companion) registerTypeAdapter(JsonFunction.Companion)
// Общее // Общее
registerTypeAdapterFactory(LeveledStatusEffect.ADAPTER)
registerTypeAdapter(MaterialReference.Companion)
registerTypeAdapterFactory(ThingDescription.Factory(stringInterner)) registerTypeAdapterFactory(ThingDescription.Factory(stringInterner))
registerTypeAdapter(EnumAdapter(DamageType::class, default = DamageType.NORMAL)) registerTypeAdapter(EnumAdapter(DamageType::class, default = DamageType.NORMAL))
@ -172,7 +170,7 @@ class Starbound : ISBFileLocator {
registerTypeAdapter(spriteRegistry) registerTypeAdapter(spriteRegistry)
registerTypeAdapterFactory(IItemDefinition.InventoryIcon.Factory(pathStack, spriteRegistry)) registerTypeAdapterFactory(IItemDefinition.InventoryIcon.Factory(pathStack, spriteRegistry))
registerTypeAdapterFactory(IArmorItemDefinition.ArmorFrames.Factory(pathStack, this@Starbound::atlasRegistry)) registerTypeAdapterFactory(IArmorItemDefinition.Frames.Factory(pathStack, this@Starbound::atlasRegistry))
registerTypeAdapterFactory(DirectAssetReferenceFactory(pathStack)) registerTypeAdapterFactory(DirectAssetReferenceFactory(pathStack))
registerTypeAdapter(ImageReference.Adapter(pathStack, this@Starbound::atlasRegistry)) registerTypeAdapter(ImageReference.Adapter(pathStack, this@Starbound::atlasRegistry))

View File

@ -0,0 +1,107 @@
package ru.dbotthepony.kstarbound.defs
import ru.dbotthepony.kstarbound.io.json.builder.JsonIgnoreProperty
import ru.dbotthepony.kstarbound.util.INotNullDelegate
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
abstract class DefinitionBuilder {
interface IProperty {
fun checkAndThrow()
}
inner class Nullable<V>(private var value: V? = null) : ReadWriteProperty<Any?, V?>, IProperty {
override fun getValue(thisRef: Any?, property: KProperty<*>): V? {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V?) {
if (isFrozen) throw IllegalStateException("$thisRef is frozen!")
this.value = value
}
override fun checkAndThrow() {
// no op
}
override fun equals(other: Any?): Boolean {
return other is Nullable<*> && other.value == value
}
override fun hashCode(): Int {
return value?.hashCode() ?: 0
}
override fun toString(): String {
return "Nullable[$value]"
}
}
inner class NotNull<V : Any>(private var value: V? = null) : ReadWriteProperty<Any?, V>, IProperty, INotNullDelegate {
override val isPresent: Boolean
get() = value != null
fun getNullable(): V? {
return value
}
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return checkNotNull(value) {"${property.name} was not initialized"}
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
if (isFrozen) throw IllegalStateException("$thisRef is frozen!")
this.value = value
}
override fun checkAndThrow() {
if (value == null) {
throw NullPointerException("Value was not initialized")
}
}
override fun equals(other: Any?): Boolean {
return other is NotNull<*> && other.value == value
}
override fun hashCode(): Int {
return value?.hashCode() ?: 0
}
override fun toString(): String {
return "NotNull[$value]"
}
}
@JsonIgnoreProperty
var isFrozen = false
private set
@JsonIgnoreProperty
private val properties = ArrayList<IProperty>()
override fun equals(other: Any?): Boolean {
if (other is DefinitionBuilder && other.javaClass === this.javaClass)
return other.properties == properties
return false
}
override fun hashCode(): Int {
return properties.hashCode()
}
override fun toString(): String {
return "${this::class.simpleName}[frozen=$isFrozen,values={${properties.joinToString(",")}}]"
}
protected open fun onFreeze() {
}
fun freeze() {
if (isFrozen) return
onFreeze()
isFrozen = true
}
}

View File

@ -8,6 +8,11 @@ import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.util.PathStack import ru.dbotthepony.kstarbound.util.PathStack
/**
* Путь как указан в JSON + Абсолютный путь
*
* @see DirectAssetReference
*/
class DirectAssetReferenceFactory(val remapper: PathStack) : TypeAdapterFactory { class DirectAssetReferenceFactory(val remapper: PathStack) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == DirectAssetReference::class.java) { if (type.rawType == DirectAssetReference::class.java) {
@ -33,4 +38,7 @@ class DirectAssetReferenceFactory(val remapper: PathStack) : TypeAdapterFactory
} }
} }
/**
* Путь как указан в JSON + Абсолютный путь
*/
data class DirectAssetReference(val path: String, val fullPath: String) data class DirectAssetReference(val path: String, val fullPath: String)

View File

@ -1,36 +0,0 @@
package ru.dbotthepony.kstarbound.defs
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
data class MaterialReference(
val id: Int?,
val name: String?
) {
init {
require(id != null || name != null) { "At least ID or material string ID should be not null" }
}
companion object : TypeAdapter<MaterialReference>() {
override fun write(out: JsonWriter, value: MaterialReference) {
if (value.id != null) {
out.value(value.id)
} else {
out.value(value.name!!)
}
}
override fun read(`in`: JsonReader): MaterialReference {
if (`in`.peek() == JsonToken.NUMBER) {
return MaterialReference(id = `in`.nextInt(), name = null)
} else if (`in`.peek() == JsonToken.STRING) {
return MaterialReference(id = null, name = `in`.nextString())
} else {
throw JsonSyntaxException("Invalid material reference: ${`in`.peek()} (must be either an Integer or String), near ${`in`.path}")
}
}
}
}

View File

@ -1,35 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.DirectAssetReference
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription
data class ArmorItemDefinition(
override val itemName: String,
override val price: Long,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: List<IItemDefinition.IInventoryIcon>?,
override val itemTags: List<String>,
override val learnBlueprintsOnPickup: List<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: List<String>,
override val scripts: List<DirectAssetReference>,
override val scriptDelta: Int,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: List<String>,
override val fuelAmount: Long?,
override val colorOptions: List<Map<String, String>>,
override val maleFrames: IArmorItemDefinition.IArmorFrames,
override val femaleFrames: IArmorItemDefinition.IArmorFrames,
override val level: Double,
override val leveledStatusEffects: List<ILeveledStatusEffect>,
override val armorType: ArmorPieceType,
val descriptionData: ThingDescription,
) : IArmorItemDefinition, IThingWithDescription by descriptionData

View File

@ -2,85 +2,45 @@ package ru.dbotthepony.kstarbound.defs.item
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.DirectAssetReference import ru.dbotthepony.kstarbound.defs.DirectAssetReference
import ru.dbotthepony.kstarbound.defs.util.enrollMap
import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder
import ru.dbotthepony.kstarbound.io.json.builder.JsonIgnoreProperty import ru.dbotthepony.kstarbound.io.json.builder.JsonIgnoreProperty
import ru.dbotthepony.kstarbound.util.NotNullVar
@JsonBuilder @JsonBuilder
open class ArmorItemPrototype : ItemPrototype(), IArmorItemDefinition { abstract class ArmorItemPrototype : ItemPrototype(), IArmorItemDefinition {
override var colorOptions: ImmutableList<Map<String, String>> = ImmutableList.of() override var colorOptions: ImmutableList<Map<String, String>> by NotNull(ImmutableList.of())
override var maleFrames: IArmorItemDefinition.ArmorFrames by NotNullVar() override var maleFrames: IArmorItemDefinition.Frames by NotNull()
override var femaleFrames: IArmorItemDefinition.ArmorFrames by NotNullVar() override var femaleFrames: IArmorItemDefinition.Frames by NotNull()
override var level: Double = 1.0 override var level: Double by NotNull(1.0)
override var leveledStatusEffects: ImmutableList<LeveledStatusEffect> = ImmutableList.of() override var leveledStatusEffects: ImmutableList<LeveledStatusEffect> by NotNull(ImmutableList.of())
override var scripts: ImmutableList<DirectAssetReference> = ImmutableList.of() override var scripts: ImmutableList<DirectAssetReference> by NotNull(ImmutableList.of())
override var scriptDelta: Int = 1 override var scriptDelta: Int by NotNull(1)
@JsonIgnoreProperty
override var armorType: ArmorPieceType by NotNullVar()
init { init {
maxStack = 1L maxStack = 1L
} }
override fun assemble(): IItemDefinition {
return ArmorItemDefinition(
descriptionData = descriptionData,
itemName = itemName,
price = price,
rarity = rarity,
category = category,
inventoryIcon = inventoryIcon,
itemTags = itemTags,
learnBlueprintsOnPickup = learnBlueprintsOnPickup,
maxStack = maxStack,
eventCategory = eventCategory,
consumeOnPickup = consumeOnPickup,
pickupQuestTemplates = pickupQuestTemplates,
scripts = scripts,
scriptDelta = scriptDelta,
tooltipKind = tooltipKind,
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount,
colorOptions = colorOptions,
maleFrames = maleFrames,
femaleFrames = femaleFrames,
level = level,
leveledStatusEffects = leveledStatusEffects,
armorType = armorType,
)
}
} }
@JsonBuilder @JsonBuilder
class HeadArmorItemPrototype : ArmorItemPrototype() { class HeadArmorItemPrototype : ArmorItemPrototype() {
init { @JsonIgnoreProperty
armorType = ArmorPieceType.HEAD override val armorType: ArmorPieceType = ArmorPieceType.HEAD
}
} }
@JsonBuilder @JsonBuilder
class ChestArmorItemPrototype : ArmorItemPrototype() { class ChestArmorItemPrototype : ArmorItemPrototype() {
init { @JsonIgnoreProperty
armorType = ArmorPieceType.CHEST override val armorType: ArmorPieceType = ArmorPieceType.CHEST
}
} }
@JsonBuilder @JsonBuilder
class LegsArmorItemPrototype : ArmorItemPrototype() { class LegsArmorItemPrototype : ArmorItemPrototype() {
init { @JsonIgnoreProperty
armorType = ArmorPieceType.LEGS override val armorType: ArmorPieceType = ArmorPieceType.LEGS
}
} }
@JsonBuilder @JsonBuilder
class BackArmorItemPrototype : ArmorItemPrototype() { class BackArmorItemPrototype : ArmorItemPrototype() {
init { @JsonIgnoreProperty
armorType = ArmorPieceType.BACK override val armorType: ArmorPieceType = ArmorPieceType.BACK
}
} }

View File

@ -1,32 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription
data class CurrencyItemDefinition(
override val itemName: String,
override val price: Long,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: List<IItemDefinition.IInventoryIcon>?,
override val itemTags: List<String>,
override val learnBlueprintsOnPickup: List<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: List<String>,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: List<String>,
override val fuelAmount: Long?,
override val pickupSoundsSmall: List<String>,
override val pickupSoundsMedium: List<String>,
override val pickupSoundsLarge: List<String>,
override val smallStackLimit: Long,
override val mediumStackLimit: Long,
override val currency: String,
override val value: Long,
val descriptionData: ThingDescription,
) : ICurrencyItemDefinition, IThingWithDescription by descriptionData

View File

@ -8,44 +8,10 @@ import ru.dbotthepony.kstarbound.util.NotNullVar
@JsonBuilder @JsonBuilder
class CurrencyItemPrototype : ItemPrototype(), ICurrencyItemDefinition { class CurrencyItemPrototype : ItemPrototype(), ICurrencyItemDefinition {
override var pickupSoundsSmall: ImmutableList<String> = ImmutableList.of() override var currency: String by NotNull()
override var pickupSoundsMedium: ImmutableList<String> = ImmutableList.of() override var value: Long by NotNull()
override var pickupSoundsLarge: ImmutableList<String> = ImmutableList.of()
override var smallStackLimit: Long by NotNullVar()
override var mediumStackLimit: Long by NotNullVar()
override var currency: String by NotNullVar()
override var value: Long by NotNullVar()
init { init {
maxStack = 16777216L maxStack = 16777216L
} }
override fun assemble(): IItemDefinition {
return CurrencyItemDefinition(
descriptionData = descriptionData,
itemName = itemName,
price = price,
rarity = rarity,
category = category,
inventoryIcon = inventoryIcon,
itemTags = itemTags,
learnBlueprintsOnPickup = learnBlueprintsOnPickup,
maxStack = maxStack,
eventCategory = eventCategory,
consumeOnPickup = consumeOnPickup,
pickupQuestTemplates = pickupQuestTemplates,
tooltipKind = tooltipKind,
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount,
pickupSoundsSmall = pickupSoundsSmall,
pickupSoundsMedium = pickupSoundsMedium,
pickupSoundsLarge = pickupSoundsLarge,
smallStackLimit = smallStackLimit,
mediumStackLimit = mediumStackLimit,
currency = currency,
value = value,
)
}
} }

View File

@ -1,33 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
data class FlashlightDefinition(
override val itemName: String,
override val price: Long,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: ImmutableList<out IItemDefinition.IInventoryIcon>?,
override val itemTags: ImmutableList<String>,
override val learnBlueprintsOnPickup: ImmutableList<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: ImmutableList<String>,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: ImmutableList<String>,
override val fuelAmount: Long?,
override val lightPosition: Vector2d,
override val lightColor: Color,
override val beamLevel: Int,
override val beamAmbience: Double,
override val handPosition: Vector2d,
val descriptionData: ThingDescription,
) : IFlashlightDefinition, IThingWithDescription by descriptionData

View File

@ -8,40 +8,13 @@ import ru.dbotthepony.kvector.vector.ndouble.Vector2d
@JsonBuilder @JsonBuilder
class FlashlightPrototype : ItemPrototype(), IFlashlightDefinition { class FlashlightPrototype : ItemPrototype(), IFlashlightDefinition {
override var lightPosition: Vector2d by NotNullVar() override var lightPosition: Vector2d by NotNull()
override var lightColor: Color by NotNullVar() override var lightColor: Color by NotNull()
override var beamLevel: Int by NotNullVar() override var beamLevel: Int by NotNull()
override var beamAmbience: Double by NotNullVar() override var beamAmbience: Double by NotNull()
override var handPosition: Vector2d by NotNullVar() override var handPosition: Vector2d by NotNull()
init { init {
maxStack = 1L maxStack = 1L
} }
override fun assemble(): IItemDefinition {
return FlashlightDefinition(
descriptionData = descriptionData,
itemName = itemName,
price = price,
rarity = rarity,
category = category,
inventoryIcon = inventoryIcon,
itemTags = itemTags,
learnBlueprintsOnPickup = learnBlueprintsOnPickup,
maxStack = maxStack,
eventCategory = eventCategory,
consumeOnPickup = consumeOnPickup,
pickupQuestTemplates = pickupQuestTemplates,
tooltipKind = tooltipKind,
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount,
lightPosition = lightPosition,
lightColor = lightColor,
beamLevel = beamLevel,
beamAmbience = beamAmbience,
handPosition = handPosition,
)
}
} }

View File

@ -1,36 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
data class HarvestingToolDefinition(
override val itemName: String,
override val price: Long = 4L,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: ImmutableList<out IItemDefinition.IInventoryIcon>?,
override val itemTags: ImmutableList<String>,
override val learnBlueprintsOnPickup: ImmutableList<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: ImmutableList<String>,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: ImmutableList<String>,
override val fuelAmount: Long?,
override val frames: Int,
override val animationCycle: Double,
override val blockRadius: Int,
override val altBlockRadius: Int,
override val idleSound: ImmutableList<String>,
override val strikeSounds: ImmutableList<String>,
override val handPosition: Vector2d,
override val fireTime: Double,
val descriptionData: ThingDescription,
) : IHarvestingToolDefinition, IThingWithDescription by descriptionData

View File

@ -8,46 +8,16 @@ import ru.dbotthepony.kvector.vector.ndouble.Vector2d
@JsonBuilder @JsonBuilder
class HarvestingToolPrototype : ItemPrototype(), IHarvestingToolDefinition { class HarvestingToolPrototype : ItemPrototype(), IHarvestingToolDefinition {
override var frames: Int by NotNullVar() override var frames: Int by NotNull()
override var animationCycle: Double by NotNullVar() override var animationCycle: Double by NotNull()
override var blockRadius: Int by NotNullVar() override var blockRadius: Int by NotNull()
override var altBlockRadius: Int = 0 override var altBlockRadius: Int by NotNull(0)
override var idleSound: ImmutableList<String> = ImmutableList.of() override var idleSound: ImmutableList<String> by NotNull(ImmutableList.of())
override var strikeSounds: ImmutableList<String> = ImmutableList.of() override var strikeSounds: ImmutableList<String> by NotNull(ImmutableList.of())
override var handPosition: Vector2d by NotNullVar() override var handPosition: Vector2d by NotNull()
override var fireTime: Double by NotNullVar() override var fireTime: Double by NotNull()
init { init {
maxStack = 1L maxStack = 1L
} }
override fun assemble(): IItemDefinition {
return HarvestingToolDefinition(
descriptionData = descriptionData,
itemName = itemName,
price = price,
rarity = rarity,
category = category,
inventoryIcon = inventoryIcon,
itemTags = itemTags,
learnBlueprintsOnPickup = learnBlueprintsOnPickup,
maxStack = maxStack,
eventCategory = eventCategory,
consumeOnPickup = consumeOnPickup,
pickupQuestTemplates = pickupQuestTemplates,
tooltipKind = tooltipKind,
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount,
frames = frames,
animationCycle = animationCycle,
blockRadius = blockRadius,
altBlockRadius = altBlockRadius,
idleSound = idleSound,
strikeSounds = strikeSounds,
handPosition = handPosition,
fireTime = fireTime,
)
}
} }

View File

@ -27,50 +27,50 @@ interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefiniti
/** /**
* Визуальные кадры анимации, когда надето на гуманоида мужского пола * Визуальные кадры анимации, когда надето на гуманоида мужского пола
*/ */
val maleFrames: IArmorFrames val maleFrames: IFrames
/** /**
* Визуальные кадры анимации, когда надето на гуманоида женского пола * Визуальные кадры анимации, когда надето на гуманоида женского пола
*/ */
val femaleFrames: IArmorFrames val femaleFrames: IFrames
@JsonImplementation(ArmorFrames::class) @JsonImplementation(Frames::class)
interface IArmorFrames { interface IFrames {
val body: ImageReference val body: ImageReference
val backSleeve: ImageReference? val backSleeve: ImageReference?
val frontSleeve: ImageReference? val frontSleeve: ImageReference?
} }
data class ArmorFrames( data class Frames(
override val body: ImageReference, override val body: ImageReference,
override val backSleeve: ImageReference? = null, override val backSleeve: ImageReference? = null,
override val frontSleeve: ImageReference? = null, override val frontSleeve: ImageReference? = null,
) : IArmorFrames { ) : IFrames {
class Factory(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapterFactory { class Factory(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == ArmorFrames::class.java) { if (type.rawType == Frames::class.java) {
return object : TypeAdapter<ArmorFrames>() { return object : TypeAdapter<Frames>() {
private val adapter = FactoryAdapter.Builder( private val adapter = FactoryAdapter.Builder(
ArmorFrames::class, Frames::class,
ArmorFrames::body, Frames::body,
ArmorFrames::backSleeve, Frames::backSleeve,
ArmorFrames::frontSleeve, Frames::frontSleeve,
).build(gson) ).build(gson)
override fun write(out: JsonWriter, value: ArmorFrames?) { override fun write(out: JsonWriter, value: Frames?) {
if (value == null) if (value == null)
out.nullValue() out.nullValue()
else else
adapter.write(out, value) adapter.write(out, value)
} }
override fun read(`in`: JsonReader): ArmorFrames? { override fun read(`in`: JsonReader): Frames? {
if (`in`.peek() == JsonToken.NULL) if (`in`.peek() == JsonToken.NULL)
return null return null
if (`in`.peek() == JsonToken.STRING) { if (`in`.peek() == JsonToken.STRING) {
val path = remapper.remap(`in`.nextString()) val path = remapper.remap(`in`.nextString())
return ArmorFrames(ImageReference(path, atlasRegistry.invoke().get(path)), null, null) return Frames(ImageReference(path, atlasRegistry.invoke().get(path)), null, null)
} }
return adapter.read(`in`) return adapter.read(`in`)

View File

@ -1,31 +1,6 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
interface ICurrencyItemDefinition : IItemDefinition { interface ICurrencyItemDefinition : IItemDefinition {
/**
* Звуки при поднятии "малого" количества предметов. Не имеет никакого смысла без [smallStackLimit]
*/
val pickupSoundsSmall: List<String>
/**
* Звуки при поднятии "среднего" количества предметов. Не имеет никакого смысла без [mediumStackLimit]
*/
val pickupSoundsMedium: List<String>
/**
* Звуки при поднятии "большого" количества предметов. Не имеет никакого смысла без [smallStackLimit] и без [mediumStackLimit]
*/
val pickupSoundsLarge: List<String>
/**
* Количество предметов ниже или равному данному значению проиграет звук [pickupSoundsSmall]
*/
val smallStackLimit: Long
/**
* Количество предметов ниже или равному данному значению (но не меньше [smallStackLimit]) проиграет звук [pickupSoundsMedium]
*/
val mediumStackLimit: Long
/** /**
* ID валюты * ID валюты
*/ */

View File

@ -8,6 +8,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.defs.IThingWithDescription import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.RegistryReference
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
@ -90,7 +91,7 @@ interface IItemDefinition : IThingWithDescription {
/** /**
* При подборе предмета мгновенно заставляет игрока изучить эти рецепты крафта * При подборе предмета мгновенно заставляет игрока изучить эти рецепты крафта
*/ */
val learnBlueprintsOnPickup: List<String> val learnBlueprintsOnPickup: List<RegistryReference<IItemDefinition>>
/** /**
* Максимальное количество предмета в стопке * Максимальное количество предмета в стопке
@ -133,4 +134,29 @@ interface IItemDefinition : IThingWithDescription {
* Топливо корабля * Топливо корабля
*/ */
val fuelAmount: Long? val fuelAmount: Long?
/**
* Звуки при поднятии "малого" количества предметов. Не имеет никакого смысла без [smallStackLimit]
*/
val pickupSoundsSmall: List<String>
/**
* Звуки при поднятии "среднего" количества предметов. Не имеет никакого смысла без [mediumStackLimit]
*/
val pickupSoundsMedium: List<String>
/**
* Звуки при поднятии "большого" количества предметов. Не имеет никакого смысла без [smallStackLimit] и без [mediumStackLimit]
*/
val pickupSoundsLarge: List<String>
/**
* Количество предметов ниже или равному данному значению проиграет звук [pickupSoundsSmall]
*/
val smallStackLimit: Long?
/**
* Количество предметов ниже или равному данному значению (но не меньше [smallStackLimit]) проиграет звук [pickupSoundsMedium]
*/
val mediumStackLimit: Long?
} }

View File

@ -1,7 +1,9 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
@JsonImplementation(LeveledStatusEffect::class)
interface ILeveledStatusEffect { interface ILeveledStatusEffect {
val levelFunction: String val levelFunction: String
val stat: String val stat: String
@ -9,17 +11,10 @@ interface ILeveledStatusEffect {
val amount: Double val amount: Double
} }
@JsonFactory
data class LeveledStatusEffect( data class LeveledStatusEffect(
override val levelFunction: String, override val levelFunction: String,
override val stat: String, override val stat: String,
override val baseMultiplier: Double = 1.0, override val baseMultiplier: Double = 1.0,
override val amount: Double = 0.0, override val amount: Double = 0.0,
) : ILeveledStatusEffect { ) : ILeveledStatusEffect
companion object {
val ADAPTER = FactoryAdapter.Builder(LeveledStatusEffect::class,
LeveledStatusEffect::levelFunction,
LeveledStatusEffect::stat,
LeveledStatusEffect::baseMultiplier,
LeveledStatusEffect::amount)
}
}

View File

@ -1,10 +1,10 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.MaterialReference import ru.dbotthepony.kstarbound.util.Either
interface ILiquidItem : IItemDefinition { interface ILiquidItem : IItemDefinition {
/** /**
* То, какую жидкость из себя представляет данный предмет * То, какую жидкость из себя представляет данный предмет
*/ */
val liquid: MaterialReference val liquid: Either<Int, String>
} }

View File

@ -1,10 +1,10 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.MaterialReference import ru.dbotthepony.kstarbound.util.Either
interface IMaterialItem : IItemDefinition { interface IMaterialItem : IItemDefinition {
/** /**
* То, какой материал (блок) из себя представляет данный предмет * То, какой материал (блок) из себя представляет данный предмет
*/ */
val material: MaterialReference val material: Either<Int, String>
} }

View File

@ -1,27 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonPropertyConfig
data class ItemDefinition(
override val itemName: String,
override val price: Long = 4L,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: ImmutableList<out IItemDefinition.IInventoryIcon>?,
override val itemTags: ImmutableList<String>,
override val learnBlueprintsOnPickup: ImmutableList<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: ImmutableList<String>,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: ImmutableList<String>,
override val fuelAmount: Long?,
val descriptionData: ThingDescription,
) : IItemDefinition, IThingWithDescription by descriptionData

View File

@ -1,6 +1,8 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.DefinitionBuilder
import ru.dbotthepony.kstarbound.defs.RegistryReference
import ru.dbotthepony.kstarbound.defs.ThingDescription import ru.dbotthepony.kstarbound.defs.ThingDescription
import ru.dbotthepony.kstarbound.defs.util.enrollMap import ru.dbotthepony.kstarbound.defs.util.enrollMap
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter
@ -11,49 +13,45 @@ import ru.dbotthepony.kstarbound.io.json.builder.JsonIgnoreProperty
import ru.dbotthepony.kstarbound.util.NotNullVar import ru.dbotthepony.kstarbound.util.NotNullVar
@JsonBuilder @JsonBuilder
open class ItemPrototype : IItemDefinition { open class ItemPrototype : DefinitionBuilder(), IItemDefinition {
@JsonIgnoreProperty @JsonIgnoreProperty
final override var shortdescription: String = "..." final override val shortdescription: String
@JsonIgnoreProperty get() = descriptionData.shortdescription
final override var description: String = "..."
final override var itemName: String by NotNullVar() @JsonIgnoreProperty
final override var price: Long = 0L final override val description: String
final override var rarity: ItemRarity = ItemRarity.COMMON get() = descriptionData.description
final override var category: String? = null
final override var inventoryIcon: ImmutableList<IItemDefinition.InventoryIcon>? = null @JsonIgnoreProperty
final override var itemTags: ImmutableList<String> = ImmutableList.of() final override val racialDescription: Map<String, String>
final override var learnBlueprintsOnPickup: ImmutableList<String> = ImmutableList.of() get() = descriptionData.racialDescription
final override var maxStack: Long = 9999L
final override var eventCategory: String? = null @JsonIgnoreProperty
final override var consumeOnPickup: Boolean = false final override val racialShortDescription: Map<String, String>
final override var pickupQuestTemplates: ImmutableList<String> = ImmutableList.of() get() = descriptionData.racialShortDescription
final override var tooltipKind: String = "normal"
final override var twoHanded: Boolean = false
final override var radioMessagesOnPickup: ImmutableList<String> = ImmutableList.of()
final override var fuelAmount: Long? = null
@JsonPropertyConfig(isFlat = true) @JsonPropertyConfig(isFlat = true)
var descriptionData: ThingDescription by NotNullVar() var descriptionData: ThingDescription by NotNullVar()
open fun assemble(): IItemDefinition { final override var itemName: String by NotNull()
return ItemDefinition( final override var price: Long by NotNull(0L)
descriptionData = descriptionData, final override var rarity: ItemRarity by NotNull(ItemRarity.COMMON)
itemName = itemName, final override var category: String? by Nullable()
price = price, final override var inventoryIcon: ImmutableList<IItemDefinition.InventoryIcon>? by Nullable()
rarity = rarity, final override var itemTags: ImmutableList<String> by NotNull(ImmutableList.of())
category = category, final override var learnBlueprintsOnPickup: ImmutableList<RegistryReference<IItemDefinition>> by NotNull(ImmutableList.of())
inventoryIcon = inventoryIcon, final override var maxStack: Long by NotNull(9999L)
itemTags = itemTags, final override var eventCategory: String? by Nullable()
learnBlueprintsOnPickup = learnBlueprintsOnPickup, final override var consumeOnPickup: Boolean by NotNull(false)
maxStack = maxStack, final override var pickupQuestTemplates: ImmutableList<String> by NotNull(ImmutableList.of())
eventCategory = eventCategory, final override var tooltipKind: String by NotNull("normal")
consumeOnPickup = consumeOnPickup, final override var twoHanded: Boolean by NotNull(false)
pickupQuestTemplates = pickupQuestTemplates, final override var radioMessagesOnPickup: ImmutableList<String> by NotNull(ImmutableList.of())
tooltipKind = tooltipKind, final override var fuelAmount: Long? by Nullable()
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup, final override var pickupSoundsSmall: ImmutableList<String> by NotNull(ImmutableList.of())
fuelAmount = fuelAmount, final override var pickupSoundsMedium: ImmutableList<String> by NotNull(ImmutableList.of())
) final override var pickupSoundsLarge: ImmutableList<String> by NotNull(ImmutableList.of())
} final override var smallStackLimit: Long? by Nullable()
final override var mediumStackLimit: Long? by Nullable()
} }

View File

@ -1,27 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.MaterialReference
import ru.dbotthepony.kstarbound.defs.ThingDescription
data class LiquidItemDefinition(
override val itemName: String,
override val price: Long,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: List<IItemDefinition.IInventoryIcon>?,
override val itemTags: List<String>,
override val learnBlueprintsOnPickup: List<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: List<String>,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: List<String>,
override val fuelAmount: Long?,
override val liquid: MaterialReference,
val descriptionData: ThingDescription,
) : ILiquidItem, IThingWithDescription by descriptionData

View File

@ -1,45 +1,24 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.MaterialReference
import ru.dbotthepony.kstarbound.defs.util.enrollMap
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter
import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder
import ru.dbotthepony.kstarbound.util.Either
@JsonBuilder @JsonBuilder
class LiquidItemPrototype : ItemPrototype() { class LiquidItemPrototype : ItemPrototype(), ILiquidItem {
var liquid: MaterialReference? = null private val liquidDelegate = NotNull<Either<Int, String>>()
override var liquid: Either<Int, String> by liquidDelegate
var liquidId: Int? var liquidId: Int?
get() = liquid?.id get() = liquidDelegate.getNullable()?.left
set(value) { set(value) { if (liquidDelegate.getNullable() == null) liquid = Either.left(value!!) }
if (liquid == null)
liquid = MaterialReference(id = value, name = null)
}
var liquidName: String? var liquidName: String?
get() = liquid?.name get() = liquidDelegate.getNullable()?.right
set(value) { liquid = MaterialReference(name = value, id = null) } set(value) { liquid = Either.right(value!!) }
override fun assemble(): IItemDefinition { override fun onFreeze() {
return LiquidItemDefinition( if (liquidDelegate.getNullable() == null) {
descriptionData = descriptionData, throw NullPointerException("no liquidId nor liquidName was defined")
itemName = itemName, }
price = price,
rarity = rarity,
category = category,
inventoryIcon = inventoryIcon,
itemTags = itemTags,
learnBlueprintsOnPickup = learnBlueprintsOnPickup,
maxStack = maxStack,
eventCategory = eventCategory,
consumeOnPickup = consumeOnPickup,
pickupQuestTemplates = pickupQuestTemplates,
tooltipKind = tooltipKind,
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount,
liquid = checkNotNull(liquid) { "Liquid is null (either 'liquidId' or 'liquidName' should be present, or 'liquid' itself)" },
)
} }
} }

View File

@ -1,27 +0,0 @@
package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.MaterialReference
import ru.dbotthepony.kstarbound.defs.ThingDescription
data class MaterialItemDefinition(
override val itemName: String,
override val price: Long,
override val rarity: ItemRarity,
override val category: String?,
override val inventoryIcon: List<IItemDefinition.IInventoryIcon>?,
override val itemTags: List<String>,
override val learnBlueprintsOnPickup: List<String>,
override val maxStack: Long,
override val eventCategory: String?,
override val consumeOnPickup: Boolean,
override val pickupQuestTemplates: List<String>,
override val tooltipKind: String,
override val twoHanded: Boolean,
override val radioMessagesOnPickup: List<String>,
override val fuelAmount: Long?,
override val material: MaterialReference,
val descriptionData: ThingDescription,
) : IMaterialItem, IThingWithDescription by descriptionData

View File

@ -1,45 +1,24 @@
package ru.dbotthepony.kstarbound.defs.item package ru.dbotthepony.kstarbound.defs.item
import ru.dbotthepony.kstarbound.defs.MaterialReference
import ru.dbotthepony.kstarbound.defs.util.enrollMap
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter
import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder
import ru.dbotthepony.kstarbound.util.Either
@JsonBuilder @JsonBuilder
class MaterialItemPrototype : ItemPrototype() { class MaterialItemPrototype : ItemPrototype(), IMaterialItem {
var material: MaterialReference? = null private val materialDelegate = NotNull<Either<Int, String>>()
override var material: Either<Int, String> by materialDelegate
var materialId: Int? var materialId: Int?
get() = material?.id get() = materialDelegate.getNullable()?.left
set(value) { set(value) { if (materialDelegate.getNullable() == null) material = Either.left(value!!) }
if (material == null)
material = MaterialReference(id = value, name = null)
}
var materialName: String? var materialName: String?
get() = material?.name get() = materialDelegate.getNullable()?.right
set(value) { material = MaterialReference(name = value, id = null) } set(value) { material = Either.right(value!!) }
override fun assemble(): IItemDefinition { override fun onFreeze() {
return MaterialItemDefinition( if (material == null) {
descriptionData = descriptionData, throw NullPointerException("no materialId nor materialName was defined")
itemName = itemName, }
price = price,
rarity = rarity,
category = category,
inventoryIcon = inventoryIcon,
itemTags = itemTags,
learnBlueprintsOnPickup = learnBlueprintsOnPickup,
maxStack = maxStack,
eventCategory = eventCategory,
consumeOnPickup = consumeOnPickup,
pickupQuestTemplates = pickupQuestTemplates,
tooltipKind = tooltipKind,
twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount,
material = checkNotNull(material) { "Material is null (either 'materialId' or 'materialName' should be present, or 'material' itself)" },
)
} }
} }

View File

@ -19,8 +19,10 @@ import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.defs.DefinitionBuilder
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter.Builder import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter.Builder
import ru.dbotthepony.kstarbound.util.INotNullDelegate
import ru.dbotthepony.kstarbound.util.NotNullVar import ru.dbotthepony.kstarbound.util.NotNullVar
import kotlin.properties.Delegates import kotlin.properties.Delegates
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -173,7 +175,7 @@ class BuilderAdapter<T : Any> private constructor(
val delegate = property.property.getDelegate(instance) val delegate = property.property.getDelegate(instance)
if (delegate is NotNullVar<*> && !delegate.isInitialized) { if (delegate is INotNullDelegate && !delegate.isPresent) {
throw JsonSyntaxException("${property.name} in ${instance::class.qualifiedName} can not be null, but it is missing from JSON structure") throw JsonSyntaxException("${property.name} in ${instance::class.qualifiedName} can not be null, but it is missing from JSON structure")
} else { } else {
try { try {
@ -185,6 +187,10 @@ class BuilderAdapter<T : Any> private constructor(
} }
} }
if (instance is DefinitionBuilder) {
instance.freeze()
}
return instance return instance
} }

View File

@ -0,0 +1,5 @@
package ru.dbotthepony.kstarbound.util
interface INotNullDelegate {
val isPresent: Boolean
}

View File

@ -7,13 +7,13 @@ import kotlin.properties.Delegates
/** /**
* Аналог [Delegates.notNull], но со свойством [isInitialized] * Аналог [Delegates.notNull], но со свойством [isInitialized]
*/ */
class NotNullVar<V : Any> : ReadWriteProperty<Any?, V> { class NotNullVar<V : Any> : ReadWriteProperty<Any?, V>, INotNullDelegate {
private var value: V? = null private var value: V? = null
/** /**
* Имеет ли данный делегат не-null значение * Имеет ли данный делегат не-null значение
*/ */
val isInitialized: Boolean override val isPresent: Boolean
get() = value != null get() = value != null
override fun getValue(thisRef: Any?, property: KProperty<*>): V { override fun getValue(thisRef: Any?, property: KProperty<*>): V {

View File

@ -6,7 +6,6 @@ import ru.dbotthepony.kbox2d.api.Manifold
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
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.world.World import ru.dbotthepony.kstarbound.world.World
class ItemEntity(world: World<*, *>, val def: IItemDefinition) : Entity(world) { class ItemEntity(world: World<*, *>, val def: IItemDefinition) : Entity(world) {