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
This commit is contained in:
Anibus 2025-05-21 02:48:48 +03:00
parent fb94b26c83
commit 8f14dd9e62
11 changed files with 192 additions and 28 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -31,7 +31,7 @@ class BuildingAddon {
var addonModifiers: MutableSet<AddonModifiers>? = null
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
var addonRequires: MutableSet<AddonRequires>? = null
var addonRequirements: MutableSet<AddonRequirements>? = null
var icon: String? = null

View File

@ -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

View File

@ -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"

View File

@ -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<RgdData>): List<AddonModifiers> {
val modifiers = addonData.getRgdTableByName("modifiers")
return modifiers?.mapNotNull { m ->
if (m.name.contains("modifier_")) {
val mTable = m.value as List<RgdData>
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<RgdData>): List<AddonRequirements> {
val requirements = addonData.getRgdTableByName("requirements")
return requirements?.mapNotNull { r ->
if (r.name.contains("required_")) {
val rTable = r.value as List<RgdData>
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<RgdData>): 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<RgdData>, modFolderData: String, modName: String?): String? {
private fun convertIconAndReturnPath(
buildingData: List<RgdData>,
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)
}

View File

@ -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}")

View File

@ -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<RgdData>, squadData: List<RgdData>): BuildCost {

View File

@ -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<RgdData>, armorTypes: Set<ArmorType>, 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
}

View File

@ -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"
}
}
]
}
}
]
}

View File

@ -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"
}
}
]
}