232 lines
8.6 KiB
Kotlin
232 lines
8.6 KiB
Kotlin
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<Int, String>,
|
|
buildingData: List<RgdData>,
|
|
weapons: Set<Weapon>,
|
|
race: String,
|
|
modFolderData: String,
|
|
mod: Mod,
|
|
races: List<Race>,
|
|
armorTypes: List<ArmorType>,
|
|
addonsRgdData: Map<String, List<RgdData>>,
|
|
): 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<RgdData>,
|
|
armorTypes: Iterable<ArmorType>,
|
|
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<RgdData>): 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<RgdData>, modDictionary: Map<Int, String>): 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<RgdData>): 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<RgdData>): Double? = unitData
|
|
.getRgdTableByName("sight_ext")
|
|
?.getDoubleByName("sight_radius")
|
|
|
|
private fun getDetectRadius(unitData: List<RgdData>): Double? = unitData
|
|
.getRgdTableByName("sight_ext")
|
|
?.getDoubleByName("keen_sight_radius")
|
|
|
|
|
|
private fun getBuildingWeapon(buildingData: List<RgdData>?): List<WeaponsData>? = 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<RgdData>
|
|
hardpointTable.getRgdTableByName("weapon_table")?.let {
|
|
it.mapNotNull { weapon ->
|
|
(weapon.value as? List<RgdData>)?.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<RgdData>, 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<RgdData>): List<String>? = buildingData
|
|
.getRgdTableByName("addon_ext")
|
|
?.getRgdTableByName("addons")
|
|
?.mapNotNull { addon ->
|
|
if (addon.value != "") {
|
|
addon.value.toString()
|
|
.replace("addons\\", "")
|
|
.replace(".lua", "")
|
|
.plus(".rgd")
|
|
} else null
|
|
}
|
|
}
|
|
|