diff --git a/pom.xml b/pom.xml index 38e2d2e..ef8c52a 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ Down of war wiki 17 - 1.8.22 + 2.2.0 3.3.1 diff --git a/src/main/kotlin/com/dowstats/Metadata.kt b/src/main/kotlin/com/dowstats/Metadata.kt index b58f35c..0ae534b 100644 --- a/src/main/kotlin/com/dowstats/Metadata.kt +++ b/src/main/kotlin/com/dowstats/Metadata.kt @@ -4,4 +4,13 @@ object Metadata { const val USER_ROLE = "USER" + object Requirements { + val REFERENCE_REQUIREMENT_POP = "requirements\\required_total_pop.lua" + val REFERENCE_REQUIREMENT_ADDON = "requirements\\local_required_addon.lua" + val REFERENCE_GLOBAL_REQUIREMENT_ADDON = "requirements\\global_required_addon.lua" + val REFERENCE_REQUIREMENT_STRUCTURE_EITHER = "requirements\\required_structure_either.lua" + val REFERENCE_REQUIREMENT_STRUCTURE = "requirements\\required_structure.lua" + val REFERENCE_REQUIREMENT_RESEARCH = "requirements\\required_research.lua" + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt b/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt new file mode 100644 index 0000000..6e88f69 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt @@ -0,0 +1,13 @@ +package com.dowstats.data.dto + +data class AreaEffect( + val minDamage: Double, + val maxDamage: Double, + val damageRadius: Double, + val throwForceMin: Double, + val throwForceMax: Double, + val minDamageValue: Double, + val moraleDamage: Double, + val weaponDmgMap: Map, + val defaultArmorPiercing: Double, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/ResourceIncome.kt b/src/main/kotlin/com/dowstats/data/dto/ResourceIncome.kt new file mode 100644 index 0000000..29e1e4c --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/ResourceIncome.kt @@ -0,0 +1,7 @@ +package com.dowstats.data.dto + +data class ResourceIncome( + val faith: Double?, + val power: Double?, + val requisition: Double?, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/UiInfo.kt b/src/main/kotlin/com/dowstats/data/dto/UiInfo.kt new file mode 100644 index 0000000..eb63016 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/UiInfo.kt @@ -0,0 +1,7 @@ +package com.dowstats.data.dto + +data class UiInfo ( + val name: String?, + val description: String?, + val iconPath: String?, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/EntityCompressDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/EntityCompressDto.kt new file mode 100644 index 0000000..7aa7f50 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/EntityCompressDto.kt @@ -0,0 +1,48 @@ +package com.dowstats.data.dto.controllers + +import com.dowstats.data.entities.Building +import com.dowstats.data.entities.DowUnit +import com.dowstats.data.entities.Sergeant +import com.dowstats.data.entities.Weapon + + +data class EntityCompressDto( + val name: String?, + val icon: String?, + val id: Long, + val filename: String?, +) + +object EntityCompressDtoObject { + fun Sergeant.compressDto(): EntityCompressDto = + EntityCompressDto( + this.name, + this.icon, + this.id!!, + this.filename + ) + + fun DowUnit.compressDto(): EntityCompressDto = + EntityCompressDto( + this.name, + this.icon, + this.id!!, + this.filenameSquad + ";" + this.filenameUnit + ) + + fun Building.compressDto(): EntityCompressDto = + EntityCompressDto( + this.name, + this.icon, + this.id!!, + this.filename + ) + + fun Weapon.compressDto(): EntityCompressDto = + EntityCompressDto( + this.name, + this.icon, + this.id!!, + this.filename + ) +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonModifierDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/ModifierDto.kt similarity index 50% rename from src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonModifierDto.kt rename to src/main/kotlin/com/dowstats/data/dto/controllers/ModifierDto.kt index e7226ec..9e78e49 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonModifierDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/ModifierDto.kt @@ -1,8 +1,9 @@ -package com.dowstats.data.dto.controllers.building +package com.dowstats.data.dto.controllers -data class AddonModifierDto ( +data class ModifierDto ( val id: Long, val reference: String?, val usageType: String?, val value: Double?, + val target: String? = null, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt new file mode 100644 index 0000000..fbde80a --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt @@ -0,0 +1,20 @@ +package com.dowstats.data.dto.controllers + +import com.dowstats.data.dto.controllers.building.BuildingAddonShortDto +import com.dowstats.data.dto.controllers.building.BuildingShortDto +import com.dowstats.data.dto.controllers.research.ResearchShortDto + +data class RequirementDto ( + val requirementBuildings: Set, + val requirementBuildingsEither: Set, + val requirementResearches: Set, + val requireAddon: BuildingAddonShortDto?, + val requirementsGlobalAddons: Set?, + val requiredTotalPop: Int?, + val replaceWhenDone: Boolean = false, +) + +data class RequirementResearchDto( + val researchShortDto: ResearchShortDto, + val researchMustNotBeComplete: Boolean, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt index 0b07f4d..ae2e346 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt @@ -1,5 +1,7 @@ package com.dowstats.data.dto.controllers +import com.dowstats.data.dto.controllers.research.ResearchShortDto + data class SergeantDto( val id: Long?, @@ -27,4 +29,5 @@ data class SergeantDto( val detectRadius: Int?, val icon: String?, val weapons: List?, + val affectedResearches: Set, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt new file mode 100644 index 0000000..753a971 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt @@ -0,0 +1,9 @@ +package com.dowstats.data.dto.controllers + +data class SergeantUnitShortDto( + val id: Long?, + val filename: String, + val name: String?, + val icon: String?, + val unit: EntityCompressDto +) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt index b5cc754..7edc77f 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt @@ -1,5 +1,7 @@ package com.dowstats.data.dto.controllers +import com.dowstats.data.dto.controllers.research.ResearchShortDto + data class UnitFullDto( val id: Long, @@ -35,17 +37,19 @@ data class UnitFullDto( val moveSpeed: Int?, val sightRadius: Int?, val detectRadius: Int?, - val reinforceCostRequisition: Int?, - val reinforceCostPower: Int?, - val reinforceCostPopulation: Int?, - val reinforceCostFaith: Int?, - val reinforceCostSouls: Int?, + val reinforceCostRequisition: Double?, + val reinforceCostPower: Double?, + val reinforceCostPopulation: Double?, + val reinforceCostFaith: Double?, + val reinforceCostSouls: Double?, val reinforceTime: Int?, val repairMax: Int?, val repairSpeed: Int?, + val repairCostPercent: Int?, val maxSergeants: Int?, val icon: String?, val modId: Long, val sergeants: Set?, val weapons: Set?, + val affectedResearches: Set, ) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt index 2c28781..9116cb4 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt @@ -1,12 +1,14 @@ package com.dowstats.data.dto.controllers +import com.dowstats.data.dto.controllers.research.ResearchShortDto + data class WeaponDto( val id: Long?, val filename: String, val name: String?, val description: String?, - val costRequisition: Int?, - val costPower: Int?, + val costRequisition: Double?, + val costPower: Double?, val costTimeSeconds: Int?, val accuracy: Double?, val reloadTime: Double?, @@ -27,5 +29,6 @@ data class WeaponDto( val icon: String?, val haveEquipButton: Boolean, val modId: Long?, - val weaponArmorPiercing: List + val weaponArmorPiercing: List, + val affectedResearches: Set, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt new file mode 100644 index 0000000..136bee0 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt @@ -0,0 +1,10 @@ +package com.dowstats.data.dto.controllers + +data class WeaponUnitShortDto( + val id: Long?, + val filename: String, + val name: String?, + val units: Set, + val sergeants: Set, + val buildings: Set +) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt deleted file mode 100644 index 20162dc..0000000 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.dowstats.data.dto.controllers.building - -data class AddonRequirementDto ( - val requirementBuildings: List, - val requirementBuildingsEither: List, - val requireAddon: BuildingAddonShortDto?, - val replaceWhenDone: Boolean, - val requirementsGlobalAddons: List?, - val requiredTotalPop: Int?, -) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingAddonDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingAddonDto.kt index ceab56c..af4811e 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingAddonDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingAddonDto.kt @@ -1,5 +1,8 @@ package com.dowstats.data.dto.controllers.building +import com.dowstats.data.dto.controllers.ModifierDto +import com.dowstats.data.dto.controllers.RequirementDto + data class BuildingAddonDto( val id: Long?, val name: String?, @@ -11,8 +14,8 @@ data class BuildingAddonDto( val addonCostFaith: Double?, val addonCostSouls: Double?, val addonCostTime: Int?, - val addonModifiers: Set, - val addonRequirement: AddonRequirementDto?, + val addonModifiers: Set, + val addonRequirement: RequirementDto?, val icon: String?, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt index bee71ef..dd8f7d3 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt @@ -4,7 +4,8 @@ import com.dowstats.data.dto.controllers.ArmorTypeDto import com.dowstats.data.dto.controllers.RaceDto import com.dowstats.data.dto.controllers.UnitShortDto import com.dowstats.data.dto.controllers.WeaponSlotDto -import com.dowstats.data.entities.DowUnit +import com.dowstats.data.dto.controllers.research.ResearchDto +import com.dowstats.data.dto.controllers.research.ResearchShortDto data class BuildingFullDto( var id: Long?, @@ -32,6 +33,8 @@ data class BuildingFullDto( var icon: String?, var modId: Long?, var addons: Set?, + var researches: List?, val units: Set, val weapons: Set?, + val affectedResearches: Set, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingShortDto.kt index 422dddf..edf535e 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingShortDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingShortDto.kt @@ -12,6 +12,7 @@ data class BuildingShortDto( val name: String, val icon: String, val id: Long, + val filename: String, val units: Set, val armourTypeName: String, val canDetect: Boolean, diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchDto.kt new file mode 100644 index 0000000..9509bc0 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchDto.kt @@ -0,0 +1,24 @@ +package com.dowstats.data.dto.controllers.research + +import com.dowstats.data.dto.controllers.* + + +data class ResearchDto( + val id: Long?, + val name: String?, + val description: String?, + val filename: String?, + val costRequisition: Double?, + val costPower: Double?, + val costFaith: Double?, + val costSouls: Double?, + val costTime: Int?, + val modifiers: List, + val requirements: RequirementDto?, + val affectedUnits: Set, + val affectedSergeants: Set, + val affectedBuildings: Set, + val affectedWeapons: Set, + val icon: String?, + val modId: Long?, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchShortDto.kt new file mode 100644 index 0000000..fd52e37 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchShortDto.kt @@ -0,0 +1,8 @@ +package com.dowstats.data.dto.controllers.research + +data class ResearchShortDto( + val id: Long?, + val name: String?, + val icon: String?, + val buildingId: Long?, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt deleted file mode 100644 index 0adb7a6..0000000 --- a/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.dowstats.data.entities - -import com.dowstats.data.dto.controllers.building.AddonRequirementDto -import com.fasterxml.jackson.annotation.JsonIgnore -import jakarta.persistence.* - - -@Entity -@Table(name = "addon_requirements") -class AddonRequirements { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long? = null - - @ManyToOne - @JoinColumn(name = "addon_id", nullable = false) - @JsonIgnore - var addon: BuildingAddon? = null - var reference: String? = null - var replaceWhenDone: Boolean = false - var value: String? = null - - companion object { - val REFERENCE_REQUIREMENT_POP = "requirements\\required_total_pop.lua" - val REFERENCE_REQUIREMENT_ADDON = "requirements\\local_required_addon.lua" - val REFERENCE_GLOBAL_REQUIREMENT_ADDON = "requirements\\global_required_addon.lua" - val REFERENCE_REQUIREMENT_STRUCTURE_EITHER = "requirements\\required_structure_either.lua" - val REFERENCE_REQUIREMENT_STRUCTURE = "requirements\\required_structure.lua" - } - -} diff --git a/src/main/kotlin/com/dowstats/data/entities/Building.kt b/src/main/kotlin/com/dowstats/data/entities/Building.kt index 95b3a7c..61c1015 100644 --- a/src/main/kotlin/com/dowstats/data/entities/Building.kt +++ b/src/main/kotlin/com/dowstats/data/entities/Building.kt @@ -1,10 +1,12 @@ package com.dowstats.data.entities -import com.dowstats.data.dto.controllers.UnitShortDto import com.dowstats.data.dto.controllers.building.BuildingAddonDto import com.dowstats.data.dto.controllers.building.BuildingFullDto +import com.dowstats.data.dto.controllers.research.ResearchDto import com.dowstats.data.entities.DowUnitObject.toUnitDto import com.dowstats.data.entities.Weapon.HardpointPosition +import com.dowstats.data.entities.addon.BuildingAddon +import com.dowstats.data.entities.research.Research import jakarta.persistence.* @@ -16,7 +18,7 @@ class Building { @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null - var canBuild: Boolean = true + var canBuild: Boolean? = true @ManyToOne @JoinColumn(name = "race_id", nullable = false) @@ -63,10 +65,22 @@ class Building { inverseJoinColumns = [JoinColumn(name = "unit_id")]) var units: MutableSet? = null + @ManyToMany + @JoinTable(name = "buildings_researches", + joinColumns = [JoinColumn(name = "building_id")], + inverseJoinColumns = [JoinColumn(name = "research_id")]) + var researches: MutableSet? = null + + @ManyToMany + @JoinTable(name = "researches_affected_buildings", + joinColumns = [JoinColumn(name = "building_id")], + inverseJoinColumns = [JoinColumn(name = "research_id")]) + var affectedResearches: MutableSet = mutableSetOf() + @Transient var weaponHardpoints: MutableSet = mutableSetOf() - fun toDto(buildingAddons: Set?): BuildingFullDto = + fun toDto(buildingAddons: Set?, researches: List?): BuildingFullDto = BuildingFullDto( id!!, race?.toDto(), @@ -93,8 +107,10 @@ class Building { icon, modId!!, buildingAddons, + researches, units?.toList()?.toUnitDto() ?: emptySet(), weapons?.map { it.toWeaponSlotDto() }?.toSet(), + affectedResearches.map { it.toResearchShortDto() }.toSet(), ) diff --git a/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt b/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt index 34d6822..68a036c 100644 --- a/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt +++ b/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt @@ -2,6 +2,7 @@ package com.dowstats.data.entities import com.dowstats.data.dto.controllers.UnitFullDto import com.dowstats.data.dto.controllers.UnitShortDto +import com.dowstats.data.entities.research.Research import jakarta.persistence.* @@ -30,7 +31,8 @@ class DowUnit { var name: String? = null var description: String? = null - var filename: String? = null + var filenameSquad: String? = null + var filenameUnit: String? = null var buildCostRequisition: Double? = null var buildCostPower: Double? = null var buildCostPopulation: Double? = null @@ -57,11 +59,11 @@ class DowUnit { var moveSpeed: Int? = null var sightRadius: Int? = null var detectRadius: Int? = null - var reinforceCostRequisition: Int? = null - var reinforceCostPower: Int? = null - var reinforceCostPopulation: Int? = null - var reinforceCostFaith: Int? = null - var reinforceCostSouls: Int? = null + var reinforceCostRequisition: Double? = null + var reinforceCostPower: Double? = null + var reinforceCostPopulation: Double? = null + var reinforceCostFaith: Double? = null + var reinforceCostSouls: Double? = null var reinforceTime: Int? = null var maxSergeants: Int? = null var faithIncome: Double? = null @@ -76,6 +78,11 @@ class DowUnit { @OneToMany(mappedBy = "unit", cascade = [CascadeType.ALL]) var weapons: MutableSet? = null + @ManyToMany + @JoinTable(name = "researches_affected_units", + joinColumns = [JoinColumn(name = "unit_id")], + inverseJoinColumns = [JoinColumn(name = "research_id")]) + var affectedResearches: MutableSet = mutableSetOf() fun toDto(): UnitFullDto = @@ -86,7 +93,7 @@ class DowUnit { armorType2?.toDto(), name, description, - filename!!, + filenameSquad!!, buildCostRequisition, buildCostPower, buildCostPopulation, @@ -121,34 +128,24 @@ class DowUnit { reinforceTime, repairMax, repairSpeed, + repairCostPercent, maxSergeants, icon, modId!!, sergeants?.map { it.toDto() }?.toSet(), - weapons?.map { it.toWeaponSlotDto() }?.toSet() + weapons?.map { it.toWeaponSlotDto() }?.toSet(), + affectedResearches.map { it.toResearchShortDto() }.toSet(), ) } object DowUnitObject { fun List.toUnitDto(): Set = this.mapNotNull { - val name = it.name ?: it.filename + val name = it.name ?: it.filenameSquad val icon = it.icon if (name == null || icon == null) null else UnitShortDto(name, icon, it.id!!, it.armorType?.name!!, (it.detectRadius ?: 0) > 0) }.toSet() - fun List.filterCompanyUnits(): List = - this.filter { - it.filename?.contains("_sp.") != true - && it.filename?.contains("_sp_") != true - && it.filename?.contains("sp_eldar_") != true - && it.filename?.contains("_dxp3.") != true - && it.filename?.contains("_dxp3_") != true - && it.filename?.contains("_nis.") != true - && it.filename?.contains("_exarch_council.") != true - && it.filename?.contains("_dark_reapers_base.") != true - && it.filename?.contains("tau_squad_slave_murdered") != true - } } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/entities/RequirementBase.kt b/src/main/kotlin/com/dowstats/data/entities/RequirementBase.kt new file mode 100644 index 0000000..cff0dd1 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/RequirementBase.kt @@ -0,0 +1,16 @@ +package com.dowstats.data.entities + +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.MappedSuperclass + +@MappedSuperclass +open class RequirementBase { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + var reference: String? = null + var value: String? = null +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/entities/Sergant.kt b/src/main/kotlin/com/dowstats/data/entities/Sergant.kt index e5c09d4..2eda976 100644 --- a/src/main/kotlin/com/dowstats/data/entities/Sergant.kt +++ b/src/main/kotlin/com/dowstats/data/entities/Sergant.kt @@ -2,6 +2,7 @@ package com.dowstats.data.entities import com.dowstats.data.dto.controllers.SergeantDto import com.dowstats.data.entities.Weapon.HardpointPosition +import com.dowstats.data.entities.research.Research import com.fasterxml.jackson.annotation.JsonIgnore import jakarta.persistence.* @@ -29,7 +30,7 @@ class Sergeant { var name: String? = null var description: String? = null - var filename: String? = null + var filename: String = "" var buildCostRequisition: Double? = null var buildCostPower: Double? = null var buildCostPopulation: Double? = null @@ -49,6 +50,8 @@ class Sergeant { var powerIncome: Double? = null var requisitionIncome: Double? = null + var modId: Long? = null + @Transient var weaponHardpoints: MutableSet = mutableSetOf() @@ -56,6 +59,12 @@ class Sergeant { @OneToMany(mappedBy = "sergeant", cascade = [CascadeType.ALL]) var weapons: MutableSet? = null + @ManyToMany + @JoinTable(name = "researches_affected_sergeants", + joinColumns = [JoinColumn(name = "sergeant_id")], + inverseJoinColumns = [JoinColumn(name = "research_id")]) + var affectedResearches: MutableSet = mutableSetOf() + fun toDto(): SergeantDto = SergeantDto( id!!, @@ -82,6 +91,7 @@ class Sergeant { sightRadius, detectRadius, icon, - weapons?.map { it.toWeaponSlotDto() } + weapons?.map { it.toWeaponSlotDto() }, + affectedResearches.map { it.toResearchShortDto() }.toSet() ) } diff --git a/src/main/kotlin/com/dowstats/data/entities/Weapon.kt b/src/main/kotlin/com/dowstats/data/entities/Weapon.kt index 9fa9dda..2c2b4bd 100644 --- a/src/main/kotlin/com/dowstats/data/entities/Weapon.kt +++ b/src/main/kotlin/com/dowstats/data/entities/Weapon.kt @@ -1,6 +1,7 @@ package com.dowstats.data.entities import com.dowstats.data.dto.controllers.WeaponDto +import com.dowstats.data.entities.research.Research import jakarta.persistence.* @@ -14,8 +15,8 @@ class Weapon { var filename: String? = null var name: String? = null var description: String? = null - var costRequisition: Int? = null - var costPower: Int? = null + var costRequisition: Double? = null + var costPower: Double? = null var costTimeSeconds: Int? = null var accuracy: Double? = null var reloadTime: Double? = null @@ -37,6 +38,21 @@ class Weapon { var haveEquipButton: Boolean = true var modId: Long? = null + @ManyToMany + @JoinTable(name = "researches_affected_weapons", + joinColumns = [JoinColumn(name = "weapon_id")], + inverseJoinColumns = [JoinColumn(name = "research_id")]) + var affectedResearches: MutableSet = mutableSetOf() + + @OneToMany(mappedBy = "weapon", cascade = [CascadeType.ALL]) + var unitsUse: MutableSet? = null + + @OneToMany(mappedBy = "weapon", cascade = [CascadeType.ALL]) + var sergeantsUse: MutableSet? = null + + @OneToMany(mappedBy = "weapon", cascade = [CascadeType.ALL]) + var buildingUse: MutableSet? = null + // for many-to-many persistance data class HardpointPosition(val weaponId: Long, val hardpoint: Int, val order: Int) @@ -71,6 +87,7 @@ class Weapon { icon, haveEquipButton, modId, - weaponPiercings.map { it.toDto() } + weaponPiercings.map { it.toDto() }, + affectedResearches.map { it.toResearchShortDto() }.toSet(), ) } diff --git a/src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt b/src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt similarity index 74% rename from src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt rename to src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt index 8610c41..ceca423 100644 --- a/src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt +++ b/src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt @@ -1,6 +1,6 @@ -package com.dowstats.data.entities +package com.dowstats.data.entities.addon -import com.dowstats.data.dto.controllers.building.AddonModifierDto +import com.dowstats.data.dto.controllers.ModifierDto import com.fasterxml.jackson.annotation.JsonIgnore import jakarta.persistence.* @@ -22,12 +22,12 @@ class AddonModifiers { var usageType: String? = null var value: Double? = null - fun toDto(): AddonModifierDto { - return AddonModifierDto( + fun toDto(): ModifierDto { + return ModifierDto( id = id!!, reference = reference, usageType = usageType, - value = value + value = value, ) } } diff --git a/src/main/kotlin/com/dowstats/data/entities/addon/AddonRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/addon/AddonRequirements.kt new file mode 100644 index 0000000..64da8cc --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/addon/AddonRequirements.kt @@ -0,0 +1,17 @@ +package com.dowstats.data.entities.addon + +import com.dowstats.data.entities.RequirementBase +import com.fasterxml.jackson.annotation.JsonIgnore +import jakarta.persistence.* + + +@Entity +@Table(name = "addon_requirements") +class AddonRequirements: RequirementBase() { + + @ManyToOne + @JoinColumn(name = "addon_id", nullable = false) + @JsonIgnore + var addon: BuildingAddon? = null + var replaceWhenDone: Boolean = false +} diff --git a/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt b/src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt similarity index 89% rename from src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt rename to src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt index 2bd0c28..b4beeeb 100644 --- a/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt +++ b/src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt @@ -1,8 +1,9 @@ -package com.dowstats.data.entities +package com.dowstats.data.entities.addon -import com.dowstats.data.dto.controllers.building.AddonRequirementDto +import com.dowstats.data.dto.controllers.RequirementDto import com.dowstats.data.dto.controllers.building.BuildingAddonDto import com.dowstats.data.dto.controllers.building.BuildingAddonShortDto +import com.dowstats.data.entities.Building import com.fasterxml.jackson.annotation.JsonIgnore import jakarta.persistence.* @@ -39,7 +40,7 @@ class BuildingAddon { var icon: String? = null var modId: Long? = null - fun toDto(addonRequirementDto: AddonRequirementDto?): BuildingAddonDto = BuildingAddonDto( + fun toDto(addonRequirementDto: RequirementDto?): BuildingAddonDto = BuildingAddonDto( id = id, name = name, description = description, diff --git a/src/main/kotlin/com/dowstats/data/entities/research/Research.kt b/src/main/kotlin/com/dowstats/data/entities/research/Research.kt new file mode 100644 index 0000000..2098a60 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/research/Research.kt @@ -0,0 +1,137 @@ +package com.dowstats.data.entities.research + +import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto +import com.dowstats.data.dto.controllers.ModifierDto +import com.dowstats.data.dto.controllers.RequirementDto +import com.dowstats.data.dto.controllers.SergeantUnitShortDto +import com.dowstats.data.dto.controllers.WeaponUnitShortDto +import com.dowstats.data.dto.controllers.research.ResearchDto +import com.dowstats.data.dto.controllers.research.ResearchShortDto +import com.dowstats.data.entities.Building +import com.dowstats.data.entities.DowUnit +import com.dowstats.data.entities.Sergeant +import com.dowstats.data.entities.Weapon +import jakarta.persistence.* + + +@Entity +@Table(name = "researches") +class Research { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + var name: String? = null + var description: String? = null + var filename: String? = null + var costRequisition: Double? = null + var costPower: Double? = null + var costFaith: Double? = null + var costSouls: Double? = null + var costTime: Int? = null + var icon: String? = null + var modId: Long? = null + + @OneToMany(mappedBy = "research", cascade = [CascadeType.ALL]) + var researchModifiers: MutableSet = mutableSetOf() + + @OneToMany(mappedBy = "research", cascade = [CascadeType.ALL]) + var addonRequirements: MutableSet = mutableSetOf() + + @ManyToMany + @JoinTable(name = "researches_affected_units", + joinColumns = [JoinColumn(name = "research_id")], + inverseJoinColumns = [JoinColumn(name = "unit_id")]) + var affectedUnits: MutableSet = mutableSetOf() + + @ManyToMany + @JoinTable(name = "researches_affected_sergeants", + joinColumns = [JoinColumn(name = "research_id")], + inverseJoinColumns = [JoinColumn(name = "sergeant_id")]) + var affectedSergeants: MutableSet = mutableSetOf() + + @ManyToMany + @JoinTable(name = "researches_affected_buildings", + joinColumns = [JoinColumn(name = "research_id")], + inverseJoinColumns = [JoinColumn(name = "building_id")]) + var affectedBuildings: MutableSet = mutableSetOf() + + @ManyToMany + @JoinTable(name = "researches_affected_weapons", + joinColumns = [JoinColumn(name = "research_id")], + inverseJoinColumns = [JoinColumn(name = "weapon_id")]) + var affectedWeapons: MutableSet = mutableSetOf() + + @ManyToMany + @JoinTable(name = "buildings_researches", + joinColumns = [JoinColumn(name = "research_id")], + inverseJoinColumns = [JoinColumn(name = "building_id")]) + var buildings: MutableSet? = null + + fun toResearchShortDto(): ResearchShortDto = ResearchShortDto( + id = id!!, + name = name, + icon = icon, + buildings?.firstOrNull()?.id + ) + + fun toResearchDto(requirements: RequirementDto?): ResearchDto = ResearchDto( + id = id!!, + name = name, + icon = icon, + filename = filename, + description = description, + costRequisition = costRequisition, + costPower = costPower, + costFaith = costFaith, + costSouls = costSouls, + costTime = costTime, + modifiers = researchModifiers.map { + ModifierDto( + it.id!!, + it.reference, + it.usageType, + it.value, + it.target, + ) + }.sortedBy { it.target }, + requirements = requirements, + affectedUnits = affectedUnits.map { it.compressDto() }.toSet(), + affectedSergeants = affectedSergeants.map { + SergeantUnitShortDto( + it.id!!, + it.filename!!, + it.name, + it.icon, + it.unit!!.compressDto() + ) + }.toSet(), + affectedBuildings = affectedBuildings.map { it.compressDto() }.toSet(), + affectedWeapons = affectedWeapons.mapNotNull { + if(it.unitsUse!!.isEmpty() && it.sergeantsUse!!.isEmpty() && it.buildingUse!!.isEmpty()) { + null + } else + WeaponUnitShortDto( + it.id!!, + it.filename!!, + it.name, + it.unitsUse?.mapNotNull { + it.unit?.compressDto() + }?.toSet() ?: emptySet(), + it.sergeantsUse?.map { + SergeantUnitShortDto( + it.sergeant!!.id!!, + it.sergeant!!.filename!!, + it.sergeant!!.name, + it.sergeant!!.icon, + it.sergeant!!.unit!!.compressDto() + ) + }?.toSet() ?: emptySet(), + it.buildingUse?.map { it.building!!.compressDto() }?.toSet() ?: emptySet() + ) + }.toSet(), + modId = modId, + ) + +} diff --git a/src/main/kotlin/com/dowstats/data/entities/research/ResearchModifiers.kt b/src/main/kotlin/com/dowstats/data/entities/research/ResearchModifiers.kt new file mode 100644 index 0000000..99928bb --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/research/ResearchModifiers.kt @@ -0,0 +1,35 @@ +package com.dowstats.data.entities.research + +import com.dowstats.data.dto.controllers.ModifierDto +import com.fasterxml.jackson.annotation.JsonIgnore +import jakarta.persistence.* + + +@Entity +@Table(name = "research_modifiers") +class ResearchModifiers { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + @ManyToOne + @JoinColumn(name = "research_id", nullable = false) + @JsonIgnore + var research: Research? = null + + var reference: String? = null + var target: String? = null + var usageType: String? = null + var value: Double? = null + + fun toDto(): ModifierDto { + return ModifierDto( + id = id!!, + reference = reference, + usageType = usageType, + value = value, + target = target, + ) + } +} diff --git a/src/main/kotlin/com/dowstats/data/entities/research/ResearchRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/research/ResearchRequirements.kt new file mode 100644 index 0000000..76b2a4e --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/research/ResearchRequirements.kt @@ -0,0 +1,16 @@ +package com.dowstats.data.entities.research + +import com.dowstats.data.entities.RequirementBase +import com.fasterxml.jackson.annotation.JsonIgnore +import jakarta.persistence.* + + +@Entity +@Table(name = "research_requirements") +class ResearchRequirements : RequirementBase() { + + @ManyToOne + @JoinColumn(name = "research_id", nullable = false) + @JsonIgnore + var research: Research? = null +} diff --git a/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt index 9c9749e..fd60691 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt @@ -1,10 +1,6 @@ package com.dowstats.data.repositories -import com.dowstats.data.entities.Building -import com.dowstats.data.entities.BuildingAddon -import com.dowstats.data.entities.DowUnit -import com.dowstats.data.entities.Race -import org.springframework.data.jpa.repository.Query +import com.dowstats.data.entities.addon.BuildingAddon import org.springframework.data.repository.CrudRepository interface AddonRepository : CrudRepository{ diff --git a/src/main/kotlin/com/dowstats/data/repositories/ModRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/ModRepository.kt index 6e868a3..2b819fd 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/ModRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/ModRepository.kt @@ -13,4 +13,10 @@ interface ModRepository : CrudRepository{ """, nativeQuery = true) @Modifying fun clearModData(modId: Long) + + @Query(""" + CALL delete_campaign_entities(:modId) + """, nativeQuery = true) + @Modifying + fun removeCampaignEntities(modId: Long) } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/ResearchRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/ResearchRepository.kt new file mode 100644 index 0000000..b1f851b --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/repositories/ResearchRepository.kt @@ -0,0 +1,13 @@ +package com.dowstats.data.repositories + +import com.dowstats.data.entities.DowUnit +import com.dowstats.data.entities.Weapon +import com.dowstats.data.entities.addon.BuildingAddon +import com.dowstats.data.entities.research.Research +import org.springframework.data.repository.* + +interface ResearchRepository : CrudRepository{ + fun deleteAllByModId(modId: Long) + fun findAllByModId(modId: Long): List + fun findFirstByModIdAndFilename(modId: Long, fileName: String): Research? +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/SergeantRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/SergeantRepository.kt index 7608640..663b02c 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/SergeantRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/SergeantRepository.kt @@ -1,6 +1,9 @@ package com.dowstats.data.repositories import com.dowstats.data.entities.Sergeant +import com.dowstats.data.entities.Weapon import org.springframework.data.repository.CrudRepository -interface SergeantRepository : CrudRepository \ No newline at end of file +interface SergeantRepository : CrudRepository{ + fun findAllByModId(modId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt index 490ecc7..e66a350 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt @@ -18,7 +18,5 @@ interface UnitRepository : CrudRepository { """) fun findByModIdAndRace(modId: Long, race: Race?): List - fun findByFilenameAndRaceAndModId(fileName: String, race: Race, modId: Long): DowUnit? - fun deleteAllByModIdAndRaceId(modId: Long, raceId: String) } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/WeaponRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/WeaponRepository.kt index 7cd68fc..f205c0f 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/WeaponRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/WeaponRepository.kt @@ -2,8 +2,10 @@ package com.dowstats.data.repositories import com.dowstats.data.entities.DowUnit import com.dowstats.data.entities.Weapon +import com.dowstats.data.entities.research.Research import org.springframework.data.repository.* interface WeaponRepository : CrudRepository{ fun deleteAllByModId(modId: Long) + fun findAllByModId(modId: Long): List } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/CommonMapping.kt b/src/main/kotlin/com/dowstats/service/datamaps/CommonMapping.kt new file mode 100644 index 0000000..0c8aa74 --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/datamaps/CommonMapping.kt @@ -0,0 +1,44 @@ +package com.dowstats.service.datamaps + +import com.dowstats.data.dto.controllers.building.BuildingShortDto +import com.dowstats.data.entities.Building +import com.dowstats.data.entities.DowUnitObject.toUnitDto + +object CommonMapping { + fun List.toBuildingShortDto(): List = + this + .sortedWith(compareBy { it.units?.isEmpty() }.thenBy{ it.buildCostRequisition?.let { 0 - it } }) + .mapNotNull { + val name = it.name ?: it.filename?.replace(".rgd", "")?.replace("_", " ") + val icon = it.icon + if (name == null || icon == null) null else BuildingShortDto( + name, icon, it.id!!, + it.filename!!, + it.units?.toList()?.toUnitDto() ?: emptySet(), + it.armorType?.name!!, + (it.detectRadius ?: 0) > 0 + ) + } + + fun isNotCompanyEntity(fileName: String): Boolean = + !fileName.contains("_dxp3.") && + !fileName.contains("_dxp3_") && + !fileName.contains("sp_eldar_") && + !fileName.contains("_sp_") && + !fileName.contains("_sp.") && + !fileName.contains("_nis.") && + !fileName.contains("_interface_relay.") && + !fileName.contains("necron_tunnel.rgd") && + !fileName.contains("_exarch_council.") && + !fileName.contains("_dark_reapers_base.") && + !fileName.contains("eldar_deep_strike_building.rgd") && + !fileName.contains("ork_deep_strike_building.rgd") && + !fileName.contains("_caravel_ai.rgd") && + !fileName.contains("sisters_tanktrap_ai.rgd") && + !fileName.contains("sisters_hq_ktgm.rgd") && + !fileName.contains("tau_squad_slave_murdered") && + !fileName.contains("single_player_only") && + !fileName.contains("space_marine_drop_pod_building.rgd") + + +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt index 782417a..6b14acd 100644 --- a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt +++ b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt @@ -1,147 +1,68 @@ package com.dowstats.service.datamaps -import com.dowstats.data.dto.controllers.building.AddonRequirementDto +import com.dowstats.Metadata.Requirements import com.dowstats.data.dto.controllers.building.BuildingFullDto -import com.dowstats.data.dto.controllers.building.BuildingShortDto import com.dowstats.data.dto.controllers.building.RaceBuildings -import com.dowstats.data.entities.AddonRequirements import com.dowstats.data.entities.Building -import com.dowstats.data.entities.DowUnitObject.filterCompanyUnits -import com.dowstats.data.entities.DowUnitObject.toUnitDto -import com.dowstats.data.repositories.AddonRepository import com.dowstats.data.repositories.BuildingRepository import com.dowstats.data.repositories.RaceRepository +import com.dowstats.service.datamaps.CommonMapping.isNotCompanyEntity +import com.dowstats.service.datamaps.CommonMapping.toBuildingShortDto import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service @Service class DowBuildingMappingService @Autowired constructor( val buildingRepository: BuildingRepository, - val addonRepository: AddonRepository, + val requirementsMappingComponent: RequirementsMappingComponent, val raceRepository: RaceRepository ) { fun findBuildingsByMod(modId: Long): List { return getAllBuildings(modId).groupBy { it.race }.mapNotNull { raceUnits -> - RaceBuildings(raceUnits.key?.toDto() ?: throw Exception("Race is null"), raceUnits.value.toBuildingDto()) + RaceBuildings(raceUnits.key?.toDto() ?: throw Exception("Race is null"), raceUnits.value.toBuildingShortDto()) } } fun findBuildingsByModAndRace(modId: Long, race: String): RaceBuildings { val buildings = getAllBuildings(modId, race) val raceEntity = race.let { raceRepository.findById(race) ?: throw Exception("Race $race not found") } - return RaceBuildings(raceEntity.toDto(), buildings.toBuildingDto()) + return RaceBuildings(raceEntity.toDto(), buildings.toBuildingShortDto()) } fun mapToDto(building: Building): BuildingFullDto { val buildingAddons = building.addons?.map { addon -> - val requirements = addon.addonRequirements - - val requireCap = - requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble() - ?.toInt() - - val requirementAddon = - requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_ADDON }?.value?.let { - building.addons?.find { addon -> addon.filename == it.split("\\").last().replace(".lua", ".rgd") } - } - - val replaceWhenDone = requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_ADDON }?.replaceWhenDone ?: false - - val requirementAddonGlobal = - requirements?.filter { it.reference == AddonRequirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON } - ?.mapNotNull { rgra -> - val addonFileName = rgra.value?.split("\\")?.last()?.replace(".lua", ".rgd") - addonFileName?.let { - addonRepository.findFirstByModIdAndFilename( - building.modId!!, - it.split("\\").last().replace(".lua", ".rgd") - )?.toShortDto() - } - } - - val requirementBuildings = - requirements?.filter { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE }?.mapNotNull { - val buildingFileName = it.value?.split("\\")?.last()?.replace(".lua", ".rgd") - buildingFileName?.let { - buildingRepository.findByModIdAndFilename(building.modId!!, buildingFileName) - } - }?.filter { it.id != building.id }?.distinct()?.toBuildingDto() - - val requirementBuildingsEither = - requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let { - it.value?.split(";")?.mapNotNull { bPath -> - buildingRepository.findByModIdAndFilename( - building.modId!!, - bPath.split("\\").last().replace(".lua", ".rgd") - ) - } - }?.toBuildingDto() - - val addonRequirement = if (requireCap != null || - requirementAddon != null || - (requirementBuildings?.size ?: 0) > 0 || - (requirementBuildingsEither?.size ?: 0) > 0 || - (requirementAddonGlobal?.size ?: 0) > 0 - ) { - AddonRequirementDto( - requirementBuildings ?: emptyList(), - requirementBuildingsEither ?: emptyList(), - requirementAddon?.toShortDto(), - replaceWhenDone, - requirementAddonGlobal, - requireCap + val replaceWhenDone = addon.addonRequirements?.find { it.reference == Requirements.REFERENCE_REQUIREMENT_ADDON }?.replaceWhenDone ?: false + val requirement = requirementsMappingComponent + .getRequirements(addon.addonRequirements?.toList() ?: emptyList(), + building.modId!!, + building.addons?.toList() ?: emptyList() ) - } else null - addon.toDto(addonRequirement) + addon.toDto(requirement?.copy( + replaceWhenDone = replaceWhenDone, + requirementBuildings = requirement.requirementBuildings.filter { it.id != building.id }.toSet()) + ) }?.sortedBy { it.name }?.toSet() - return building.toDto(buildingAddons) + val researches = building.researches?.map {research -> + val requiremens = requirementsMappingComponent + .getRequirements(research.addonRequirements.toList() ?: emptyList(), + building.modId!!, + building.addons?.toList() ?: emptyList() + ) + research.toResearchDto(requiremens) + }?.sortedBy { it.name } + + return building.toDto(buildingAddons, researches) } - private fun List.toBuildingDto(): List = - this - .sortedWith(compareBy { it.units?.isEmpty() }.thenBy{ it.buildCostRequisition?.let { 0 - it } }) - .mapNotNull { - val name = it.name ?: it.filename?.replace(".rgd", "")?.replace("_", " ") - val icon = it.icon - if (name == null || icon == null) null else BuildingShortDto( - name, icon, it.id!!, - it.units?.toList()?.filterCompanyUnits()?.toUnitDto() ?: emptySet(), - it.armorType?.name!!, - (it.detectRadius ?: 0) > 0 - ) - } - - private fun getAllBuildings(modId: Long, race: String? = null): List { val raceEntity = race?.let { raceRepository.findById(race) ?: throw Exception("Race $race not found") } - return filterCompanyUnits(buildingRepository.findByModIdAndRace(modId, raceEntity)) + return buildingRepository.findByModIdAndRace(modId, raceEntity) } - private fun filterCompanyUnits(buildings: List): List = - buildings.filter { - it.filename?.contains("_sp.") != true - && it.filename?.contains("_sp_") != true - && it.filename?.contains("sp_eldar_") != true - && it.filename?.contains("_dxp3.") != true - && it.filename?.contains("_dxp3_") != true - && it.filename?.contains("_nis.") != true - && it.filename?.contains("_interface_relay.") != true - && it.filename?.contains("necron_tunnel.rgd") != true - && it.filename?.contains("_exarch_council.") != true - && it.filename?.contains("_dark_reapers_base.") != true - && it.filename?.contains("eldar_deep_strike_building.rgd") != true - && it.filename?.contains("ork_deep_strike_building.rgd") != true - && it.filename?.contains("_caravel_ai.rgd") != true - && it.filename?.contains("sisters_tanktrap_ai.rgd") != true - && it.filename?.contains("sisters_hq_ktgm.rgd") != true - && it.filename?.contains("tau_squad_slave_murdered") != true - && it.filename?.contains("single_player_only") != true - && it.filename?.contains("space_marine_drop_pod_building.rgd") != true - } } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt b/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt index a460512..9f51043 100644 --- a/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt +++ b/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt @@ -1,9 +1,7 @@ package com.dowstats.service.datamaps import com.dowstats.data.dto.controllers.RaceUnits -import com.dowstats.data.dto.controllers.UnitShortDto import com.dowstats.data.entities.DowUnit -import com.dowstats.data.entities.DowUnitObject.filterCompanyUnits import com.dowstats.data.entities.DowUnitObject.toUnitDto import com.dowstats.data.entities.Race import com.dowstats.data.repositories.RaceRepository @@ -40,7 +38,7 @@ class DowUnitMappingService @Autowired constructor( .toUnitDto() val support = units.filter { - it.capInfantry?.let { it == 0 } ?: false && it.reinforceCostPopulation?.let { it == 0 } ?: true && + it.capInfantry?.let { it == 0 } ?: false && it.reinforceCostPopulation?.let { it == 0.0 } ?: true && it.capSupport?.let { it == 0 } ?: false } .toUnitDto() @@ -51,7 +49,7 @@ class DowUnitMappingService @Autowired constructor( private fun getAllUnits(modId: Long, race: String? = null): List { val raceEntity = race?.let{ raceRepository.findById(race) ?: throw Exception("Race $race not found") } - return unitRepository.findByModIdAndRace(modId, raceEntity).filterCompanyUnits() + return unitRepository.findByModIdAndRace(modId, raceEntity) } } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt b/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt new file mode 100644 index 0000000..bc9b12f --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt @@ -0,0 +1,94 @@ +package com.dowstats.service.datamaps + +import com.dowstats.Metadata.Requirements +import com.dowstats.data.dto.controllers.RequirementDto +import com.dowstats.data.dto.controllers.RequirementResearchDto +import com.dowstats.data.entities.RequirementBase +import com.dowstats.data.entities.addon.BuildingAddon +import com.dowstats.data.repositories.AddonRepository +import com.dowstats.data.repositories.BuildingRepository +import com.dowstats.data.repositories.ResearchRepository +import com.dowstats.service.datamaps.CommonMapping.toBuildingShortDto +import org.springframework.stereotype.Component + +@Component +class RequirementsMappingComponent( + val addonRepository: AddonRepository, + val buildingRepository: BuildingRepository, + val researchRepository: ResearchRepository, +) { + fun getRequirements(requirements : List, modId: Long, thisBuildingAddons: List = emptyList()) : RequirementDto? { + + val requireCap = + requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble() + ?.toInt() + + val requirementAddon = + requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_ADDON }?.value?.let { + thisBuildingAddons.find { addon -> addon.filename == it.split("\\").last().replace(".lua", ".rgd") } + }?.toShortDto() + + + val requirementAddonGlobal = + requirements.filter { it.reference == Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON } + .mapNotNull { rgra -> + val addonFileName = rgra.value?.split("\\")?.last()?.replace(".lua", ".rgd") + addonFileName?.let { + addonRepository.findFirstByModIdAndFilename( + modId, + it.split("\\").last().replace(".lua", ".rgd") + )?.toShortDto() + } + }.toSet() + + val requirementBuildings = + requirements.filter { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE }.mapNotNull { + val buildingFileName = it.value?.split("\\")?.last()?.replace(".lua", ".rgd") + buildingFileName?.let { + buildingRepository.findByModIdAndFilename(modId, buildingFileName) + } + }.distinct().toBuildingShortDto().toSet() + + val requirementBuildingsEither = + requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let { + it.value?.split(";")?.mapNotNull { bPath -> + buildingRepository.findByModIdAndFilename( + modId, + bPath.split("\\").last().replace(".lua", ".rgd") + ) + } + }?.toBuildingShortDto()?.toSet() ?: emptySet() + + val requirementResearches = + requirements.filter { it.reference == Requirements.REFERENCE_REQUIREMENT_RESEARCH }.mapNotNull { + val research = it.value?.split(";")?.first() + val mustNotBeCompleteStr = it.value?.split(";")?.last() + val researchFileName = research?.split("\\")?.last()?.replace(".lua", ".rgd")?.let { + if(it.endsWith(".rgd")) it else "$it.rgd" + } + researchFileName?.let { + researchRepository.findFirstByModIdAndFilename(modId, researchFileName) + }?.toResearchShortDto()?.let { + val mustNotBeComplete = mustNotBeCompleteStr == "true" + RequirementResearchDto(it, mustNotBeComplete) + } + }.toSet() + + return if (requireCap != null || + requirementAddon != null || + requirementBuildings.isNotEmpty() || + requirementBuildingsEither.isNotEmpty() || + requirementResearches.isNotEmpty() || + requirementAddonGlobal.isNotEmpty() + ) { + RequirementDto( + requirementBuildings, + requirementBuildingsEither, + requirementResearches, + requirementAddon, + requirementAddonGlobal, + requireCap + ) + } else null + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt b/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt new file mode 100644 index 0000000..ea73ef3 --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt @@ -0,0 +1,107 @@ +package com.dowstats.service.postparsing + +import com.dowstats.configuration.StorageConfig +import com.dowstats.data.entities.* +import com.dowstats.data.entities.research.Research +import com.dowstats.data.repositories.* +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import java.awt.image.BufferedImage +import java.io.File +import java.nio.file.Path +import javax.imageio.ImageIO +import kotlin.io.path.exists + + +@Service +class PostParsingService @Autowired constructor( + val researchRepository: ResearchRepository, + val unitRepository: UnitRepository, + val sergeantRepository: SergeantRepository, + val buildingRepository: BuildingRepository, + val weaponRepository: WeaponRepository, +) { + + val log = LoggerFactory.getLogger(PostParsingService::class.java) + + fun bindResearch(mod: Mod) { + try { + val modId = mod.id!! + val researches = researchRepository.findAllByModId(modId) + val units = unitRepository.findByModIdAndRace(modId, null) + val sergeants = sergeantRepository.findAllByModId(modId) + val buildings = buildingRepository.findByModIdAndRace(modId, null) + val weapons = weaponRepository.findAllByModId(modId) + + bindResearchUnits(units, researches) + bindResearchSergeants(sergeants, researches) + bindResearchBuildings(buildings, researches) + bindResearchWeapons(weapons, researches) + + } catch (e: Exception) { + log.warn("Error occurred during bind researches", e) + } + + } + + private fun bindResearchUnits(units: List, researches: List) { + + val unitsWithBindings: List = researches.flatMap { research -> + research.researchModifiers.mapNotNull { modifier -> + units.find { + it.filenameSquad?.replace(".rgd", "") == modifier.target || + it.filenameUnit?.replace(".rgd", "") == modifier.target + } + ?.let { + it.affectedResearches.add(research) + it + } + } + } + unitRepository.saveAll(unitsWithBindings) + log.info("Successfully bind researches to units") + } + + private fun bindResearchSergeants(sergeants: List, researches: List) { + + val sergeantsWithBindings: List = researches.flatMap { research -> + research.researchModifiers.mapNotNull { modifier -> + sergeants.find { it.filename.replace(".rgd", "") == modifier.target }?.let { + it.affectedResearches.add(research) + it + } + } + } + sergeantRepository.saveAll(sergeantsWithBindings) + log.info("Successfully bind researches to sergeants") + } + + private fun bindResearchBuildings(buildings: List, researches: List) { + + val buildingsWithBindings: List = researches.flatMap { research -> + research.researchModifiers.mapNotNull { modifier -> + buildings.find { it.filename?.replace(".rgd", "") == modifier.target }?.let { + it.affectedResearches.add(research) + it + } + } + } + buildingRepository.saveAll(buildingsWithBindings) + log.info("Successfully bind researches to buildings") + } + + private fun bindResearchWeapons(weapons: List, researches: List) { + + val weaponsWithBindings: List = researches.flatMap { research -> + research.researchModifiers.mapNotNull { modifier -> + weapons.find { it.filename?.replace(".rgd", "") == modifier.target }?.let { + it.affectedResearches.add(research) + it + } + } + } + weaponRepository.saveAll(weaponsWithBindings) + log.info("Successfully bind researches to weapons") + } +} diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt index 8dad551..9443cff 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt @@ -1,7 +1,9 @@ package com.dowstats.service.w40k -import com.dowstats.data.dto.BuildCost import com.dowstats.data.entities.* +import com.dowstats.data.entities.addon.AddonModifiers +import com.dowstats.data.entities.addon.AddonRequirements +import com.dowstats.data.entities.addon.BuildingAddon import com.dowstats.data.rgd.RgdData import com.dowstats.data.rgd.RgdDataUtil.getBooleanByName import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName @@ -10,23 +12,13 @@ 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 BuildingAddonRgdExtractService @Autowired constructor( - private val modAttribPathService: ModAttribPathService, - private val iconsService: IconsService, + private val commonParseRgdService: CommonParseRgdService, ) { - val log = LoggerFactory.getLogger(BuildingAddonRgdExtractService::class.java) - data class AddonTexts( - val name: String?, - val description: String?, - ) - fun extractToAddonEntity( fileName: String, modDictionary: Map, @@ -37,14 +29,16 @@ class BuildingAddonRgdExtractService @Autowired constructor( ): BuildingAddon { val addon = BuildingAddon() - - val nameAndDescription = getAddonNameAndDescription(addonRgdData, modDictionary) - addon.name = nameAndDescription.name - addon.description = nameAndDescription.description addon.building = building + + val uiInfoRgd = addonRgdData.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileName") + val uiInfo = commonParseRgdService.getUiInfo(uiInfoRgd, modDictionary, modFolderData, mod, log) + addon.name = uiInfo.name + addon.description = uiInfo.description + addon.icon = uiInfo.iconPath addon.filename = fileName - val buildCost = getAddonCost(addonRgdData) + val buildCost = commonParseRgdService.getBuildCost(addonRgdData.getRgdTableByName("time_cost")) addon.addonCostRequisition = buildCost.requisition addon.addonCostPower = buildCost.power addon.addonCostPopulation = buildCost.population @@ -54,8 +48,6 @@ class BuildingAddonRgdExtractService @Autowired constructor( addon.addonModifiers = getAddonModifiers(addon, addonRgdData).toMutableSet() addon.addonRequirements = getAddonRequirements(addon, addonRgdData).toMutableSet() - val addonIcon = convertIconAndReturnPath(addonRgdData, modFolderData, mod.name) - addon.icon = addonIcon addon.modId = mod.id return addon @@ -88,82 +80,11 @@ class BuildingAddonRgdExtractService @Autowired constructor( it.addon = addon it.reference = rTable.getStringByName("\$REF") it.replaceWhenDone = rTable.getBooleanByName("replace_when_done") == true - it.value = when(it.reference){ - AddonRequirements.REFERENCE_REQUIREMENT_POP -> rTable.getDoubleByName("population_required").toString() - AddonRequirements.REFERENCE_REQUIREMENT_ADDON -> rTable.getStringByName("addon_name") - AddonRequirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON -> rTable.getStringByName("global_addon_name") - AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER -> rTable.getStringByName("structure_name_or") + ";" + rTable.getStringByName("structure_name_either") - AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE -> rTable.getStringByName("structure_name") - else -> null - } + it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, addon.filename!!, log) } } } else null } ?: emptyList() } - - private fun getAddonCost(addonData: List): BuildCost { - - val cost = addonData.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 getAddonNameAndDescription(addonData: List, modDictionary: Map): AddonTexts { - 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 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 AddonTexts(name, description) - } - - - private fun convertIconAndReturnPath( - buildingData: List, - modFolderData: String, - modName: String? - ): String? { - val iconPathInMod = buildingData - .getRgdTableByName("ui_info") - ?.getStringByName("icon_name") - - return iconPathInMod?.let { modAttribPathService.getIconPath(modFolderData, iconPathInMod) } - ?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) } - } - } diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt index 39b465d..a83ebd6 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt @@ -1,27 +1,21 @@ 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.repositories.UnitRepository +import com.dowstats.data.entities.research.Research 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 com.dowstats.service.w40k.UnitRgdExtractService.ResourceIncome 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, + private val commonParseRgdService: CommonParseRgdService, ) { val log = LoggerFactory.getLogger(BuildingRgdExtractService::class.java) @@ -39,16 +33,12 @@ class BuildingRgdExtractService @Autowired constructor( val weaponFilename: String, ) - data class BuildingTexts( - val name: String?, - val description: String?, - ) - fun extractToBuildingEntity( fileName: String, modDictionary: Map, buildingData: List, weapons: Set, + researches: Set, units: List, race: Race, modFolderData: String, @@ -63,13 +53,16 @@ class BuildingRgdExtractService @Autowired constructor( 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) + val buildingUiInfo = buildingData.getRgdTableByName("ui_ext") + ?.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileName") + val buildingUiData = commonParseRgdService.getUiInfo(buildingUiInfo, modDictionary, modFolderData, mod, log) + building.name = buildingUiData.name + building.description = buildingUiData.description + building.icon = buildingUiData.iconPath + + val buildCost = commonParseRgdService.getBuildCost(buildingData.getRgdTableByName("cost_ext")?.getRgdTableByName("time_cost")) building.buildCostRequisition = buildCost.requisition building.buildCostPower = buildCost.power building.buildCostPopulation = buildCost.population @@ -77,7 +70,7 @@ class BuildingRgdExtractService @Autowired constructor( building.buildCostSouls = buildCost.souls building.buildCostTime = buildCost.time - val incomeData = getResource(buildingData) + val incomeData = commonParseRgdService.getResourceIncome(buildingData.getRgdTableByName("resource_ext")) building.faithIncome = incomeData.faith building.powerIncome = incomeData.power building.requisitionIncome = incomeData.requisition @@ -94,6 +87,7 @@ class BuildingRgdExtractService @Autowired constructor( building.repairMax = healthData.maxRepaires building.units = getUnits(buildingData, units).toMutableSet() + building.researches = getResearches(buildingData, researches).toMutableSet() val addons = getAddons(buildingData) building.addons = addons?.mapNotNull {addonFileName -> @@ -106,8 +100,6 @@ class BuildingRgdExtractService @Autowired constructor( } }?.toMutableSet() - val buildingIcon = convertIconAndReturnPath(buildingData, modFolderData, mod.name) - building.icon = buildingIcon val buildingWeapons = getBuildingWeapon(buildingData)?.mapNotNull { weaponData -> weapons.find { @@ -135,54 +127,6 @@ class BuildingRgdExtractService @Autowired constructor( 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 getResource(buildingData: List): ResourceIncome { - val resourceExt = buildingData.getRgdTableByName("resource_ext") - return ResourceIncome( - resourceExt?.getDoubleByName("faith_per_second")?.let { it * 10 }, - resourceExt?.getDoubleByName("power_per_second")?.let { it * 10 }, - resourceExt?.getDoubleByName("requisition_per_second")?.let { it * 10 }, - ) - } - - 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( @@ -225,17 +169,6 @@ class BuildingRgdExtractService @Autowired constructor( }?.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") @@ -254,10 +187,19 @@ class BuildingRgdExtractService @Autowired constructor( ?.mapNotNull { unit -> if (unit.name.contains("squad_")) { val fileName = unit.value.toString().split("\\").last().replace(".lua", ".rgd") - units.find { it.filename == fileName } + units.find { it.filenameSquad == fileName } } else null } ?: emptyList() } + private fun getResearches(buildingData: List, researches: Set): List { + return buildingData.getRgdTableByName("research_ext") + ?.getRgdTableByName("research_table") + ?.mapNotNull { research -> + if (research.name.contains("research_")) { + val fileName = research.value.toString().split("\\").last().replace(".lua", "") + researches.find { it.filename?.replace(".rgd", "") == fileName } + } else null + } ?: emptyList() + } } - diff --git a/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt b/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt new file mode 100644 index 0000000..e2ed2c4 --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt @@ -0,0 +1,137 @@ +package com.dowstats.service.w40k + +import com.dowstats.Metadata.Requirements +import com.dowstats.data.dto.AreaEffect +import com.dowstats.data.dto.BuildCost +import com.dowstats.data.dto.ResourceIncome +import com.dowstats.data.dto.UiInfo +import com.dowstats.data.entities.Mod +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 +import org.slf4j.Logger +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +@Service +class CommonParseRgdService @Autowired constructor( + private val modAttribPathService: ModAttribPathService, + private val iconsService: IconsService, +) { + + + fun getRequirementReference(ref: String?, rTable: List, fileName: String, log: Logger): String? = when (ref) { + Requirements.REFERENCE_REQUIREMENT_POP -> rTable.getDoubleByName("population_required").toString() + Requirements.REFERENCE_REQUIREMENT_ADDON -> rTable.getStringByName("addon_name") + Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON -> rTable.getStringByName("global_addon_name") + Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER -> rTable.getStringByName("structure_name_or") + ";" + rTable.getStringByName( + "structure_name_either" + ) + Requirements.REFERENCE_REQUIREMENT_STRUCTURE -> rTable.getStringByName("structure_name") + Requirements.REFERENCE_REQUIREMENT_RESEARCH -> rTable.getStringByName("research_name")+ ";" + rTable.getBooleanByName( + "research_must_not_be_complete" + ) + else -> { + log.warn("Unknown requirement reference $ref at $fileName") + null + } + } + + fun getBuildCost(cost: List?): BuildCost { + + 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() + ) + } + + fun getResourceIncome(resourceExt: List?): ResourceIncome { + return ResourceIncome( + resourceExt?.getDoubleByName("faith_per_second")?.let { it * 10 }, + resourceExt?.getDoubleByName("power_per_second")?.let { it * 10 }, + resourceExt?.getDoubleByName("requisition_per_second")?.let { it * 10 }, + ) + } + + + fun getUiInfo(uiInfoRgdData: List, modDictionary: Map, modFolderData: String, mod: Mod, log: Logger): UiInfo { + val nameRef = uiInfoRgdData?.getStringByName("screen_name_id")?.replace("$", "") + val name = nameRef?.let { try { modDictionary[it.toInt()] } catch (e: Exception) { null } } + + val descriptionRefs = uiInfoRgdData.getRgdTableByName("help_text_list") + ?.mapNotNull{try { + (it.value as String).replace("$", "") + } catch (e: Exception) { + log.error("Error parsing ui help_text weapon $name", e) + null + }} + ?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""} + ?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } } + + val description = try { + descriptionRefs?.map { try { modDictionary[it.toInt()] } catch (e: Exception) { "" } }?.joinToString ( "\n" ) + } catch(e:Exception) { + log.warn("Error parsing ui description weapon $name", e) + null + } + + val icon = try { + val iconPath = uiInfoRgdData.getStringByName("icon_name") + + iconPath?.let { modAttribPathService.getIconPath(modFolderData, iconPath) } + ?.let { iconsService.convertTgaToJpegImage(iconPath, it, mod.name) } + } catch (e: Exception) { + log.error("Error parsing ui icon path for weapon $name", e) + null + } + + return UiInfo(name, description, icon) + } + + fun getAreaEffectData(weaponData: List): AreaEffect { + val areaEffect = weaponData.getRgdTableByName("area_effect") + + 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 + val forceMax = throwData?.getDoubleByName("force_max") ?: 0.0 + + val armourDamage = areaEffect + ?.getRgdTableByName("weapon_damage") + ?.getRgdTableByName("armour_damage") + val minDamage = armourDamage?.getDoubleByName("min_damage") ?: 0.0 + val maxDamage = armourDamage?.getDoubleByName("max_damage") ?: 0.0 + val minDamageValue = armourDamage?.getDoubleByName("min_damage_value") ?: 0.0 + val moraleDamage = armourDamage?.getDoubleByName("morale_damage") ?: 0.0 + + + val defaultArmourPiercing = armourDamage?.getDoubleByName("armour_piercing") ?: 0.0 + val weaponDmgMap: Map = + armourDamage?.getRgdTableByName("armour_piercing_types")?.mapNotNull { armour_piercing -> + if (armour_piercing.name.contains("entry")) { + val entry = armour_piercing.value as List + val dmgType = entry.getRgdTableByName("armour_type")?.getStringByName("\$REF")?.replace("type_armour\\tp_","")?.replace(".lua","") + val dmgValue = entry.getDoubleByName("armour_piercing_value") + dmgType!! to dmgValue!! + } else null + }?.toMap() ?: emptyMap() + + + + return AreaEffect(minDamage, maxDamage, damageRadius, forceMin, forceMax, minDamageValue, moraleDamage, weaponDmgMap, defaultArmourPiercing) + } + + +} + diff --git a/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt b/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt index 5afc3d4..bf03ccf 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt @@ -43,6 +43,7 @@ class IconsService @Autowired constructor( null } else { pathToSave.replace("${storageConfig.iconsStorage.replace("/", File.separator)}${File.separator}", "") + .replace("${File.separator}${File.separator}","${File.separator}") } } catch (e: Exception) { log.warn("Can't convert icon $iconPathInMod", e) diff --git a/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt b/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt index 0cc5390..6510ffb 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt @@ -26,6 +26,9 @@ class ModAttribPathService @Autowired constructor( fun getWeaponAttribsPath(modFolderData: String): String = "$modFolderData${File.separator}attrib${File.separator}weapon" + fun getResearchAttribsPath(modFolderData: String): String = + "$modFolderData${File.separator}attrib${File.separator}research" + fun getAddonAttribsPath(modFolderData: String): String = "$modFolderData${File.separator}attrib${File.separator}addons" diff --git a/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt b/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt index 5ea18fc..90403bb 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt @@ -1,8 +1,10 @@ package com.dowstats.service.w40k import com.dowstats.data.entities.* +import com.dowstats.data.entities.research.Research import com.dowstats.data.repositories.* import com.dowstats.data.rgd.RgdData +import com.dowstats.service.postparsing.PostParsingService import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.lang.Exception @@ -17,6 +19,7 @@ import kotlin.io.path.name class ModParserService @Autowired constructor( val rgdParserService: RgdParserService, val unitRgdExtractService: UnitRgdExtractService, + val researchRgdExtractService: ResearchRgdExtractService, val raceRepository: RaceRepository, val armorTypeRepository: ArmorTypeRepository, val unitRepository: UnitRepository, @@ -26,6 +29,9 @@ class ModParserService @Autowired constructor( val modAttribPathService: ModAttribPathService, val buildingRepository: BuildingRepository, val buildingExtractService: BuildingRgdExtractService, + val postParsingService: PostParsingService, + private val researchRepository: ResearchRepository, + private val modRepository: ModRepository, ) { val defaultDictionary: MutableMap = mutableMapOf() @@ -56,6 +62,7 @@ class ModParserService @Autowired constructor( fun parseModFilesAndSaveToDb(mod: Mod) { log.info("Start parse mod files ${mod.technicalName}:${mod.version}") + modRepository.clearModData(mod.id!!) val modFolderData = modAttribPathService.getModFolderData(mod.technicalName!!, mod.version!!) val racesList = Files.walk(Path(modAttribPathService.getSbpsAttribsFolderPath(modFolderData)), 1) @@ -78,9 +85,14 @@ class ModParserService @Autowired constructor( val enrichedModDictionary = defaultDictionary + modDictionary val weapons = saveWeapons(modFolderData, mod, armorTypes, enrichedModDictionary) + val researches = saveResearches(modFolderData, mod, enrichedModDictionary) saveUnits(modFolderData, weapons, racesList, armorTypes, mod, enrichedModDictionary) + saveBuildings(modFolderData, weapons, researches, racesList, armorTypes, mod, enrichedModDictionary) + + modRepository.removeCampaignEntities(mod.id!!) + postParsingService.bindResearch(mod) + log.info("Complete parse mod ${mod.technicalName}:${mod.version}") - saveBuildings(modFolderData, weapons, racesList, armorTypes, mod, enrichedModDictionary) } @@ -110,6 +122,49 @@ class ModParserService @Autowired constructor( return modDictionary } + + private fun saveResearches( + modFolderData: String, + mod: Mod, + modDictionary: Map + ): Set { + + val classicRgdDataResearches = + rgdParserService.parseFolderToRgdFiles( + modAttribPathService.getResearchAttribsPath( + modAttribPathService.pathToWanilaData, + ) + ) + val modRgdDataResearches = + rgdParserService.parseFolderToRgdFiles( + modAttribPathService.getResearchAttribsPath( + modFolderData, + ) + ) + + val researchesFull = classicRgdDataResearches + modRgdDataResearches + + val researches = researchesFull.mapNotNull { researchData -> + try { + researchRgdExtractService.extractToResearchEntity( + researchData.key, + modDictionary, + researchData.value, + modFolderData, + mod, + ) + } catch (e: Exception) { + log.error("Can't extract ${researchData.key}", e) + null + } + } + return try { + researchRepository.saveAll(researches).toSet() + } catch (e: Exception) { + throw e + } + } + private fun saveUnits( modFolderData: String, weapons: Set, @@ -173,6 +228,7 @@ class ModParserService @Autowired constructor( try { unitRgdExtractService.extractToUnitEntity( squadRgdData.key, + baseUnitName, modDictionary, squadRgdData.value, unitRgdData, @@ -230,6 +286,7 @@ class ModParserService @Autowired constructor( sergeantRepository.save(sergeant) } } catch (e: Exception) { + log.error("Cant save unit ${unitDataToSave.unit.name}", e) throw e } } @@ -239,6 +296,7 @@ class ModParserService @Autowired constructor( private fun saveBuildings( modFolderData: String, weapons: Set, + researches: Set, racesList: List, armorTypes: Set, mod: Mod, modDictionary: Map @@ -282,6 +340,7 @@ class ModParserService @Autowired constructor( modDictionary, structure.value, weapons, + researches, raceUnits, race, modFolderData, @@ -356,4 +415,6 @@ class ModParserService @Autowired constructor( } } + + } diff --git a/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt new file mode 100644 index 0000000..a871ede --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt @@ -0,0 +1,88 @@ +package com.dowstats.service.w40k + +import com.dowstats.data.entities.* +import com.dowstats.data.entities.research.Research +import com.dowstats.data.entities.research.ResearchModifiers +import com.dowstats.data.entities.research.ResearchRequirements +import com.dowstats.data.rgd.RgdData +import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName +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 + +@Service +class ResearchRgdExtractService @Autowired constructor( + private val commonParseRgdService: CommonParseRgdService, +) { + + val log = LoggerFactory.getLogger(ResearchRgdExtractService::class.java) + + fun extractToResearchEntity( + fileName: String, + modDictionary: Map, + researchData: List, + modFolderData: String, + mod: Mod, + ): Research { + + val research = Research() + research.filename = fileName + + val uiInfo = researchData.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileName") + val researchUiInfo = commonParseRgdService.getUiInfo(uiInfo, modDictionary, modFolderData, mod, log) + research.name = researchUiInfo.name + research.description = researchUiInfo.description + research.icon = researchUiInfo.iconPath + + val cost = commonParseRgdService.getBuildCost(researchData.getRgdTableByName("time_cost")) + + research.costRequisition = cost.requisition + research.costPower = cost.power + research.costFaith = cost.faith + research.costSouls = cost.souls + research.costTime = cost.time + research.researchModifiers = getResearchModifiers(research, researchData).toMutableSet() + research.addonRequirements = getResearchRequirements(research, researchData).toMutableSet() + + research.modId = mod.id + + return research + } + + private fun getResearchModifiers(research: Research, researchData: List): List { + val modifiers = researchData.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 { + ResearchModifiers().also { + it.research = research + it.reference = mTable.getStringByName("\$REF") + it.usageType = mTable.getRgdTableByName("usage_type")?.getStringByName("\$REF") + it.target = mTable.getStringByName("target_type_name") + it.value = mTable.getDoubleByName("value") + } + } + } else null + } ?: emptyList() + } + + private fun getResearchRequirements(research: Research, researchData: List): List { + val requirements = researchData.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 { + ResearchRequirements().also { + it.research = research + it.reference = rTable.getStringByName("\$REF") + it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, research.filename!!, log) + } + } + } else null + } ?: emptyList() + } + +} diff --git a/src/main/kotlin/com/dowstats/service/w40k/RgdParserService.kt b/src/main/kotlin/com/dowstats/service/w40k/RgdParserService.kt index bd10861..7ac0a6a 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/RgdParserService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/RgdParserService.kt @@ -13,7 +13,7 @@ import java.nio.ByteBuffer class RgdParserService @Autowired constructor( ) { - val log = LoggerFactory.getLogger(WeaponRgdExtractService::class.java) + val log = LoggerFactory.getLogger(RgdParserService::class.java) val zeroByte: Byte = 0 diff --git a/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt index 4f9b38a..9d5fb0e 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt @@ -7,18 +7,13 @@ 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 com.dowstats.service.w40k.UnitRgdExtractService.ResourceIncome 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 SergeantRgdExtractService @Autowired constructor( - private val modAttribPathService: ModAttribPathService, - private val iconsService: IconsService, + private val commonParseRgdService: CommonParseRgdService, ) { val log = LoggerFactory.getLogger(SergeantRgdExtractService::class.java) @@ -42,11 +37,6 @@ class SergeantRgdExtractService @Autowired constructor( val upTime: Double?, ) - data class SquadTexts( - val name: String?, - val description: String?, - ) - fun extractToSergeantEntity( fileName: String, modDictionary: Map, @@ -69,19 +59,23 @@ class SergeantRgdExtractService @Autowired constructor( sergeant.armorType = getUnitArmorType(sergeantData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") sergeant.armorType2 = getUnitArmorType(sergeantData, armorTypes, "type_armour_2") - - val nameAndDescription = getSergeantNameAndDescription(sergeantData, modDictionary) - sergeant.name = nameAndDescription.name - sergeant.description = nameAndDescription.description sergeant.filename = fileName + val sergeantUiRgd = sergeantData.getRgdTableByName("ui_ext") + ?.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileName") + val sergeantUiInfo = commonParseRgdService.getUiInfo(sergeantUiRgd, modDictionary, modFolderData, mod, log) + sergeant.name = sergeantUiInfo.name + sergeant.description = sergeantUiInfo.description + sergeant.icon = sergeantUiInfo.iconPath + + val healthData = getHealthAndMoraleDeathPenaltyData(sergeantData) sergeant.health = healthData.hitpoints?.toInt() sergeant.armour = healthData.armour sergeant.healthRegeneration = healthData.regeneration sergeant.moraleDeathPenalty = healthData.moraleDeathPenalty?.toInt() - val incomeData = getResource(sergeantData) + val incomeData = commonParseRgdService.getResourceIncome(sergeantData.getRgdTableByName("resource_ext")) sergeant.faithIncome = incomeData.faith sergeant.powerIncome = incomeData.power sergeant.requisitionIncome = incomeData.requisition @@ -93,8 +87,7 @@ class SergeantRgdExtractService @Autowired constructor( sergeant.mass = massData.mass sergeant.upTime = massData.upTime - val unitIcon = convertSergeantIconAndReturnPath(sergeantData, modFolderData, mod.name) - sergeant.icon = unitIcon + sergeant.modId = mod.id!! val sergeantWeapons = getSergeantWeapons(sergeantData)?.mapNotNull { weaponData -> weapons.find { @@ -119,29 +112,6 @@ class SergeantRgdExtractService @Autowired constructor( return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") } } - private fun getSergeantNameAndDescription(sergeantData: List, modDictionary: Map): SquadTexts { - val uiInfo = sergeantData.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 SquadTexts(name, description) - } - private fun getHealthAndMoraleDeathPenaltyData(unitData: List): HealthAndMoraleDeathData { val healthExt = unitData.getRgdTableByName("health_ext") @@ -153,14 +123,6 @@ class SergeantRgdExtractService @Autowired constructor( ) } - private fun getResource(sergeantData: List): ResourceIncome { - val resourceExt = sergeantData.getRgdTableByName("resource_ext") - return ResourceIncome( - resourceExt?.getDoubleByName("faith_per_second")?.let { it * 10 }, - resourceExt?.getDoubleByName("power_per_second")?.let { it * 10 }, - resourceExt?.getDoubleByName("requisition_per_second")?.let { it * 10 }, - ) - } private fun getMassData(unitData: List): MassData { val massDataRgd = unitData @@ -201,14 +163,4 @@ class SergeantRgdExtractService @Autowired constructor( } else null }?.flatten() - private fun convertSergeantIconAndReturnPath(sergeantData: List, modFolderData: String, modName: String?): String? { - val iconPathInMod = sergeantData - .getRgdTableByName("ui_ext") - ?.getRgdTableByName("ui_info") - ?.getStringByName("icon_name") - - return iconPathInMod?.let { modAttribPathService.getIconPath(modFolderData, iconPathInMod) } - ?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) } - } - } diff --git a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt index 598ac8b..805d762 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt @@ -16,8 +16,7 @@ import org.springframework.stereotype.Service @Service class UnitRgdExtractService @Autowired constructor( - private val modAttribPathService: ModAttribPathService, - private val iconsService: IconsService, + private val commonParseRgdService: CommonParseRgdService, private val sergeantRgdExtractService: SergeantRgdExtractService, ) { @@ -36,12 +35,6 @@ class UnitRgdExtractService @Autowired constructor( val percentCost: Int?, ) - data class ResourceIncome( - val faith: Double?, - val power: Double?, - val requisition: Double?, - ) - data class MoraleData( val max: Double?, val broken: Double?, @@ -58,13 +51,10 @@ class UnitRgdExtractService @Autowired constructor( val upTime: Double?, ) - data class UnitTexts( - val name: String?, - val description: String?, - ) fun extractToUnitEntity( - fileName: String, + fileNameSquad: String, + fileNameUnit: String, modDictionary: Map, squadData: List, unitData: List, @@ -84,10 +74,14 @@ class UnitRgdExtractService @Autowired constructor( unit.armorType = getUnitArmorType(unitData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") unit.armorType2 = getUnitArmorType(unitData, armorTypes, "type_armour_2") - val nameAndDescription = getUnitNameAndDescription(squadData, modDictionary) - unit.name = nameAndDescription.name - unit.description = nameAndDescription.description - unit.filename = fileName + val squadUiInfo = squadData.getRgdTableByName("squad_ui_ext") + ?.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileNameSquad") + val squadUiData = commonParseRgdService.getUiInfo(squadUiInfo, modDictionary, modFolderData, mod, log) + unit.name = squadUiData.name + unit.description = squadUiData.description + unit.icon = squadUiData.iconPath + unit.filenameSquad = fileNameSquad + unit.filenameUnit = fileNameUnit val buildCost = getBuildCost(unitData, squadData) unit.buildCostRequisition = buildCost.requisition @@ -117,7 +111,7 @@ class UnitRgdExtractService @Autowired constructor( unit.repairSpeed = repairData.healthPerSecond unit.repairCostPercent = repairData.percentCost - val incomeData = getResource(unitData) + val incomeData = commonParseRgdService.getResourceIncome(unitData.getRgdTableByName("resource_ext")) unit.faithIncome = incomeData.faith unit.powerIncome = incomeData.power unit.requisitionIncome = incomeData.requisition @@ -135,14 +129,14 @@ class UnitRgdExtractService @Autowired constructor( unit.mass = massData.mass unit.upTime = massData.upTime - val reinforceData = getReinforceRgdData(squadData) - val reinforceCostData = reinforceData?.getRgdTableByName("cost") - unit.reinforceCostRequisition = getReinforceRequisition(reinforceCostData) - unit.reinforceCostPower = getReinforcePower(reinforceCostData) - unit.reinforceCostPopulation = getReinforcePopulation(reinforceCostData) - unit.reinforceCostFaith = getReinforceFaith(reinforceCostData) - unit.reinforceCostSouls = getReinforceSouls(reinforceCostData) - unit.reinforceTime = getReinforceTime(reinforceData) + val reinforceCostRgdData = getReinforceCostRgdData(squadData) + val reinforceCostData = commonParseRgdService.getBuildCost(reinforceCostRgdData) + unit.reinforceCostRequisition = reinforceCostData.requisition + unit.reinforceCostPower = reinforceCostData.power + unit.reinforceCostPopulation = reinforceCostData.population + unit.reinforceCostFaith = reinforceCostData.faith + unit.reinforceCostSouls = reinforceCostData.souls + unit.reinforceTime = reinforceCostData.time @@ -167,8 +161,6 @@ class UnitRgdExtractService @Autowired constructor( unit.maxSergeants = sergeantsData.second - val unitIcon = convertIconAndReturnPath(mod.name, squadData, modFolderData) - unit.icon = unitIcon val unitWeapons = getUnitWeapons(unitData, weapons) @@ -201,11 +193,7 @@ class UnitRgdExtractService @Autowired constructor( private fun getBuildCost(unitData: List, squadData: List): BuildCost { - val cost = unitData.getRgdTableByName("cost_ext") - ?.getRgdTableByName("time_cost") - - val costResources = cost - ?.getRgdTableByName("cost") + val cost = commonParseRgdService.getBuildCost(unitData.getRgdTableByName("cost_ext")?.getRgdTableByName("time_cost")) val minSquadSize = squadData.getRgdTableByName("squad_loadout_ext") ?.getDoubleByName("unit_min")?.toInt() @@ -214,45 +202,15 @@ class UnitRgdExtractService @Autowired constructor( cost?.let { it * (minSquadSize ?: 1) } return BuildCost( - getCost(costResources?.getDoubleByName("requisition")), - getCost(costResources?.getDoubleByName("power")), - getCost(costResources?.getDoubleByName("population")), - getCost(costResources?.getDoubleByName("faith")), - getCost(costResources?.getDoubleByName("souls")), - getCost(cost?.getDoubleByName("time_seconds"))?.toInt() + getCost(cost.requisition), + getCost(cost.power), + getCost(cost.population), + getCost(cost.faith), + getCost(cost.souls), + getCost(cost.time?.toDouble())?.toInt() ) } - private fun getUnitNameAndDescription(squadData: List, modDictionary: Map): UnitTexts { - val uiInfo = squadData.getRgdTableByName("squad_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 != "" && it.toIntOrNull() != null } - ?.sortedBy { it.toInt() } - - val description = try { - descriptionRefs?.map { - modDictionary[it.toInt()] }?.joinToString("\n") - } catch (e: Exception) { - log.warn("Error parsing ui description", e) - null - } - - return UnitTexts(name, description) - } - private fun getSquadCap(squadData: List): Pair { @@ -307,14 +265,6 @@ class UnitRgdExtractService @Autowired constructor( ) } - private fun getResource(unitData: List): ResourceIncome { - val resourceExt = unitData.getRgdTableByName("resource_ext") - return ResourceIncome( - resourceExt?.getDoubleByName("faith_per_second")?.let { it * 10 }, - resourceExt?.getDoubleByName("power_per_second")?.let { it * 10 }, - resourceExt?.getDoubleByName("requisition_per_second")?.let { it * 10 }, - ) - } private fun getMoraleData(squadData: List): MoraleData { val moraleData = squadData.getRgdTableByName("squad_morale_ext") @@ -346,28 +296,10 @@ class UnitRgdExtractService @Autowired constructor( .getRgdTableByName("sight_ext") ?.getDoubleByName("keen_sight_radius") - private fun getReinforceRgdData(squadData: List): List? = squadData + private fun getReinforceCostRgdData(squadData: List): List? = squadData .getRgdTableByName("squad_reinforce_ext") ?.getRgdTableByName("cost") - private fun getReinforceRequisition(reinforceData: List?): Int? = reinforceData - ?.getIntByName("requisition") - - private fun getReinforcePower(reinforceData: List?): Int? = reinforceData - ?.getIntByName("power") - - private fun getReinforcePopulation(reinforceData: List?): Int? = reinforceData - ?.getIntByName("population") - - private fun getReinforceFaith(reinforceData: List?): Int? = reinforceData - ?.getIntByName("faith") - - private fun getReinforceSouls(reinforceData: List?): Int? = reinforceData - ?.getIntByName("souls") - - private fun getReinforceTime(reinforceData: List?): Int? = reinforceData - ?.getIntByName("time_seconds") - private fun getUnitWeapons(reinforceData: List?, weapons: Set): List? = reinforceData ?.getRgdTableByName("combat_ext") ?.getRgdTableByName("hardpoints") @@ -382,9 +314,9 @@ class UnitRgdExtractService @Autowired constructor( it.mapNotNull { weapon -> (weapon.value as? List)?.getStringByName("weapon")?.let { if (it != "") { - val weaponFileName = it.replace("weapon\\", "").replace(".lua", ".rgd") + val weaponFileName = it.replace("weapon\\", "").replace(".lua", "") val weaponEntity = weapons.find { - it.filename == weaponFileName + it.filename?.replace(".rgd", "") == weaponFileName } if(weaponEntity == null){ log.warn("Can't find weapon $weaponFileName") @@ -418,19 +350,9 @@ class UnitRgdExtractService @Autowired constructor( if (sergeantLeaderFilePath == null || sergeantLeaderFilePath == "") null else { - val cost = sergeantRgdTable.getRgdTableByName("cost_time") - val costResources = cost?.getRgdTableByName("cost") - SergeantData( sergeantLeaderFilePath, - BuildCost( - costResources?.getDoubleByName("requisition"), - costResources?.getDoubleByName("power"), - costResources?.getDoubleByName("population"), - costResources?.getDoubleByName("faith"), - costResources?.getDoubleByName("souls"), - cost?.getIntByName("time_seconds"), - ) + commonParseRgdService.getBuildCost(sergeantRgdTable.getRgdTableByName("cost_time")) ) } } else null @@ -438,15 +360,4 @@ class UnitRgdExtractService @Autowired constructor( return Pair(sergeantsData, maxSergeants) } - - private fun convertIconAndReturnPath(modName: String?, squadData: List, modFolderData: String): String? { - val iconPathInMod = squadData - .getRgdTableByName("squad_ui_ext") - ?.getRgdTableByName("ui_info") - ?.getStringByName("icon_name") - - return iconPathInMod?.let { modAttribPathService.getIconPath(modFolderData, iconPathInMod) } - ?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) } - } - } diff --git a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt index cf98e3f..af21074 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt @@ -4,69 +4,40 @@ import com.dowstats.data.entities.ArmorType import com.dowstats.data.entities.Mod import com.dowstats.data.entities.Weapon import com.dowstats.data.entities.WeaponArmorPiercing -import com.dowstats.data.repositories.ArmorTypeRepository 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.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.math.BigDecimal -import java.nio.file.Path -import kotlin.io.path.exists @Service class WeaponRgdExtractService @Autowired constructor( - private val armorTypeRepository: ArmorTypeRepository, - private val iconsService: IconsService, - private val modAttribPathService: ModAttribPathService, + private val commonParseRgdService: CommonParseRgdService, ) { val log = LoggerFactory.getLogger(WeaponRgdExtractService::class.java) - data class BuildCost( - val requisition: Int?, - val power: Int?, - val seconds: Int? - ) - - data class AreaEffectData( - val minDamage: Double, - val maxDamage: Double, - val damageRadius: Double, - val throwForceMin: Double, - val throwForceMax: Double, - val minDamageValue: Double, - val moraleDamage: Double, - val armourPiercing: List, - ) - - data class WeaponUiInfo( - val name: String?, - val description: String?, - val iconPath: String?, - val haveEquipButton: Boolean - ) fun extractToWeaponEntity(weaponFileName: String, weaponData: List, mod: Mod, armorTypes: Set, modFolderData: String, modDictionary: Map): Weapon? { val weapon = Weapon() weapon.filename = weaponFileName - val weaponUiData = getWeaponNameAndDescription(weaponData, modDictionary, modFolderData, mod) + + val weaponUiInfo = weaponData.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $weaponFileName") + val weaponUiData = commonParseRgdService.getUiInfo(weaponUiInfo, modDictionary, modFolderData, mod, log) weapon.name = weaponUiData.name weapon.icon = weaponUiData.iconPath weapon.description = weaponUiData.description - weapon.haveEquipButton = weaponUiData.haveEquipButton + weapon.haveEquipButton = weaponUiInfo.getBooleanByName("no_button")?.let { !it } ?: false - val cost = getCost(weaponData) - weapon.costRequisition = cost.requisition ?: 0 - weapon.costPower = cost.power ?: 0 - weapon.costTimeSeconds = cost.seconds ?: 0 + val cost = commonParseRgdService.getBuildCost(weaponData.getRgdTableByName("cost")) + weapon.costRequisition = cost.requisition ?: 0.0 + weapon.costPower = cost.power ?: 0.0 + weapon.costTimeSeconds = cost.time ?: 0 weapon.accuracy = weaponData.getDoubleByName("accuracy") ?: 1.0 weapon.accuracyReductionMoving = weaponData.getDoubleByName("accuracy_reduction_when_moving") weapon.minRange = weaponData.getDoubleByName("min_range") @@ -79,14 +50,24 @@ class WeaponRgdExtractService @Autowired constructor( weapon.canAttackGround = weaponData.getBooleanByName("can_attack_ground_units") ?: true - val areaEffectData = getAreaEffectData(weaponData, armorTypes, weapon) + val areaEffectData = commonParseRgdService.getAreaEffectData(weaponData) + + val armoursPiercing = armorTypes.map { + val weaponArmourPiercing = WeaponArmorPiercing() + weaponArmourPiercing.weapon = weapon + weaponArmourPiercing.armorType = it + val piercingValue = (areaEffectData.weaponDmgMap[it.id] ?: areaEffectData.defaultArmorPiercing).toBigDecimal() + weaponArmourPiercing.piercingValue = piercingValue.let {pv -> if(pv <= BigDecimal(100)) pv else BigDecimal(100) } + weaponArmourPiercing + } + weapon.minDamageValue = areaEffectData.minDamageValue weapon.minDamage = areaEffectData.minDamage weapon.maxDamage = areaEffectData.maxDamage weapon.throwForceMin = areaEffectData.throwForceMin weapon.throwForceMax = areaEffectData.throwForceMax weapon.moraleDamage = areaEffectData.moraleDamage - weapon.weaponPiercings = areaEffectData.armourPiercing + weapon.weaponPiercings = armoursPiercing weapon.damageRadius = areaEffectData.damageRadius weapon.modId = mod.id @@ -95,94 +76,5 @@ class WeaponRgdExtractService @Autowired constructor( } else weapon } - private fun getCost(weaponData: List): BuildCost { - val costTable = weaponData.getRgdTableByName("cost") - val costTime = costTable?.getIntByName("time_seconds") - val costCost = costTable?.getRgdTableByName("cost") - val power = costCost?.getIntByName("power") - val requisition = costCost?.getIntByName("requisition") - return BuildCost(requisition, power, costTime) - } - private fun getAreaEffectData(weaponData: List, armorTypes: Set, thisWeapon: Weapon): AreaEffectData { - val areaEffect = weaponData.getRgdTableByName("area_effect") - - 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 - val forceMax = throwData?.getDoubleByName("force_max") ?: 0.0 - - val armourDamage = areaEffect - ?.getRgdTableByName("weapon_damage") - ?.getRgdTableByName("armour_damage") - val minDamage = armourDamage?.getDoubleByName("min_damage") ?: 0.0 - val maxDamage = armourDamage?.getDoubleByName("max_damage") ?: 0.0 - val minDamageValue = armourDamage?.getDoubleByName("min_damage_value") ?: 0.0 - val moraleDamage = armourDamage?.getDoubleByName("morale_damage") ?: 0.0 - - - val defaultArmourPiercing = armourDamage?.getDoubleByName("armour_piercing") - val weaponDmgMap: Map = - armourDamage?.getRgdTableByName("armour_piercing_types")?.mapNotNull { armour_piercing -> - if (armour_piercing.name.contains("entry")) { - val entry = armour_piercing.value as List - val dmgType = entry.getRgdTableByName("armour_type")?.getStringByName("\$REF")?.replace("type_armour\\tp_","")?.replace(".lua","") - val dmgValue = entry.getDoubleByName("armour_piercing_value") - dmgType!! to dmgValue!! - } else null - }?.toMap() ?: emptyMap() - - val armoursPiercing = armorTypes.map { - val weaponArmourPiercing = WeaponArmorPiercing() - weaponArmourPiercing.weapon = thisWeapon - weaponArmourPiercing.armorType = it - val piercingValue = (weaponDmgMap[it.id] ?: defaultArmourPiercing)?.toBigDecimal() - weaponArmourPiercing.piercingValue = piercingValue?.let {pv -> if(pv <= BigDecimal(100)) pv else BigDecimal(100) } - weaponArmourPiercing - } - - return AreaEffectData(minDamage, maxDamage, damageRadius, forceMin, forceMax, minDamageValue, moraleDamage, armoursPiercing) - } - - - private fun getWeaponNameAndDescription(weaponData: List, modDictionary: Map, modFolderData: String, mod: Mod): WeaponUiInfo { - val weaponUiInfo = weaponData.getRgdTableByName("ui_info") - - val nameRef = weaponUiInfo?.getStringByName("screen_name_id")?.replace("$", "") - val name = nameRef?.let { try { modDictionary[it.toInt()] } catch (e: Exception) { null } } - - val descriptionRefs = weaponUiInfo?.getRgdTableByName("help_text_list") - ?.mapNotNull{try { - (it.value as String).replace("$", "") - } catch (e: Exception) { - log.error("Error parsing ui help_text weapon $name", e) - null - }} - ?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""} - ?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } } - - val description = try { - descriptionRefs?.map { try { modDictionary[it.toInt()] } catch (e: Exception) { "" } }?.joinToString ( "\n" ) - } catch(e:Exception) { - log.warn("Error parsing ui description weapon $name", e) - null - } - - val icon = try { - val iconPath = weaponUiInfo?.getStringByName("icon_name") - - iconPath?.let { modAttribPathService.getIconPath(modFolderData, iconPath) } - ?.let { iconsService.convertTgaToJpegImage(iconPath, it, mod.name) } - } catch (e: Exception) { - log.error("Error parsing ui icon path for weapon $name", e) - null - } - - val haveUpgradeButton = weaponUiInfo?.getBooleanByName("no_button")?.let { !it } ?: false - - return WeaponUiInfo(name, description, icon, haveUpgradeButton) - } } diff --git a/src/main/resources/db/0.0.3/data/armor_types.json b/src/main/resources/db/0.0.3/data/armor_types.json new file mode 100644 index 0000000..a4c0ea2 --- /dev/null +++ b/src/main/resources/db/0.0.3/data/armor_types.json @@ -0,0 +1,65 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Update armor type names", + "author": "anibus", + "changes": [ + { + "update": { + "columns": [ + { + "column": { + "name": "name", + "value": "Infantry H.Med." + } + } + ], + "tableName": "armor_types", + "where": "name='Infantry Heavy Medium'" + } + },{ + "update": { + "columns": [ + { + "column": { + "name": "name", + "value": "Infantry H.High" + } + } + ], + "tableName": "armor_types", + "where": "name='Infantry Heavy High'" + } + },{ + "update": { + "columns": [ + { + "column": { + "name": "name", + "value": "Infantry Com." + } + } + ], + "tableName": "armor_types", + "where": "name='Commander'" + } + },{ + "update": { + "columns": [ + { + "column": { + "name": "name", + "value": "Vehicle Air" + } + } + ], + "tableName": "armor_types", + "where": "name='Air'" + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/db/0.0.3/procedures/delete_campaign_entities.sql b/src/main/resources/db/0.0.3/procedures/delete_campaign_entities.sql new file mode 100644 index 0000000..2ce5684 --- /dev/null +++ b/src/main/resources/db/0.0.3/procedures/delete_campaign_entities.sql @@ -0,0 +1,11 @@ +CREATE OR REPLACE PROCEDURE delete_campaign_entities(mod_id_p bigint) + LANGUAGE SQL +AS $$ +DELETE FROM units WHERE mod_id = mod_id_p AND (fileName_squad LIKE '%\_dxp3.%' OR fileName_squad LIKE '%\_dxp3.%' OR fileName_squad LIKE '%sp\_eldar\_%' OR fileName_squad LIKE '%\_sp\_%' OR fileName_squad LIKE '%\_sp.%' OR fileName_squad LIKE '%\_nis.%' OR fileName_squad LIKE '%\_interface\_relay.%' OR fileName_squad LIKE '%necron\_tunnel.rgd%' OR fileName_squad LIKE '%\_exarch\_council.%' OR fileName_squad LIKE '%\_dark\_reapers\_base.%' OR fileName_squad LIKE '%eldar\_deep\_strike\_building.rgd%' OR fileName_squad LIKE '%ork\_deep\_strike\_building.rgd%' OR fileName_squad LIKE '%\_caravel\_ai.rgd%' OR fileName_squad LIKE '%sisters\_tanktrap\_ai.rgd%' OR fileName_squad LIKE '%sisters\_hq\_ktgm.rgd%' OR fileName_squad LIKE '%tau\_squad\_slave\_murdered%' OR fileName_squad LIKE '%single\_player\_only%' OR fileName_squad LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR fileName_squad LIKE '%advance\_sp%' OR fileName_squad LIKE '%\_no\_limit.rgd%'); +DELETE FROM buildings WHERE mod_id = mod_id_p AND (filename LIKE '%\_dxp3.%' OR filename LIKE '%\_dxp3.%' OR filename LIKE '%sp\_eldar\_%' OR filename LIKE '%\_sp\_%' OR filename LIKE '%\_sp.%' OR filename LIKE '%\_nis.%' OR filename LIKE '%\_interface\_relay.%' OR filename LIKE '%necron\_tunnel.rgd%' OR filename LIKE '%\_exarch\_council.%' OR filename LIKE '%\_dark\_reapers\_base.%' OR filename LIKE '%eldar\_deep\_strike\_building.rgd%' OR filename LIKE '%ork\_deep\_strike\_building.rgd%' OR filename LIKE '%\_caravel\_ai.rgd%' OR filename LIKE '%sisters\_tanktrap\_ai.rgd%' OR filename LIKE '%sisters\_hq\_ktgm.rgd%' OR filename LIKE '%tau\_squad\_slave\_murdered%' OR filename LIKE '%single\_player\_only%' OR filename LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR filename LIKE '%advance\_sp%' OR filename LIKE '%night\_lords\_hq\_aep%' OR filename LIKE '%\_ktgm.rgd%' OR filename LIKE '%salamander\_hq\_aep.rgd%' OR filename LIKE '%\_no\_limit.rgd%'); +DELETE FROM weapons WHERE mod_id = mod_id_p AND (filename LIKE '%\_dxp3.%' OR filename LIKE '%\_dxp3.%' OR filename LIKE '%sp\_eldar\_%' OR filename LIKE '%\_sp\_%' OR filename LIKE '%\_sp.%' OR filename LIKE '%\_nis.%' OR filename LIKE '%\_interface\_relay.%' OR filename LIKE '%necron\_tunnel.rgd%' OR filename LIKE '%\_exarch\_council.%' OR filename LIKE '%\_dark\_reapers\_base.%' OR filename LIKE '%eldar\_deep\_strike\_building.rgd%' OR filename LIKE '%ork\_deep\_strike\_building.rgd%' OR filename LIKE '%\_caravel\_ai.rgd%' OR filename LIKE '%sisters\_tanktrap\_ai.rgd%' OR filename LIKE '%sisters\_hq\_ktgm.rgd%' OR filename LIKE '%tau\_squad\_slave\_murdered%' OR filename LIKE '%single\_player\_only%' OR filename LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR filename LIKE '%advance\_sp%'); +DELETE FROM researches WHERE mod_id = mod_id_p AND (filename LIKE '%\_dxp3.%' OR filename LIKE '%\_dxp3.%' OR filename LIKE '%sp\_eldar\_%' OR filename LIKE '%\_sp\_%' OR filename LIKE '%\_sp.%' OR filename LIKE '%\_nis.%' OR filename LIKE '%\_interface\_relay.%' OR filename LIKE '%necron\_tunnel.rgd%' OR filename LIKE '%\_exarch\_council.%' OR filename LIKE '%\_dark\_reapers\_base.%' OR filename LIKE '%eldar\_deep\_strike\_building.rgd%' OR filename LIKE '%ork\_deep\_strike\_building.rgd%' OR filename LIKE '%\_caravel\_ai.rgd%' OR filename LIKE '%sisters\_tanktrap\_ai.rgd%' OR filename LIKE '%sisters\_hq\_ktgm.rgd%' OR filename LIKE '%tau\_squad\_slave\_murdered%' OR filename LIKE '%single\_player\_only%' OR filename LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR filename LIKE '%advance\_sp%'); +DELETE FROM research_modifiers USING researches WHERE researches.mod_id = 3 AND researches.id = research_id AND (target LIKE '%\_dxp3%' OR target LIKE '%\_dxp3%' OR target LIKE '%sp\_eldar\_%' OR target LIKE '%\_sp\_%' OR target LIKE '%\_sp.%' OR target LIKE '%\_nis.%' OR target LIKE '%\_interface\_relay.%' OR target LIKE '%necron\_tunnel.rgd%' OR target LIKE '%\_exarch\_council.%' OR target LIKE '%\_dark\_reapers\_base.%' OR target LIKE '%eldar\_deep\_strike\_building.rgd%' OR target LIKE '%ork\_deep\_strike\_building.rgd%' OR target LIKE '%\_caravel\_ai.rgd%' OR target LIKE '%sisters\_tanktrap\_ai.rgd%' OR target LIKE '%sisters\_hq\_ktgm.rgd%' OR target LIKE '%tau\_squad\_slave\_murdered%' OR target LIKE '%single\_player\_only%' OR target LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR target LIKE '%advance\_sp%'); +DELETE FROM building_addons USING buildings WHERE buildings.mod_id = 3 AND buildings.id = building_addons.building_id AND (building_addons.filename LIKE '%\_dxp3%' OR building_addons.filename LIKE '%\_dxp3%' OR building_addons.filename LIKE '%sp\_eldar\_%' OR building_addons.filename LIKE '%\_sp\_%' OR building_addons.filename LIKE '%\_sp.%' OR building_addons.filename LIKE '%\_nis.%' OR building_addons.filename LIKE '%\_interface\_relay.%' OR building_addons.filename LIKE '%necron\_tunnel.rgd%' OR building_addons.filename LIKE '%\_exarch\_council.%' OR building_addons.filename LIKE '%\_dark\_reapers\_base.%' OR building_addons.filename LIKE '%eldar\_deep\_strike\_building.rgd%' OR building_addons.filename LIKE '%ork\_deep\_strike\_building.rgd%' OR building_addons.filename LIKE '%\_caravel\_ai.rgd%' OR building_addons.filename LIKE '%sisters\_tanktrap\_ai.rgd%' OR building_addons.filename LIKE '%sisters\_hq\_ktgm.rgd%' OR building_addons.filename LIKE '%tau\_squad\_slave\_murdered%' OR building_addons.filename LIKE '%single\_player\_only%' OR building_addons.filename LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR building_addons.filename LIKE '%advance\_sp%' OR building_addons.filename LIKE '%addon\_necron\_hq\_3%'); +DELETE FROM abilities WHERE mod_id = mod_id_p AND (filename LIKE '%\_dxp3.%' OR filename LIKE '%\_dxp3.%' OR filename LIKE '%sp\_eldar\_%' OR filename LIKE '%\_sp\_%' OR filename LIKE '%\_sp.%' OR filename LIKE '%\_nis.%' OR filename LIKE '%\_interface\_relay.%' OR filename LIKE '%necron\_tunnel.rgd%' OR filename LIKE '%\_exarch\_council.%' OR filename LIKE '%\_dark\_reapers\_base.%' OR filename LIKE '%eldar\_deep\_strike\_building.rgd%' OR filename LIKE '%ork\_deep\_strike\_building.rgd%' OR filename LIKE '%\_caravel\_ai.rgd%' OR filename LIKE '%sisters\_tanktrap\_ai.rgd%' OR filename LIKE '%sisters\_hq\_ktgm.rgd%' OR filename LIKE '%tau\_squad\_slave\_murdered%' OR filename LIKE '%single\_player\_only%' OR filename LIKE '%space\_marine\_drop\_pod\_building.rgd%' OR filename LIKE '%advance\_sp%'); +$$; \ No newline at end of file diff --git a/src/main/resources/db/0.0.3/procedures/delete_mod_data_procedure.sql b/src/main/resources/db/0.0.3/procedures/delete_mod_data_procedure.sql new file mode 100644 index 0000000..3106e64 --- /dev/null +++ b/src/main/resources/db/0.0.3/procedures/delete_mod_data_procedure.sql @@ -0,0 +1,9 @@ +CREATE OR REPLACE PROCEDURE delete_mod_data(mod_id_p bigint) + LANGUAGE SQL +AS $$ +DELETE FROM units WHERE mod_id = mod_id_p; +DELETE FROM buildings WHERE mod_id = mod_id_p; +DELETE FROM weapons WHERE mod_id = mod_id_p; +DELETE FROM researches WHERE mod_id = mod_id_p; +DELETE FROM abilities WHERE mod_id = mod_id_p; +$$; \ No newline at end of file diff --git a/src/main/resources/db/0.0.3/schema/abilities.json b/src/main/resources/db/0.0.3/schema/abilities.json new file mode 100644 index 0000000..ed8f627 --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/abilities.json @@ -0,0 +1,94 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add abilities table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "abilities", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "filename", + "type": "varchar(255)", + "constraints": { + "nullable": false + } + } + },{ + "column": { + "name": "name", + "type": "varchar(255)" + } + },{ + "column": { + "name": "description", + "type": "varchar(5000)" + } + }, + { + "column": { + "name": "cost_requisition", + "type": "number" + } + },{ + "column": { + "name": "cost_power", + "type": "number" + } + },{ + "column": { + "name": "cost_faith", + "type": "number" + } + }, + { + "column": { + "name": "cost_souls", + "type": "number" + } + },{ + "column": { + "name": "icon", + "type": "varchar(128)" + } + },{ + "column": { + "name": "mod_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "mod_id", + "baseTableName": "abilities", + "constraintName": "fk_abilities_mods", + "referencedColumnNames": "id", + "referencedTableName": "mods" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/buildings_researches.json b/src/main/resources/db/0.0.3/schema/buildings_researches.json new file mode 100644 index 0000000..950694d --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/buildings_researches.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add buildings_researches table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "buildings_researches", + "columns": [ + { + "column": { + "name": "building_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "building_id, research_id", + "constraintName": "uc_buildings_researches_research_id_building_id", + "tableName": "buildings_researches" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "building_id", + "baseTableName": "buildings_researches", + "constraintName": "fk_buildings_buildings_researches", + "referencedColumnNames": "id", + "referencedTableName": "buildings", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "buildings_researches", + "constraintName": "fk_researches_buildings_researches", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/research_modifiers.json b/src/main/resources/db/0.0.3/schema/research_modifiers.json new file mode 100644 index 0000000..35b2b33 --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/research_modifiers.json @@ -0,0 +1,69 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add research_modifiers table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "research_modifiers", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + },{ + "column": { + "name": "reference", + "type": "varchar(255)" + } + },{ + "column": { + "name": "usage_type", + "type": "varchar(255)" + } + },{ + "column": { + "name": "target", + "type": "varchar(255)" + } + },{ + "column": { + "name": "value", + "type": "number" + } + },{ + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "research_modifiers", + "constraintName": "fk_researches_research_modifiers", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/research_requirements.json b/src/main/resources/db/0.0.3/schema/research_requirements.json new file mode 100644 index 0000000..825cb3e --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/research_requirements.json @@ -0,0 +1,59 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add research_requirements table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "research_requirements", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + },{ + "column": { + "name": "reference", + "type": "varchar(255)" + } + },{ + "column": { + "name": "value", + "type": "varchar(255)" + } + },{ + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "research_requirements", + "constraintName": "fk_research_requirements_researches", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/researches.json b/src/main/resources/db/0.0.3/schema/researches.json new file mode 100644 index 0000000..a105dde --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/researches.json @@ -0,0 +1,99 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add researches table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "researches", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "filename", + "type": "varchar(255)", + "constraints": { + "nullable": false + } + } + },{ + "column": { + "name": "name", + "type": "varchar(4096)" + } + },{ + "column": { + "name": "description", + "type": "varchar(5000)" + } + }, + { + "column": { + "name": "cost_requisition", + "type": "number" + } + },{ + "column": { + "name": "cost_power", + "type": "number" + } + },{ + "column": { + "name": "cost_faith", + "type": "number" + } + },{ + "column": { + "name": "cost_souls", + "type": "number" + } + },{ + "column": { + "name": "cost_time", + "type": "int" + } + },{ + "column": { + "name": "mod_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "icon", + "type": "varchar(128)" + } + } + ] + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "mod_id", + "baseTableName": "researches", + "constraintName": "fk_researches_mods", + "referencedColumnNames": "id", + "referencedTableName": "mods" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/researches_affected_buildings.json b/src/main/resources/db/0.0.3/schema/researches_affected_buildings.json new file mode 100644 index 0000000..b2dba3e --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/researches_affected_buildings.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add researches_affected_buildings table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "researches_affected_buildings", + "columns": [ + { + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "building_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "research_id, building_id", + "constraintName": "uc_researches_affected_buildings_research_id_building_id", + "tableName": "researches_affected_buildings" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "researches_affected_buildings", + "constraintName": "fk_researches_researches_affected_buildings", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "building_id", + "baseTableName": "researches_affected_buildings", + "constraintName": "fk_buildings_researches_affected_buildings", + "referencedColumnNames": "id", + "referencedTableName": "buildings", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/researches_affected_sergeants.json b/src/main/resources/db/0.0.3/schema/researches_affected_sergeants.json new file mode 100644 index 0000000..51c7f86 --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/researches_affected_sergeants.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add researches_affected_sergeants table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "researches_affected_sergeants", + "columns": [ + { + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "sergeant_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "research_id, sergeant_id", + "constraintName": "uc_researches_affected_sergeants_research_id_sergeant_id", + "tableName": "researches_affected_sergeants" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "researches_affected_sergeants", + "constraintName": "fk_researches_researches_affected_sergeants", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "sergeant_id", + "baseTableName": "researches_affected_sergeants", + "constraintName": "fk_sergeants_researches_affected_sergeants", + "referencedColumnNames": "id", + "referencedTableName": "sergeants", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/researches_affected_units.json b/src/main/resources/db/0.0.3/schema/researches_affected_units.json new file mode 100644 index 0000000..24e9ea3 --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/researches_affected_units.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add researches_affected_units table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "researches_affected_units", + "columns": [ + { + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "unit_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "research_id, unit_id", + "constraintName": "uc_researches_affected_units_research_id_unit_id", + "tableName": "researches_affected_units" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "researches_affected_units", + "constraintName": "fk_researches_researches_affected_units", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "unit_id", + "baseTableName": "researches_affected_units", + "constraintName": "fk_units_researches_affected_units", + "referencedColumnNames": "id", + "referencedTableName": "units", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/researches_affected_weapons.json b/src/main/resources/db/0.0.3/schema/researches_affected_weapons.json new file mode 100644 index 0000000..94bb06a --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/researches_affected_weapons.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add researches_affected_weapons table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "researches_affected_weapons", + "columns": [ + { + "column": { + "name": "research_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "weapon_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "research_id, weapon_id", + "constraintName": "uc_researches_affected_weapons_research_id_weapon_id", + "tableName": "researches_affected_weapons" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "research_id", + "baseTableName": "researches_affected_weapons", + "constraintName": "fk_researches_researches_affected_weapons", + "referencedColumnNames": "id", + "referencedTableName": "researches", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "weapon_id", + "baseTableName": "researches_affected_weapons", + "constraintName": "fk_weapons_researches_affected_weapons", + "referencedColumnNames": "id", + "referencedTableName": "weapons", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/sergeants.json b/src/main/resources/db/0.0.3/schema/sergeants.json new file mode 100644 index 0000000..747b811 --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/sergeants.json @@ -0,0 +1,25 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add mod_id column to sergeants", + "author": "anibus", + "changes": [ + { + "addColumn": { + "columns": [ + { + "column": { + "name": "mod_id", + "type": "int" + } + } + ], + "tableName": "sergeants" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.3/schema/units.json b/src/main/resources/db/0.0.3/schema/units.json new file mode 100644 index 0000000..6923e05 --- /dev/null +++ b/src/main/resources/db/0.0.3/schema/units.json @@ -0,0 +1,36 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add filename_unit column to unit and rename filename to filename_squad", + "author": "anibus", + "changes": [ + { + "addColumn": { + "columns": [ + { + "column": { + "name": "filename_unit", + "type": "varchar(255)", + "value": "", + "constraints": { + "nullable": false + } + } + } + ], + "tableName": "units" + } + }, + { + "renameColumn": { + "newColumnName": "filename_squad", + "oldColumnName": "filename", + "tableName": "units" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/changelog-master.json b/src/main/resources/db/changelog-master.json index 69dd6b9..34e7ac7 100644 --- a/src/main/resources/db/changelog-master.json +++ b/src/main/resources/db/changelog-master.json @@ -107,6 +107,67 @@ "include": { "file": "db/0.0.2/data/armor_types.json" } + }, + { + "include": { + "file": "db/0.0.3/schema/researches.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/research_requirements.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/research_modifiers.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/abilities.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/buildings_researches.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/researches_affected_units.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/researches_affected_sergeants.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/researches_affected_buildings.json" + } + },{ + "include": { + "file": "db/0.0.3/schema/researches_affected_weapons.json" + } + }, + { + "include": { + "file": "db/0.0.3/procedures/delete_mod_data_procedure.sql" + } + }, + { + "include": { + "file": "db/0.0.3/schema/units.json" + } + }, + { + "include": { + "file": "db/0.0.3/data/armor_types.json" + } + },{ + "include": { + "file": "db/0.0.3/procedures/delete_campaign_entities.sql" + } + }, + { + "include": { + "file": "db/0.0.3/schema/sergeants.json" + } } ] } diff --git a/src/test/kotlin/com/example/dowstats/service/w40k/BuildingRgdExtractServiceTest.kt b/src/test/kotlin/com/example/dowstats/service/w40k/BuildingRgdExtractServiceTest.kt index bf94000..bd82683 100644 --- a/src/test/kotlin/com/example/dowstats/service/w40k/BuildingRgdExtractServiceTest.kt +++ b/src/test/kotlin/com/example/dowstats/service/w40k/BuildingRgdExtractServiceTest.kt @@ -18,33 +18,6 @@ class BuildingRgdExtractServiceTest { val iconService = mockk() val addonRgdExtractService = mockk() - val buildingRgdExtractService = BuildingRgdExtractService(modAttribPathService, iconService, addonRgdExtractService) - val rgdService = RgdParserService() - @Test - fun `Should correct parse building`() { - - val buildingRgdFile = File("src/test/resources/rgd/waagh_banner/ork_waagh_banner.rgd") - - val rgdData = rgdService.parseRgdFileStream(DataInputStream(buildingRgdFile.inputStream())) - - val res = buildingRgdExtractService.extractToBuildingEntity("Waagh banner", emptyMap(), rgdData, emptySet(), "orks", "/modFolder", Mod(), listOf( - Race().also { - it.id = "orks" - it.name = "Орки" - } - ), listOf( - ArmorType().also { - it.id = "building_low" - it.name = "Лёгкие здания" - } - ), - emptyMap()) - - assertEquals(170.toDouble(), res.building.buildCostRequisition) - assertEquals(emptySet(), res.buildingWeapons) - - } - } \ No newline at end of file