Add on/off weapon research dps and params tables feature

This commit is contained in:
anibus 2026-09-03 20:21:06 +03:00
parent 51bf0cdff1
commit 97ea7313b8
9 changed files with 184 additions and 3 deletions

View File

@ -0,0 +1,11 @@
package com.dowstats.data.dto.controllers
/**
* Описывает как исследование влияет на конкретное поле оружия
* (урон, точность, перезарядка и т.д.).
*/
data class ResearchEffectDto(
val field: String,
val usageType: String?,
val modifierValue: Double?,
)

View File

@ -36,4 +36,5 @@ data class WeaponDto(
val modifiers: List<ModifierDto>, val modifiers: List<ModifierDto>,
val requirements: RequirementDto?, val requirements: RequirementDto?,
val hotkey: String?, val hotkey: String?,
val researches: List<WeaponResearchDto>,
) )

View File

@ -0,0 +1,13 @@
package com.dowstats.data.dto.controllers
import com.dowstats.data.dto.controllers.research.ResearchShortDto
/**
* Описывает влияние конкретного исследования (research) на оружие:
* список эффектов по полям оружия (урон, точность, перезарядка и т.д.).
*/
data class WeaponResearchDto(
val research: ResearchShortDto,
val researchRequired: List<ResearchShortDto> = emptyList(),
val effects: List<ResearchEffectDto>,
)

View File

