From 8f14dd9e629b2ea257b29373c81eae4594439638 Mon Sep 17 00:00:00 2001 From: Anibus Date: Wed, 21 May 2025 02:48:48 +0300 Subject: [PATCH] First day release changes - add addon requirements - add addon modifiers - fix bug with incorrect dps, when armourPiercing more than 100 - fix bug, when dmg radius show on point weapon --- .../dowstats/data/entities/AddonModifiers.kt | 4 +- ...{AddonRequires.kt => AddonRequirements.kt} | 11 ++- .../dowstats/data/entities/BuildingAddon.kt | 2 +- .../com/dowstats/data/entities/DowUnit.kt | 4 +- .../ModStorageIntegrationService.kt | 36 +++++++++- .../w40k/BuildingAddonRgdExtractService.kt | 71 +++++++++++++++--- .../dowstats/service/w40k/ModParserService.kt | 2 +- .../service/w40k/UnitRgdExtractService.kt | 5 +- .../service/w40k/WeaponRgdExtractService.kt | 9 ++- src/main/resources/db/0.0.2/schema/addon.json | 72 +++++++++++++++++++ src/main/resources/db/changelog-master.json | 4 ++ 11 files changed, 192 insertions(+), 28 deletions(-) rename src/main/kotlin/com/dowstats/data/entities/{AddonRequires.kt => AddonRequirements.kt} (75%) create mode 100644 src/main/resources/db/0.0.2/schema/addon.json diff --git a/src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt b/src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt index 1bb9ea5..319fccd 100644 --- a/src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt +++ b/src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt @@ -17,7 +17,7 @@ class AddonModifiers { @JsonIgnore var addon: BuildingAddon? = null - var references: String? = null + var reference: String? = null var usageType: String? = null - var value: String? = null + var value: Double? = null } diff --git a/src/main/kotlin/com/dowstats/data/entities/AddonRequires.kt b/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt similarity index 75% rename from src/main/kotlin/com/dowstats/data/entities/AddonRequires.kt rename to src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt index d148516..9f6f2c2 100644 --- a/src/main/kotlin/com/dowstats/data/entities/AddonRequires.kt +++ b/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt @@ -5,8 +5,8 @@ import jakarta.persistence.* @Entity -@Table(name = "addon_requires") -class AddonRequires { +@Table(name = "addon_requirements") +class AddonRequirements { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -16,10 +16,7 @@ class AddonRequires { @JoinColumn(name = "addon_id", nullable = false) @JsonIgnore var addon: BuildingAddon? = null - - var references: String? = null - + var reference: String? = null var replaceWhenDone: Boolean = false - - var value: String? = null + var value: Double? = null } diff --git a/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt b/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt index 76cc9df..184239b 100644 --- a/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt +++ b/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt @@ -31,7 +31,7 @@ class BuildingAddon { var addonModifiers: MutableSet? = null @OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL]) - var addonRequires: MutableSet? = null + var addonRequirements: MutableSet? = null var icon: String? = null diff --git a/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt b/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt index 5548df9..875da15 100644 --- a/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt +++ b/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt @@ -16,11 +16,11 @@ class DowUnit { @JoinColumn(name = "race_id", nullable = false) var race: Race? = null - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "armour_type_id", nullable = false) var armorType: ArmorType? = null - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "armour_type_2_id") var armorType2: ArmorType? = null diff --git a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt index db05562..8bfbedc 100644 --- a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt +++ b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt @@ -4,6 +4,7 @@ import com.dowstats.configuration.StorageConfig import com.dowstats.data.dto.integration.AvailableMods import com.dowstats.data.entities.Mod import com.dowstats.data.repositories.ModRepository +import com.dowstats.service.w40k.ModAttribPathService import com.dowstats.service.w40k.ModParserService import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue @@ -17,7 +18,10 @@ import java.io.FileOutputStream import java.io.InputStream import java.net.URL import java.nio.charset.StandardCharsets +import java.nio.file.Files import java.nio.file.Path +import java.nio.file.Paths +import java.nio.file.StandardCopyOption import java.util.zip.* @@ -26,6 +30,7 @@ class ModStorageIntegrationService( val modStorageConfig: StorageConfig, val modRepository: ModRepository, val modParserService: ModParserService, + val storageConfig: StorageConfig, ) { val objectMapper = jacksonObjectMapper() @@ -64,7 +69,7 @@ class ModStorageIntegrationService( it.name = "Dowstats balance mod" it.technicalName = toSave.technicalName }) - modParserService.parceModFilesAndSaveToDb(savedMod) + modParserService.parseModFilesAndSaveToDb(savedMod) } catch (e: Exception) { log.error("Error while download and extract mod", e) } @@ -76,7 +81,8 @@ class ModStorageIntegrationService( fun reloadMod(modId: Long) { val mod = modRepository.findById(modId).orElseThrow { IllegalArgumentException("Mod not found") } modRepository.clearModData(modId) - modParserService.parceModFilesAndSaveToDb(mod) + checkSgaAndExtract(mod) + modParserService.parseModFilesAndSaveToDb(mod) } @@ -94,11 +100,35 @@ class ModStorageIntegrationService( val modDirectoryTo = "$name$version" val fileStream = file.bytes.inputStream() unzip(fileStream, modDirectoryTo) - modParserService.parceModFilesAndSaveToDb(savedMod) + modParserService.parseModFilesAndSaveToDb(savedMod) log.info("${file.originalFilename} successfull uploaded. Name: $name, version: $version") } } + private fun checkSgaAndExtract(mod: Mod){ + val modDirectory = "${storageConfig.modStorage.replace("/", File.separator)}${File.separator}${mod.technicalName}${mod.version}" + File(modDirectory).listFiles()?.forEach { sgaFolder -> + if(sgaFolder.isDirectory && sgaFolder.name.endsWith(".sga")){ + // Перемещаем иконки + val iconFolder = sgaFolder.path + "${File.separator}Data${File.separator}art${File.separator}ui${File.separator}ingame" + if(File(iconFolder).exists()){ + val iconFolderDestination = iconFolder.replace(sgaFolder.name + File.separator, "") + Files.createDirectories(Paths.get(iconFolderDestination)) + FileSystemUtils.copyRecursively(Paths.get(iconFolder),Paths.get(iconFolderDestination)) + } + // Перемещаем атрибуты + val attribFolder = sgaFolder.path + "${File.separator}Data${File.separator}attrib" + if(File(attribFolder).exists()) { + val attribFolderDestination = attribFolder.replace(sgaFolder.name + File.separator, "") + Files.createDirectories(Paths.get(attribFolder)) + FileSystemUtils.copyRecursively(Paths.get(attribFolder),Paths.get(attribFolderDestination)) + } + // Удаляем остальное + FileSystemUtils.deleteRecursively(sgaFolder) + } + } + } + private fun downloadAndExtractMod(modTechName: String, version: String) { log.info("Downloading mod $modTechName") val urlString = "http://crosspick.ru/dow_stats_client/dow_stats_balance_mod/$modTechName.zip" diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt index 7566a4e..e031238 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt @@ -3,6 +3,7 @@ package com.dowstats.service.w40k import com.dowstats.data.dto.BuildCost import com.dowstats.data.entities.* import com.dowstats.data.rgd.RgdData +import com.dowstats.data.rgd.RgdDataUtil.getBooleanByName import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName import com.dowstats.data.rgd.RgdDataUtil.getStringByName @@ -50,14 +51,50 @@ class BuildingAddonRgdExtractService @Autowired constructor( addon.addonCostFaith = buildCost.faith addon.addonCostSouls = buildCost.souls addon.addonCostTime = buildCost.time + addon.addonModifiers = getAddonModifiers(addon, addonRgdData).toMutableSet() + addon.addonRequirements = getAddonRequirements(addon, addonRgdData).toMutableSet() val addonIcon = convertIconAndReturnPath(addonRgdData, modFolderData, mod.name) addon.icon = addonIcon - return addon } + private fun getAddonModifiers(addon: BuildingAddon, addonData: List): List { + val modifiers = addonData.getRgdTableByName("modifiers") + return modifiers?.mapNotNull { m -> + if (m.name.contains("modifier_")) { + val mTable = m.value as List + if (mTable.getStringByName("\$REF") == "modifiers\\no_modifier.lua") null else { + AddonModifiers().also { + it.addon = addon + it.reference = mTable.getStringByName("\$REF") + it.usageType = mTable.getRgdTableByName("usage_type")?.getStringByName("\$REF") + it.value = mTable.getDoubleByName("value") + } + } + } else null + } ?: emptyList() + } + + private fun getAddonRequirements(addon: BuildingAddon, addonData: List): List { + val requirements = addonData.getRgdTableByName("requirements") + return requirements?.mapNotNull { r -> + if (r.name.contains("required_")) { + val rTable = r.value as List + if (rTable.getStringByName("\$REF") == "requirements\\required_none.lua") null else { + AddonRequirements().also { + it.addon = addon + it.reference = rTable.getStringByName("\$REF") + it.replaceWhenDone = rTable.getBooleanByName("replace_when_done") == true + it.value = + if (it.reference == "requirements\\required_total_pop.lua") rTable.getDoubleByName("population_required") else null + } + } + } else null + } ?: emptyList() + } + private fun getAddonCost(addonData: List): BuildCost { @@ -79,16 +116,28 @@ class BuildingAddonRgdExtractService @Autowired constructor( val uiInfo = addonData.getRgdTableByName("ui_info") val nameRef = uiInfo?.getStringByName("screen_name_id")?.replace("$", "") - val name = nameRef?.let { try{modDictionary[it.toInt()]} catch (e: Exception) { null } } + 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 } } + ?.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) { + descriptionRefs?.map { modDictionary[it.toInt()] }?.joinToString("\n") + } catch (e: Exception) { log.warn("Error parsing ui description", e) null } @@ -97,7 +146,11 @@ class BuildingAddonRgdExtractService @Autowired constructor( } - private fun convertIconAndReturnPath(buildingData: List, modFolderData: String, modName: String?): String? { + private fun convertIconAndReturnPath( + buildingData: List, + modFolderData: String, + modName: String? + ): String? { val iconPathInMod = buildingData .getRgdTableByName("ui_info") ?.getStringByName("icon_name") @@ -106,7 +159,7 @@ class BuildingAddonRgdExtractService @Autowired constructor( val tgaIconPath = iconPathInMod?.let { val modIcon = modAttribPathService.getIconPath(modFolderData, it) - if(Path.of(modIcon).exists()) modIcon else + if (Path.of(modIcon).exists()) modIcon else modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it) } diff --git a/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt b/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt index f0929de..2f49a25 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt @@ -51,7 +51,7 @@ class ModParserService @Autowired constructor( val log = LoggerFactory.getLogger(ModParserService::class.java) @Transactional - fun parceModFilesAndSaveToDb(mod: Mod) { + fun parseModFilesAndSaveToDb(mod: Mod) { log.info("Start parse mod files ${mod.technicalName}:${mod.version}") diff --git a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt index c3e6f6f..9ddafce 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt @@ -169,7 +169,10 @@ class UnitRgdExtractService @Autowired constructor( ?.getRgdTableByName(armorTypeTableName) ?.getStringByName("\$REF") - return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") } + return armorTypes.find { it.id == armorType + ?.replace("TYPE_Armour\\tp_", "") + ?.replace("type_armour\\tp_", "") + ?.replace(".lua", "") } } private fun getBuildCost(unitData: List, squadData: List): BuildCost { diff --git a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt index efa98f8..11284fe 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.io.File +import java.math.BigDecimal import java.nio.file.Path import kotlin.io.path.exists @@ -107,7 +108,10 @@ class WeaponRgdExtractService @Autowired constructor( private fun getAreaEffectData(weaponData: List, armorTypes: Set, thisWeapon: Weapon): AreaEffectData { val areaEffect = weaponData.getRgdTableByName("area_effect") - val damageRadius = areaEffect?.getRgdTableByName("area_effect_information")?.getDoubleByName("radius") ?: 0.0 + + val areaEffectInformation = areaEffect?.getRgdTableByName("area_effect_information") + val cantHaveRadius = areaEffectInformation?.getRgdTableByName("area_type")?.getStringByName("\$REF")?.contains("tp_area_effect_point") == true + val damageRadius = if(cantHaveRadius) 0.0 else areaEffectInformation?.getDoubleByName("radius") ?: 0.0 val throwData = areaEffect?.getRgdTableByName("throw_data") val forceMin = throwData?.getDoubleByName("force_min") ?: 0.0 @@ -137,7 +141,8 @@ class WeaponRgdExtractService @Autowired constructor( val weaponArmourPiercing = WeaponArmorPiercing() weaponArmourPiercing.weapon = thisWeapon weaponArmourPiercing.armorType = it - weaponArmourPiercing.piercingValue = (weaponDmgMap[it.id] ?: defaultArmourPiercing)?.toBigDecimal() + val piercingValue = (weaponDmgMap[it.id] ?: defaultArmourPiercing)?.toBigDecimal() + weaponArmourPiercing.piercingValue = piercingValue?.let {pv -> if(pv <= BigDecimal(100)) pv else BigDecimal(100) } weaponArmourPiercing } diff --git a/src/main/resources/db/0.0.2/schema/addon.json b/src/main/resources/db/0.0.2/schema/addon.json new file mode 100644 index 0000000..69691b5 --- /dev/null +++ b/src/main/resources/db/0.0.2/schema/addon.json @@ -0,0 +1,72 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Rename addon columns", + "author": "anibus", + "changes": [ + { + "renameColumn": { + "newColumnName": "reference", + "oldColumnName": "references", + "tableName": "addon_modifiers" + } + },{ + "renameColumn": { + "newColumnName": "reference", + "oldColumnName": "references", + "tableName": "addon_requires" + } + } + ] + } + }, + { + "changeSet": { + "id": "Rename addon_requires table", + "author": "anibus", + "changes": [ + { + "renameTable": { + "oldTableName": "addon_requires", + "newTableName": "addon_requirements" + } + } + ] + } + }, + { + "changeSet": { + "id": "Change addon_requirements value type", + "author": "anibus", + "changes": [ + { + "dropColumn": { + "columns": [ + { + "column": { + "name": "value" + } + } + ], + "tableName": "addon_requirements" + } + }, + { + "addColumn": { + "columns": [ + { + "column": { + "name": "value", + "type": "number" + } + } + ], + "tableName": "addon_requirements" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/changelog-master.json b/src/main/resources/db/changelog-master.json index 1277c9d..e1f9f08 100644 --- a/src/main/resources/db/changelog-master.json +++ b/src/main/resources/db/changelog-master.json @@ -73,6 +73,10 @@ "include": { "file": "db/0.0.1/schema/procedure_delete_mod_data.json" } + },{ + "include": { + "file": "db/0.0.2/schema/addon.json" + } } ] }