package com.dowstats.service.w40k import com.dowstats.data.dto.BuildCost import com.dowstats.data.dto.BuildingDataToSave import com.dowstats.data.entities.* import com.dowstats.data.rgd.RgdData import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName import com.dowstats.data.rgd.RgdDataUtil.getIntByName import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName import com.dowstats.data.rgd.RgdDataUtil.getStringByName import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.io.File import java.nio.file.Path import kotlin.io.path.exists @Service class BuildingRgdExtractService @Autowired constructor( private val modAttribPathService: ModAttribPathService, private val iconsService: IconsService, private val addonRgdExtractService: BuildingAddonRgdExtractService, ) { val log = LoggerFactory.getLogger(BuildingRgdExtractService::class.java) data class HealthData( val hitpoints: Double?, val regeneration: Double?, val maxRepaires: Int?, ) data class WeaponsData( val hardpoint: Int, val hardpointOrder: Int, val weaponFilename: String, ) data class BuildingTexts( val name: String?, val description: String?, ) fun extractToBuildingEntity( fileName: String, modDictionary: Map, buildingData: List, weapons: Set, race: String, modFolderData: String, mod: Mod, races: List, armorTypes: List, addonsRgdData: Map>, ): BuildingDataToSave { val building = Building() val race = races.find { it.id == race } ?: throw Exception("Cant get race $race") building.race = race building.armorType = getBuildingArmourType(buildingData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") building.armorType2 = getBuildingArmourType(buildingData, armorTypes, "type_armour_2") val nameAndDescription = getBuildingNameAndDescription(buildingData, modDictionary) building.name = nameAndDescription.name building.description = nameAndDescription.description building.filename = fileName val buildCost = getBuildCost(buildingData) building.buildCostRequisition = buildCost.requisition building.buildCostPower = buildCost.power building.buildCostPopulation = buildCost.population building.buildCostFaith = buildCost.faith building.buildCostSouls = buildCost.souls building.buildCostTime = buildCost.time val healthData = getHealthData(buildingData) building.health = healthData.hitpoints?.toInt() building.healthRegeneration = healthData.regeneration building.sightRadius = getSightRadius(buildingData)?.toInt() building.detectRadius = getDetectRadius(buildingData)?.toInt() building.repairMax = healthData.maxRepaires val addons = getAddons(buildingData) building.addons = addons?.mapNotNull {addonFileName -> val addonRgdData = addonsRgdData[addonFileName] if(addonRgdData != null){ addonRgdExtractService.extractToAddonEntity(addonFileName, modDictionary, addonRgdData, modFolderData, building, mod) } else { log.warn("Can't find addon $addonFileName") null } }?.toMutableSet() val buildingIcon = convertIconAndReturnPath(buildingData, modFolderData, mod.name) building.icon = buildingIcon val buildingWeapons = getBuildingWeapon(buildingData)?.mapNotNull { weaponData -> weapons.find { it.filename == weaponData.weaponFilename + ".rgd" }?.also {wp -> building.weaponHardpoints.add(Weapon.HardpointPosition( wp.id!!, weaponData.hardpoint, weaponData.hardpointOrder)) } }.orEmpty().toSet() building.modId = mod.id return BuildingDataToSave(building, buildingWeapons) } private fun getBuildingArmourType( unitData: List, armorTypes: Iterable, armorTypeTableName: String ): ArmorType? { val armorType = unitData.getRgdTableByName("type_ext") ?.getRgdTableByName(armorTypeTableName) ?.getStringByName("\$REF") return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") } } private fun getBuildCost(buildingData: List): BuildCost { val cost = buildingData.getRgdTableByName("cost_ext") ?.getRgdTableByName("time_cost") val costResources = cost?.getRgdTableByName("cost") return BuildCost( costResources?.getDoubleByName("requisition"), costResources?.getDoubleByName("power"), costResources?.getDoubleByName("population"), costResources?.getDoubleByName("faith"), costResources?.getDoubleByName("souls"), cost?.getDoubleByName("time_seconds")?.toInt() ) } private fun getBuildingNameAndDescription(buildingData: List, modDictionary: Map): BuildingTexts { val uiInfo = buildingData.getRgdTableByName("ui_ext") ?.getRgdTableByName("ui_info") val nameRef = uiInfo?.getStringByName("screen_name_id")?.replace("$", "") val name = nameRef?.let { try{modDictionary[it.toInt()]} catch (e: Exception) { null } } val descriptionRefs = uiInfo?.getRgdTableByName("help_text_list") ?.map{(it.value as String).replace("$", "")} ?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""} ?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } } val description = try { descriptionRefs?.map { modDictionary[it.toInt()] }?.joinToString ( "\n" ) } catch(e:Exception) { log.warn("Error parsing ui description", e) null } return BuildingTexts(name, description) } private fun getHealthData(buildingData: List): HealthData { val healthExt = buildingData.getRgdTableByName("health_ext") return HealthData( healthExt?.getDoubleByName("hitpoints"), healthExt?.getDoubleByName("regeneration_rate"), healthExt?.getIntByName("max_repairers") ) } private fun getSightRadius(unitData: List): Double? = unitData .getRgdTableByName("sight_ext") ?.getDoubleByName("sight_radius") private fun getDetectRadius(unitData: List): Double? = unitData .getRgdTableByName("sight_ext") ?.getDoubleByName("keen_sight_radius") private fun getBuildingWeapon(buildingData: List?): List? = buildingData ?.getRgdTableByName("combat_ext") ?.getRgdTableByName("hardpoints") ?.mapNotNull { hardpoint -> if (hardpoint.name.contains("hardpoint_")) { val hardpointValue = hardpoint.name.replace("hardpoint_", "").toInt() val hardpointTable = hardpoint.value as List hardpointTable.getRgdTableByName("weapon_table")?.let { it.mapNotNull { weapon -> (weapon.value as? List)?.getStringByName("weapon")?.let { if (it != "") { WeaponsData(hardpointValue, weapon.name.replace("weapon_", "").toInt(), it.replace("weapon\\", "").replace(".lua", "")) } else null } } } } else null }?.flatten() private fun convertIconAndReturnPath(buildingData: List, modFolderData: String, modName: String?): String? { val iconPathInMod = buildingData .getRgdTableByName("ui_ext") ?.getRgdTableByName("ui_info") ?.getStringByName("icon_name") return iconPathInMod?.let { modAttribPathService.getIconPath(modFolderData, iconPathInMod) } ?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) } } private fun getAddons(buildingData: List): List? = buildingData .getRgdTableByName("addon_ext") ?.getRgdTableByName("addons") ?.mapNotNull { addon -> if (addon.value != "") { addon.value.toString() .replace("addons\\", "") .replace(".lua", "") .plus(".rgd") } else null } }