@ -2,6 +2,7 @@ package com.dowstats.data.entities.weapon
import com.dowstats.data.dto.controllers.RequirementDto import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.WeaponDto import com.dowstats.data.dto.controllers.WeaponDto
import com.dowstats.data.dto.controllers.WeaponResearchDto
import com.dowstats.data.dto.controllers.WeaponShortDto import com.dowstats.data.dto.controllers.WeaponShortDto
import com.dowstats.data.entities.ability.Ability import com.dowstats.data.entities.ability.Ability
import com.dowstats.data.entities.sergant.SergeantWeapon import com.dowstats.data.entities.sergant.SergeantWeapon
@ -107,7 +108,7 @@ class Weapon {
@OneToMany(mappedBy="weapon", cascade = [(CascadeType.ALL)]) @OneToMany(mappedBy="weapon", cascade = [(CascadeType.ALL)])
var weaponPiercings: List<WeaponArmorPiercing> = listOf() var weaponPiercings: List<WeaponArmorPiercing> = listOf()
fun toDto(requirementDto: RequirementDto?) = WeaponDto( fun toDto(requirementDto: RequirementDto?, researches: List<WeaponResearchDto>) = WeaponDto(
id!!, id!!,
filename!!, filename!!,
name, name,
@ -140,6 +141,7 @@ class Weapon {
weaponModifiers.map { mod -> mod.toDto().copy(maxLifeTime = mod.maxLifeTime) }, weaponModifiers.map { mod -> mod.toDto().copy(maxLifeTime = mod.maxLifeTime) },
requirementDto, requirementDto,
uiHotkeyName, uiHotkeyName,
researches,
) )
fun toShortDto() = WeaponShortDto( fun toShortDto() = WeaponShortDto(

View File

@ -0,0 +1,117 @@
package com.dowstats.service.datamaps
import com.dowstats.Metadata.Requirements
import com.dowstats.data.dto.controllers.ResearchEffectDto
import com.dowstats.data.dto.controllers.WeaponResearchDto
import com.dowstats.data.dto.controllers.research.ResearchShortDto
import com.dowstats.data.entities.research.Research
import com.dowstats.data.entities.weapon.Weapon
import com.dowstats.data.repositories.ResearchRepository
import org.springframework.stereotype.Component
/**
* Builds detailed information about how researches affect a weapon's fields.
* Maps research modifier references to weapon fields.
*/
@Component
class WeaponResearchEffectMappingComponent(
val researchRepository: ResearchRepository,
) {
/**
* Mapping from modifier reference name (without modifiers prefix and .lua suffix)
* to the corresponding weapon field name.
*/
private val referenceToField: Map<String, String> = mapOf(
"accuracy_moving_reduction_weapon_modifier" to "accuracyReductionMoving",
"accuracy_ranged_weapon_modifier" to "accuracy",
"accuracy_weapon_modifier" to "accuracy",
"armour_piercing_weapon_modifier" to "armourPiercing",
"max_damage_weapon_modifier" to "maxDamage",
"max_range_weapon_modifier" to "maxRange",
"min_damage_weapon_modifier" to "minDamage",
"reload_time_weapon_modifier" to "reloadTime",
"setup_time_weapon_modifier" to "setupTime",
)
/**
* Builds a list of WeaponResearchDto for a given weapon,
* describing how each affecting research modifies the weapon's fields.
*/
fun buildEffects(weapon: Weapon): List<WeaponResearchDto> {
val weaponTarget = weapon.filename?.replace(".rgd", "") ?: return emptyList()
return weapon.affectedResearches.mapNotNull { research ->
val effects = research.researchModifiers
.filter { modifier ->
modifier.target == weaponTarget && modifier.reference != null
}
.mapNotNull { modifier ->
val refName = extractRefName(modifier.reference!!)
val field = referenceToField[refName] ?: return@mapNotNull null
ResearchEffectDto(
field = field,
usageType = modifier.usageType,
modifierValue = modifier.value,
)
}
if (effects.isEmpty()) return@mapNotNull null
WeaponResearchDto(
research = research.toResearchShortDto(),
researchRequired = getRequiredResearches(research),
effects = effects,
)
}
}
/**
* Returns researches required by the given research (its prerequisites).
* Handles both "required_research" (excluding "must not be complete" ones,
* since they are mutually exclusive rather than required)
* and "required_research_either" requirements.
*/
private fun getRequiredResearches(research: Research): List<ResearchShortDto> {
val modId = research.modId ?: return emptyList()
val required = research.researchRequirements
.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_RESEARCH }
.filter { it.value?.split(";")?.last() != "true" }
.mapNotNull { req ->
req.value?.split(";")?.first()
?.replace(".lua", ".rgd")
?.replace("research\\", "")
?.let { if (it.endsWith(".rgd")) it else "$it.rgd" }
?.let { researchRepository.findFirstByModIdAndFilename(modId, it)?.toResearchShortDto() }
}
val requiredEither = research.researchRequirements
.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIRED_RESEARCH_EITHER }
.flatMap { req ->
req.value?.split(";").orEmpty().mapNotNull { r ->
val researchFileName = r.split("\\").last().replace(".lua", ".rgd").let { resFile ->
if (resFile.endsWith(".rgd")) resFile else "$resFile.rgd"
}
researchRepository.findFirstByModIdAndFilename(modId, researchFileName)?.toResearchShortDto()
}
}
return (required + requiredEither).distinct()
}
private fun String.getPureReference(): String =
this.split("\\").last()
.replace(".lua", "")
.replace(".rgd", "")
/**
* Extracts the short modifier name from a full reference path.
* e.g. modifiers/max_damage_weapon_modifier.lua -> max_damage_weapon_modifier
*/
private fun extractRefName(reference: String): String =
reference.split("\\").first()
.replace(".lua", "")
.replace(".rgd", "")
}

View File

@ -9,6 +9,7 @@ import org.springframework.stereotype.Service
class WeaponService @Autowired constructor( class WeaponService @Autowired constructor(
val weaponRepository: WeaponRepository, val weaponRepository: WeaponRepository,
val requirementsMappingComponent: RequirementsMappingComponent, val requirementsMappingComponent: RequirementsMappingComponent,
val weaponResearchEffectMappingComponent: WeaponResearchEffectMappingComponent,
) { ) {
fun getWeaponDto(id: Long, modId: Long): WeaponDto { fun getWeaponDto(id: Long, modId: Long): WeaponDto {
@ -16,7 +17,8 @@ class WeaponService @Autowired constructor(
val requirements = requirementsMappingComponent val requirements = requirementsMappingComponent
.getRequirements(weapon.weaponRequirements.toList(), .getRequirements(weapon.weaponRequirements.toList(),
modId) modId)
return weapon.toDto(requirements) val researches = weaponResearchEffectMappingComponent.buildEffects(weapon)
return weapon.toDto(requirements, researches)
} }

View File

@ -0,0 +1,30 @@
{
"databaseChangeLog": [
{
"changeSet": {
"id": "Add index on mod_id and filename to researches",
"author": "anibus",
"changes": [
{
"createIndex": {
"indexName": "idx_researches_mod_id_filename",
"tableName": "researches",
"columns": [
{
"column": {
"name": "mod_id"
}
},
{
"column": {
"name": "filename"
}
}
]
}
}
]
}
}
]
}

View File

@ -476,6 +476,11 @@
"include": { "include": {
"file": "db/0.0.6/schema/jump_requirements.json" "file": "db/0.0.6/schema/jump_requirements.json"
} }
},
{
"include": {
"file": "db/0.0.6/schema/add_index_to_researches.json"
}
} }
] ]
} }

View File

@ -18,7 +18,7 @@ class ModDiffPrinterScript {
val rgdService = RgdService() val rgdService = RgdService()
val prevVersion = "wanila2.8.0" val prevVersion = "wanila2.9.1"
val currentVersion = "wanila" val currentVersion = "wanila"
val spaceMarinesPath = "space_marines" val spaceMarinesPath = "space_marines"