package ru.dbotthepony.kstarbound.defs.`object` import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableMap import com.google.common.collect.ImmutableSet import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.google.gson.JsonSyntaxException import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonWriter import ru.dbotthepony.kstarbound.Registry import ru.dbotthepony.kstarbound.defs.AssetPath import ru.dbotthepony.kstarbound.defs.ItemReference import ru.dbotthepony.kstarbound.defs.JsonReference import ru.dbotthepony.kstarbound.defs.StatModifier import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition import ru.dbotthepony.kstarbound.defs.tile.TileDamageConfig import ru.dbotthepony.kstarbound.json.builder.JsonFactory import ru.dbotthepony.kstarbound.json.consumeNull import ru.dbotthepony.kstarbound.json.listAdapter import ru.dbotthepony.kstarbound.json.stream import ru.dbotthepony.kstarbound.math.PeriodicFunction import ru.dbotthepony.kstarbound.util.Either import ru.dbotthepony.kstarbound.json.contains import ru.dbotthepony.kstarbound.json.get import ru.dbotthepony.kstarbound.json.getArray import ru.dbotthepony.kstarbound.json.set import ru.dbotthepony.kvector.vector.RGBAColor data class ObjectDefinition( val objectName: String, val objectType: ObjectType = ObjectType.OBJECT, val race: String = "generic", val category: String = "other", val colonyTags: ImmutableSet = ImmutableSet.of(), val scripts: ImmutableSet = ImmutableSet.of(), val animationScripts: ImmutableSet = ImmutableSet.of(), val hasObjectItem: Boolean = true, val scannable: Boolean = true, val retainObjectParametersInItem: Boolean = false, val breakDropPool: Registry.Ref? = null, // null - not specified, empty list - always drop nothing val breakDropOptions: ImmutableList>? = null, val smashDropPool: Registry.Ref? = null, val smashDropOptions: ImmutableList> = ImmutableList.of(), //val animation: AssetReference? = null, val animation: AssetPath? = null, val smashSounds: ImmutableSet = ImmutableSet.of(), val smashParticles: JsonArray? = null, val smashable: Boolean = false, val unbreakable: Boolean = false, val damageShakeMagnitude: Double = 0.2, val damageMaterialKind: String = "solid", val damageTeam: DamageTeam = DamageTeam(), val lightColor: RGBAColor? = null, val lightColors: ImmutableMap = ImmutableMap.of(), val pointLight: Boolean = false, val pointBeam: Double = 0.0, val beamAmbience: Double = 0.0, val soundEffect: AssetPath? = null, val soundEffectRangeMultiplier: Double = 1.0, val price: Long = 1L, val statusEffects: ImmutableList> = ImmutableList.of(), val touchDamage: JsonReference.Object = JsonReference.Object(null, null, null), val minimumLiquidLevel: Float? = null, val maximumLiquidLevel: Float? = null, val liquidCheckInterval: Float = 0.5f, val health: Double = 1.0, val rooting: Boolean = false, val biomePlaced: Boolean = false, val printable: Boolean = false, val smashOnBreak: Boolean = false, val damageConfig: TileDamageConfig, val flickerPeriod: PeriodicFunction? = null, val orientations: ImmutableList, ) { companion object { } class Adapter(gson: Gson) : TypeAdapter() { @JsonFactory(logMisses = false) class PlainData( val objectName: String, val objectType: ObjectType = ObjectType.OBJECT, val race: String = "generic", val category: String = "other", val colonyTags: ImmutableSet = ImmutableSet.of(), val scripts: ImmutableSet = ImmutableSet.of(), val animationScripts: ImmutableSet = ImmutableSet.of(), val hasObjectItem: Boolean = true, val scannable: Boolean = true, val retainObjectParametersInItem: Boolean = false, val breakDropPool: Registry.Ref? = null, // null - not specified, empty list - always drop nothing val breakDropOptions: ImmutableList>? = null, val smashDropPool: Registry.Ref? = null, val smashDropOptions: ImmutableList> = ImmutableList.of(), //val animation: AssetReference? = null, val animation: AssetPath? = null, val smashSounds: ImmutableSet = ImmutableSet.of(), val smashParticles: JsonArray? = null, val smashable: Boolean = false, val unbreakable: Boolean = false, val damageShakeMagnitude: Double = 0.2, val damageMaterialKind: String = "solid", val damageTeam: DamageTeam = DamageTeam(), val lightColor: RGBAColor? = null, val lightColors: ImmutableMap = ImmutableMap.of(), val pointLight: Boolean = false, val pointBeam: Double = 0.0, val beamAmbience: Double = 0.0, val soundEffect: AssetPath? = null, val soundEffectRangeMultiplier: Double = 1.0, val price: Long = 1L, val statusEffects: ImmutableList> = ImmutableList.of(), //val touchDamage: TouchDamage, val touchDamage: JsonReference.Object = JsonReference.Object(null, null, null), val minimumLiquidLevel: Float? = null, val maximumLiquidLevel: Float? = null, val liquidCheckInterval: Float = 0.5f, val health: Double = 1.0, val rooting: Boolean = false, val biomePlaced: Boolean = false, ) private val objects = gson.getAdapter(JsonObject::class.java) private val objectRef = gson.getAdapter(JsonReference.Object::class.java) private val basic = gson.getAdapter(PlainData::class.java) private val damageConfig = gson.getAdapter(TileDamageConfig::class.java) private val damageTeam = gson.getAdapter(DamageTeam::class.java) private val orientations = gson.getAdapter(ObjectOrientation::class.java) private val emitter = gson.getAdapter(ParticleEmissionEntry::class.java) private val emitters = gson.listAdapter() override fun write(out: JsonWriter, value: ObjectDefinition?) { if (value == null) { out.nullValue() } else { TODO() } } override fun read(`in`: JsonReader): ObjectDefinition? { if (`in`.consumeNull()) return null val read = objects.read(`in`) val basic = basic.fromJsonTree(read) val printable = basic.hasObjectItem && read.get("printable", basic.scannable) val smashOnBreak = read.get("smashOnBreak", basic.smashable) val getDamageParams = objectRef.fromJsonTree(read.get("damageTable", JsonPrimitive("/objects/defaultParameters.config:damageTable"))) getDamageParams?.value ?: throw JsonSyntaxException("No valid damageTable specified") getDamageParams.value["health"] = read["health"] getDamageParams.value["harvestLevel"] = read["harvestLevel"] val damageConfig = damageConfig.fromJsonTree(getDamageParams.value) val flickerPeriod = if ("flickerPeriod" in read) { PeriodicFunction( read.get("flickerPeriod", 0.0), read.get("flickerMinIntensity", 0.0), read.get("flickerMaxIntensity", 0.0), read.get("flickerPeriodVariance", 0.0), read.get("flickerIntensityVariance", 0.0), ) } else { null } val orientations = ObjectOrientation.preprocess(read.getArray("orientations")) .stream() .map { orientations.fromJsonTree(it) } .collect(ImmutableList.toImmutableList()) if ("particleEmitter" in read) { orientations.forEach { it.particleEmitters.add(emitter.fromJsonTree(read["particleEmitter"])) } } if ("particleEmitters" in read) { orientations.forEach { it.particleEmitters.addAll(emitters.fromJsonTree(read["particleEmitters"])) } } return ObjectDefinition( objectName = basic.objectName, objectType = basic.objectType, race = basic.race, category = basic.category, colonyTags = basic.colonyTags, scripts = basic.scripts, animationScripts = basic.animationScripts, hasObjectItem = basic.hasObjectItem, scannable = basic.scannable, retainObjectParametersInItem = basic.retainObjectParametersInItem, breakDropPool = basic.breakDropPool, breakDropOptions = basic.breakDropOptions, smashDropPool = basic.smashDropPool, smashDropOptions = basic.smashDropOptions, animation = basic.animation, smashSounds = basic.smashSounds, smashParticles = basic.smashParticles, smashable = basic.smashable, unbreakable = basic.unbreakable, damageShakeMagnitude = basic.damageShakeMagnitude, damageMaterialKind = basic.damageMaterialKind, damageTeam = basic.damageTeam, lightColor = basic.lightColor, lightColors = basic.lightColors, pointLight = basic.pointLight, pointBeam = basic.pointBeam, beamAmbience = basic.beamAmbience, soundEffect = basic.soundEffect, soundEffectRangeMultiplier = basic.soundEffectRangeMultiplier, price = basic.price, statusEffects = basic.statusEffects, touchDamage = basic.touchDamage, minimumLiquidLevel = basic.minimumLiquidLevel, maximumLiquidLevel = basic.maximumLiquidLevel, liquidCheckInterval = basic.liquidCheckInterval, health = basic.health, rooting = basic.rooting, biomePlaced = basic.biomePlaced, printable = printable, smashOnBreak = smashOnBreak, damageConfig = damageConfig, flickerPeriod = flickerPeriod, orientations = orientations, ) } } }