diff --git a/pom.xml b/pom.xml
index ef8c52a..4c945b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -89,6 +89,11 @@
imageio-tga
3.10.1
+
+ com.twelvemonkeys.imageio
+ imageio-dds
+ 3.12.0
+
org.springframework.boot
spring-boot-starter-test
diff --git a/src/main/kotlin/com/dowstats/Metadata.kt b/src/main/kotlin/com/dowstats/Metadata.kt
index 0ae534b..712a410 100644
--- a/src/main/kotlin/com/dowstats/Metadata.kt
+++ b/src/main/kotlin/com/dowstats/Metadata.kt
@@ -5,12 +5,18 @@ object Metadata {
const val USER_ROLE = "USER"
object Requirements {
+ val REFERENCE_REQUIREMENT_NONE = "requirements\\required_none.lua"
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"
+ val REFERENCE_REQUIREMENT_OWNERSHIP = "requirements\\required_ownership.lua"
+ val REFERENCE_REQUIREMENT_CAP = "requirements\\required_cap.lua"
+ val REFERENCE_REQUIREMENT_SQUAD_CAP = "requirements\\required_squad_cap.lua"
+ val REFERENCE_REQUIREMENT_CUM_SQUAD_CAP = "requirements\\required_cumulative_squad_cap.lua"
+ val REFERENCE_REQUIREMENT_STRUCTURE_RATIO = "requirements\\required_structure_ratio.lua"
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dowstats/controllers/UnitsController.kt b/src/main/kotlin/com/dowstats/controllers/UnitsController.kt
index b4a7cb9..5606fd6 100644
--- a/src/main/kotlin/com/dowstats/controllers/UnitsController.kt
+++ b/src/main/kotlin/com/dowstats/controllers/UnitsController.kt
@@ -34,7 +34,7 @@ class UnitsController @Autowired constructor(
@GetMapping("/{unitId}")
fun getById(@PathVariable unitId: Long): UnitFullDto {
- return unitsRepo.findById(unitId).get().toDto()
+ return dowUnitMappingService.getUnitFullDto(unitId)
}
@DeleteMapping
diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/AffectedDataDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/AffectedDataDto.kt
new file mode 100644
index 0000000..2f00dae
--- /dev/null
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/AffectedDataDto.kt
@@ -0,0 +1,9 @@
+package com.dowstats.data.dto.controllers
+
+
+data class AffectedDataDto(
+ val affectedUnits: Set,
+ val affectedSergeants: Set,
+ val affectedBuildings: Set,
+ val affectedWeapons: Set,
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt
index fbde80a..2703c5d 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt
@@ -11,10 +11,17 @@ data class RequirementDto (
val requireAddon: BuildingAddonShortDto?,
val requirementsGlobalAddons: Set?,
val requiredTotalPop: Int?,
+ val limitByBuilding: RequirementLimitByBuildingDto?,
+ val requiredOwnership: Set,
val replaceWhenDone: Boolean = false,
)
data class RequirementResearchDto(
val researchShortDto: ResearchShortDto,
val researchMustNotBeComplete: Boolean,
+)
+
+data class RequirementLimitByBuildingDto(
+ val building: BuildingShortDto,
+ val limit: Int,
)
\ 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 ae2e346..2935e7a 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt
@@ -30,4 +30,5 @@ data class SergeantDto(
val icon: String?,
val weapons: List?,
val affectedResearches: Set,
+ val requirements: RequirementDto?,
)
diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt
index 753a971..0cb65e5 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantUnitShortDto.kt
@@ -1,5 +1,8 @@
package com.dowstats.data.dto.controllers
+import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto
+import com.dowstats.data.entities.Sergeant
+
data class SergeantUnitShortDto(
val id: Long?,
val filename: String,
@@ -7,3 +10,16 @@ data class SergeantUnitShortDto(
val icon: String?,
val unit: EntityCompressDto
)
+
+object SergeantUnitShortDtoObject{
+ fun MutableSet.toShortDtoSet() =
+ this.map {
+ SergeantUnitShortDto(
+ it.id!!,
+ it.filename!!,
+ it.name,
+ it.icon,
+ it.unit!!.compressDto()
+ )
+ }.toSet()
+}
\ No newline at end of file
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 7edc77f..a8c0c61 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,6 @@
package com.dowstats.data.dto.controllers
+import com.dowstats.data.dto.controllers.building.BuildingAddonShortDto
import com.dowstats.data.dto.controllers.research.ResearchShortDto
@@ -51,5 +52,8 @@ data class UnitFullDto(
val modId: Long,
val sergeants: Set?,
val weapons: Set?,
+ val haveReinforceMenu: Boolean,
val affectedResearches: Set,
+ val affectedAddons: Set,
+ val requirements: RequirementDto?,
)
\ No newline at end of file
diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/UnitShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/UnitShortDto.kt
index e7f14a9..4366b28 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/UnitShortDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/UnitShortDto.kt
@@ -3,9 +3,9 @@ package com.dowstats.data.dto.controllers
data class RaceUnits(
val race: RaceDto,
- val infantry: Set,
- val tech: Set,
- val support: Set,
+ val infantry: List,
+ val tech: List,
+ val support: List,
)
data class UnitShortDto(
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 9116cb4..6c729a8 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt
@@ -1,5 +1,6 @@
package com.dowstats.data.dto.controllers
+import com.dowstats.data.dto.controllers.building.BuildingAddonShortDto
import com.dowstats.data.dto.controllers.research.ResearchShortDto
data class WeaponDto(
@@ -27,8 +28,10 @@ data class WeaponDto(
val canAttackAir: Boolean,
val canAttackGround: Boolean,
val icon: String?,
- val haveEquipButton: Boolean,
+ val showInReinforce: Boolean,
val modId: Long?,
val weaponArmorPiercing: List,
val affectedResearches: Set,
+ val affectedAddons: Set,
+ val requirements: RequirementDto?,
)
diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt
index 136bee0..c976454 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponUnitShortDto.kt
@@ -1,5 +1,8 @@
package com.dowstats.data.dto.controllers
+import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto
+import com.dowstats.data.entities.Weapon
+
data class WeaponUnitShortDto(
val id: Long?,
val filename: String,
@@ -8,3 +11,27 @@ data class WeaponUnitShortDto(
val sergeants: Set,
val buildings: Set
)
+
+object WeaponUnitShortDtoObject{
+ fun MutableSet.toShortDtoSet() =
+ this.map {
+ 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()
+}
\ No newline at end of file
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 af4811e..a0c56be 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,7 +1,6 @@
package com.dowstats.data.dto.controllers.building
-import com.dowstats.data.dto.controllers.ModifierDto
-import com.dowstats.data.dto.controllers.RequirementDto
+import com.dowstats.data.dto.controllers.*
data class BuildingAddonDto(
val id: Long?,
@@ -15,6 +14,7 @@ data class BuildingAddonDto(
val addonCostSouls: Double?,
val addonCostTime: Int?,
val addonModifiers: Set,
+ val affectedData: AffectedDataDto,
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 dd8f7d3..596c331 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
@@ -1,9 +1,6 @@
package com.dowstats.data.dto.controllers.building
-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.dto.controllers.*
import com.dowstats.data.dto.controllers.research.ResearchDto
import com.dowstats.data.dto.controllers.research.ResearchShortDto
@@ -32,9 +29,10 @@ data class BuildingFullDto(
var repairMax: Int?,
var icon: String?,
var modId: Long?,
- var addons: Set?,
+ var addons: List?,
var researches: List?,
- val units: Set,
- val weapons: Set?,
+ val units: List,
+ val weapons: Set,
+ val requirements: RequirementDto?,
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 edf535e..806ebe0 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
@@ -6,6 +6,7 @@ import com.dowstats.data.dto.controllers.UnitShortDto
data class RaceBuildings(
val race: RaceDto,
val buildings: List,
+ val buildingsAdvanced: List,
)
data class BuildingShortDto(
@@ -13,7 +14,7 @@ data class BuildingShortDto(
val icon: String,
val id: Long,
val filename: String,
- val units: Set,
+ val units: List,
val armourTypeName: String,
val canDetect: Boolean,
)
\ No newline at end of file
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
index 9509bc0..20b62e7 100644
--- a/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchDto.kt
+++ b/src/main/kotlin/com/dowstats/data/dto/controllers/research/ResearchDto.kt
@@ -15,10 +15,8 @@ data class ResearchDto(
val costTime: Int?,
val modifiers: List,
val requirements: RequirementDto?,
- val affectedUnits: Set,
- val affectedSergeants: Set,
- val affectedBuildings: Set,
- val affectedWeapons: Set,
+ val affectedData: AffectedDataDto,
val icon: String?,
+ val uiIndexHint : Int,
val modId: Long?,
)
\ No newline at end of file
diff --git a/src/main/kotlin/com/dowstats/data/entities/Building.kt b/src/main/kotlin/com/dowstats/data/entities/Building.kt
index 61c1015..691970e 100644
--- a/src/main/kotlin/com/dowstats/data/entities/Building.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/Building.kt
@@ -1,5 +1,7 @@
package com.dowstats.data.entities
+import com.dowstats.data.dto.controllers.RequirementDto
+import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.dowstats.data.dto.controllers.building.BuildingAddonDto
import com.dowstats.data.dto.controllers.building.BuildingFullDto
import com.dowstats.data.dto.controllers.research.ResearchDto
@@ -7,6 +9,7 @@ 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 com.dowstats.data.entities.research.ResearchRequirements
import jakarta.persistence.*
@@ -47,6 +50,8 @@ class Building {
var sightRadius: Int? = null
var detectRadius: Int? = null
var repairMax: Int? = null
+ var uiIndexHint: Int = 0
+ var advancedBuildOption: Boolean = false
var icon: String? = null
var modId: Long? = null
var faithIncome: Double? = null
@@ -77,10 +82,19 @@ class Building {
inverseJoinColumns = [JoinColumn(name = "research_id")])
var affectedResearches: MutableSet = mutableSetOf()
+ @ManyToMany
+ @JoinTable(name = "addon_affected_buildings",
+ joinColumns = [JoinColumn(name = "building_id")],
+ inverseJoinColumns = [JoinColumn(name = "addon_id")])
+ var affectedAddons: MutableSet = mutableSetOf()
+
+ @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL])
+ var buildingRequirements: MutableSet = mutableSetOf()
+
@Transient
var weaponHardpoints: MutableSet = mutableSetOf()
- fun toDto(buildingAddons: Set?, researches: List?): BuildingFullDto =
+ fun toDto(buildingAddons: List?, researches: List?, weapons: Set, requirement: RequirementDto?): BuildingFullDto =
BuildingFullDto(
id!!,
race?.toDto(),
@@ -108,8 +122,9 @@ class Building {
modId!!,
buildingAddons,
researches,
- units?.toList()?.toUnitDto() ?: emptySet(),
- weapons?.map { it.toWeaponSlotDto() }?.toSet(),
+ units?.toList()?.sortedBy { it.uiIndexHint }?.toUnitDto() ?: emptyList(),
+ weapons,
+ requirement,
affectedResearches.map { it.toResearchShortDto() }.toSet(),
)
diff --git a/src/main/kotlin/com/dowstats/data/entities/BuildingRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/BuildingRequirements.kt
new file mode 100644
index 0000000..08554e8
--- /dev/null
+++ b/src/main/kotlin/com/dowstats/data/entities/BuildingRequirements.kt
@@ -0,0 +1,18 @@
+package com.dowstats.data.entities
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+import jakarta.persistence.Entity
+import jakarta.persistence.JoinColumn
+import jakarta.persistence.ManyToOne
+import jakarta.persistence.Table
+
+
+@Entity
+@Table(name = "building_requirements")
+class BuildingRequirements: RequirementBase() {
+
+ @ManyToOne
+ @JoinColumn(name = "building_id", nullable = false)
+ @JsonIgnore
+ var building: Building? = null
+}
diff --git a/src/main/kotlin/com/dowstats/data/entities/BuildingWeapon.kt b/src/main/kotlin/com/dowstats/data/entities/BuildingWeapon.kt
index 92024eb..007686e 100644
--- a/src/main/kotlin/com/dowstats/data/entities/BuildingWeapon.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/BuildingWeapon.kt
@@ -1,5 +1,6 @@
package com.dowstats.data.entities
+import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*
@@ -40,10 +41,10 @@ class BuildingWeapon {
@JoinColumn(name = "weapon_id")
var weapon: Weapon? = null
- fun toWeaponSlotDto() = WeaponSlotDto(
+ fun toWeaponSlotDto(requirementDto: RequirementDto?) = WeaponSlotDto(
buildingWeaponKey!!.hardpoint,
buildingWeaponKey!!.hardpointOrder,
- weapon?.toDto()!!
+ weapon?.toDto(requirementDto)!!
)
}
diff --git a/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt b/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt
index 68a036c..46feee6 100644
--- a/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/DowUnit.kt
@@ -1,7 +1,7 @@
package com.dowstats.data.entities
-import com.dowstats.data.dto.controllers.UnitFullDto
-import com.dowstats.data.dto.controllers.UnitShortDto
+import com.dowstats.data.dto.controllers.*
+import com.dowstats.data.entities.addon.BuildingAddon
import com.dowstats.data.entities.research.Research
import jakarta.persistence.*
@@ -69,6 +69,8 @@ class DowUnit {
var faithIncome: Double? = null
var powerIncome: Double? = null
var requisitionIncome: Double? = null
+ var haveReinforceMenu: Boolean = false
+ var uiIndexHint: Int = 0
var icon: String? = null
var modId: Long? = null
@@ -84,8 +86,16 @@ class DowUnit {
inverseJoinColumns = [JoinColumn(name = "research_id")])
var affectedResearches: MutableSet = mutableSetOf()
+ @ManyToMany
+ @JoinTable(name = "addon_affected_units",
+ joinColumns = [JoinColumn(name = "unit_id")],
+ inverseJoinColumns = [JoinColumn(name = "addon_id")])
+ var affectedAddons: MutableSet = mutableSetOf()
- fun toDto(): UnitFullDto =
+ @OneToMany(mappedBy = "unit", cascade = [CascadeType.ALL])
+ var unitRequirements: MutableSet = mutableSetOf()
+
+ fun toDto(weapons: Set, sergeantsDtos: Set, requirementDto: RequirementDto?): UnitFullDto =
UnitFullDto(
id!!,
race?.toDto(),
@@ -132,20 +142,23 @@ class DowUnit {
maxSergeants,
icon,
modId!!,
- sergeants?.map { it.toDto() }?.toSet(),
- weapons?.map { it.toWeaponSlotDto() }?.toSet(),
+ sergeantsDtos,
+ weapons,
+ haveReinforceMenu,
affectedResearches.map { it.toResearchShortDto() }.toSet(),
+ affectedAddons.map { it.toShortDto() }.toSet(),
+ requirementDto,
)
}
object DowUnitObject {
- fun List.toUnitDto(): Set =
+ fun List.toUnitDto(): List =
this.mapNotNull {
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()
+ }
}
\ 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 2eda976..3ded4f5 100644
--- a/src/main/kotlin/com/dowstats/data/entities/Sergant.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/Sergant.kt
@@ -1,7 +1,10 @@
package com.dowstats.data.entities
+import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.SergeantDto
+import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.dowstats.data.entities.Weapon.HardpointPosition
+import com.dowstats.data.entities.addon.BuildingAddon
import com.dowstats.data.entities.research.Research
import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*
@@ -65,7 +68,16 @@ class Sergeant {
inverseJoinColumns = [JoinColumn(name = "research_id")])
var affectedResearches: MutableSet = mutableSetOf()
- fun toDto(): SergeantDto =
+ @ManyToMany
+ @JoinTable(name = "addon_affected_sergeants",
+ joinColumns = [JoinColumn(name = "sergeant_id")],
+ inverseJoinColumns = [JoinColumn(name = "addon_id")])
+ var affectedAddons: MutableSet = mutableSetOf()
+
+ @OneToMany(mappedBy = "sergeant", cascade = [CascadeType.ALL])
+ var sergeantRequirements: MutableSet = mutableSetOf()
+
+ fun toDto(weapons: Set, requirements: RequirementDto?,): SergeantDto =
SergeantDto(
id!!,
armorType?.toDto(),
@@ -91,7 +103,8 @@ class Sergeant {
sightRadius,
detectRadius,
icon,
- weapons?.map { it.toWeaponSlotDto() },
- affectedResearches.map { it.toResearchShortDto() }.toSet()
+ weapons.toList(),
+ affectedResearches.map { it.toResearchShortDto() }.toSet(),
+ requirements
)
}
diff --git a/src/main/kotlin/com/dowstats/data/entities/SergantWeapon.kt b/src/main/kotlin/com/dowstats/data/entities/SergantWeapon.kt
index 48ecec7..bc19453 100644
--- a/src/main/kotlin/com/dowstats/data/entities/SergantWeapon.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/SergantWeapon.kt
@@ -1,5 +1,6 @@
package com.dowstats.data.entities
+import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.fasterxml.jackson.annotation.JsonIgnore
import java.io.Serializable
@@ -40,9 +41,9 @@ class SergeantWeapon {
@JoinColumn(name = "weapon_id")
var weapon: Weapon? = null
- fun toWeaponSlotDto() = WeaponSlotDto(
+ fun toWeaponSlotDto(requirement: RequirementDto?) = WeaponSlotDto(
sergeantWeaponKey!!.hardpoint,
sergeantWeaponKey!!.hardpointOrder,
- weapon?.toDto()!!
+ weapon?.toDto(requirement)!!
)
}
diff --git a/src/main/kotlin/com/dowstats/data/entities/SergeantRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/SergeantRequirements.kt
new file mode 100644
index 0000000..2809d70
--- /dev/null
+++ b/src/main/kotlin/com/dowstats/data/entities/SergeantRequirements.kt
@@ -0,0 +1,18 @@
+package com.dowstats.data.entities
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+import jakarta.persistence.Entity
+import jakarta.persistence.JoinColumn
+import jakarta.persistence.ManyToOne
+import jakarta.persistence.Table
+
+
+@Entity
+@Table(name = "sergeant_requirements")
+class SergeantRequirements: RequirementBase() {
+
+ @ManyToOne
+ @JoinColumn(name = "sergeant_id", nullable = false)
+ @JsonIgnore
+ var sergeant: Sergeant? = null
+}
diff --git a/src/main/kotlin/com/dowstats/data/entities/UnitRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/UnitRequirements.kt
new file mode 100644
index 0000000..e3a80e4
--- /dev/null
+++ b/src/main/kotlin/com/dowstats/data/entities/UnitRequirements.kt
@@ -0,0 +1,18 @@
+package com.dowstats.data.entities
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+import jakarta.persistence.Entity
+import jakarta.persistence.JoinColumn
+import jakarta.persistence.ManyToOne
+import jakarta.persistence.Table
+
+
+@Entity
+@Table(name = "unit_requirements")
+class UnitRequirements: RequirementBase() {
+
+ @ManyToOne
+ @JoinColumn(name = "unit_id", nullable = false)
+ @JsonIgnore
+ var unit: DowUnit? = null
+}
diff --git a/src/main/kotlin/com/dowstats/data/entities/UnitWeapon.kt b/src/main/kotlin/com/dowstats/data/entities/UnitWeapon.kt
index bfe15c9..b4e709b 100644
--- a/src/main/kotlin/com/dowstats/data/entities/UnitWeapon.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/UnitWeapon.kt
@@ -1,5 +1,6 @@
package com.dowstats.data.entities
+import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.WeaponSlotDto
import com.fasterxml.jackson.annotation.JsonIgnore
import java.io.Serializable
@@ -41,10 +42,10 @@ class UnitWeapon {
@JoinColumn(name = "weapon_id")
var weapon: Weapon? = null
- fun toWeaponSlotDto() = WeaponSlotDto(
+ fun toWeaponSlotDto(requirement: RequirementDto?) = WeaponSlotDto(
unitWeaponKey!!.hardpoint,
unitWeaponKey!!.hardpointOrder,
- weapon?.toDto()!!
+ weapon?.toDto(requirement)!!
)
}
diff --git a/src/main/kotlin/com/dowstats/data/entities/Weapon.kt b/src/main/kotlin/com/dowstats/data/entities/Weapon.kt
index 2c2b4bd..9b94087 100644
--- a/src/main/kotlin/com/dowstats/data/entities/Weapon.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/Weapon.kt
@@ -1,6 +1,8 @@
package com.dowstats.data.entities
+import com.dowstats.data.dto.controllers.RequirementDto
import com.dowstats.data.dto.controllers.WeaponDto
+import com.dowstats.data.entities.addon.BuildingAddon
import com.dowstats.data.entities.research.Research
import jakarta.persistence.*
@@ -35,7 +37,7 @@ class Weapon {
var canAttackAir: Boolean = true
var canAttackGround: Boolean = true
var icon: String? = null
- var haveEquipButton: Boolean = true
+ var showInReinforce: Boolean = true
var modId: Long? = null
@ManyToMany
@@ -44,6 +46,12 @@ class Weapon {
inverseJoinColumns = [JoinColumn(name = "research_id")])
var affectedResearches: MutableSet = mutableSetOf()
+ @ManyToMany
+ @JoinTable(name = "addon_affected_weapons",
+ joinColumns = [JoinColumn(name = "weapon_id")],
+ inverseJoinColumns = [JoinColumn(name = "addon_id")])
+ var affectedAddons: MutableSet = mutableSetOf()
+
@OneToMany(mappedBy = "weapon", cascade = [CascadeType.ALL])
var unitsUse: MutableSet? = null
@@ -56,11 +64,14 @@ class Weapon {
// for many-to-many persistance
data class HardpointPosition(val weaponId: Long, val hardpoint: Int, val order: Int)
+ @OneToMany(mappedBy = "weapon", cascade = [CascadeType.ALL])
+ var weaponRequirements: MutableSet = mutableSetOf()
- @OneToMany(mappedBy="weapon", fetch = FetchType.EAGER, cascade = [(CascadeType.ALL)])
+
+ @OneToMany(mappedBy="weapon", cascade = [(CascadeType.ALL)])
var weaponPiercings: List = listOf()
- fun toDto() = WeaponDto(
+ fun toDto(requirementDto: RequirementDto?) = WeaponDto(
id!!,
filename!!,
name,
@@ -85,9 +96,11 @@ class Weapon {
canAttackAir,
canAttackGround,
icon,
- haveEquipButton,
+ showInReinforce,
modId,
weaponPiercings.map { it.toDto() },
affectedResearches.map { it.toResearchShortDto() }.toSet(),
+ affectedAddons.map { it.toShortDto() }.toSet(),
+ requirementDto,
)
}
diff --git a/src/main/kotlin/com/dowstats/data/entities/WeaponDamage.kt b/src/main/kotlin/com/dowstats/data/entities/WeaponDamage.kt
index befeb64..651bf67 100644
--- a/src/main/kotlin/com/dowstats/data/entities/WeaponDamage.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/WeaponDamage.kt
@@ -14,12 +14,12 @@ class WeaponArmorPiercing {
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null
- @ManyToOne(fetch = FetchType.EAGER)
+ @ManyToOne
@JsonIgnore
@JoinColumn(name = "weapon_id")
var weapon: Weapon? = null
- @ManyToOne(fetch = FetchType.EAGER)
+ @ManyToOne
@JoinColumn(name = "armor_type_id")
var armorType: ArmorType? = null
diff --git a/src/main/kotlin/com/dowstats/data/entities/WeaponRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/WeaponRequirements.kt
new file mode 100644
index 0000000..3404ee6
--- /dev/null
+++ b/src/main/kotlin/com/dowstats/data/entities/WeaponRequirements.kt
@@ -0,0 +1,18 @@
+package com.dowstats.data.entities
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+import jakarta.persistence.Entity
+import jakarta.persistence.JoinColumn
+import jakarta.persistence.ManyToOne
+import jakarta.persistence.Table
+
+
+@Entity
+@Table(name = "weapon_requirements")
+class WeaponRequirements: RequirementBase() {
+
+ @ManyToOne
+ @JoinColumn(name = "weapon_id", nullable = false)
+ @JsonIgnore
+ var weapon: Weapon? = null
+}
diff --git a/src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt b/src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt
index ceca423..1855dd4 100644
--- a/src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/addon/AddonModifiers.kt
@@ -19,6 +19,7 @@ class AddonModifiers {
var addon: BuildingAddon? = null
var reference: String? = null
+ var target: String? = null
var usageType: String? = null
var value: Double? = null
@@ -28,6 +29,7 @@ class AddonModifiers {
reference = reference,
usageType = usageType,
value = value,
+ target = target,
)
}
}
diff --git a/src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt b/src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt
index b4beeeb..092f89c 100644
--- a/src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/addon/BuildingAddon.kt
@@ -1,9 +1,17 @@
package com.dowstats.data.entities.addon
+import com.dowstats.data.dto.controllers.AffectedDataDto
+import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto
import com.dowstats.data.dto.controllers.RequirementDto
+import com.dowstats.data.dto.controllers.SergeantUnitShortDto
+import com.dowstats.data.dto.controllers.SergeantUnitShortDtoObject.toShortDtoSet
+import com.dowstats.data.dto.controllers.WeaponUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.building.BuildingAddonDto
import com.dowstats.data.dto.controllers.building.BuildingAddonShortDto
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 com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*
@@ -32,11 +40,36 @@ class BuildingAddon {
var addonCostTime: Int? = null
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
- var addonModifiers: MutableSet? = null
+ var addonModifiers: MutableSet = mutableSetOf()
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
var addonRequirements: MutableSet? = null
+ @ManyToMany
+ @JoinTable(name = "addon_affected_units",
+ joinColumns = [JoinColumn(name = "addon_id")],
+ inverseJoinColumns = [JoinColumn(name = "unit_id")])
+ var affectedUnits: MutableSet = mutableSetOf()
+
+ @ManyToMany
+ @JoinTable(name = "addon_affected_sergeants",
+ joinColumns = [JoinColumn(name = "addon_id")],
+ inverseJoinColumns = [JoinColumn(name = "sergeant_id")])
+ var affectedSergeants: MutableSet = mutableSetOf()
+
+ @ManyToMany
+ @JoinTable(name = "addon_affected_buildings",
+ joinColumns = [JoinColumn(name = "addon_id")],
+ inverseJoinColumns = [JoinColumn(name = "building_id")])
+ var affectedBuildings: MutableSet = mutableSetOf()
+
+ @ManyToMany
+ @JoinTable(name = "addon_affected_weapons",
+ joinColumns = [JoinColumn(name = "addon_id")],
+ inverseJoinColumns = [JoinColumn(name = "weapon_id")])
+ var affectedWeapons: MutableSet = mutableSetOf()
+
+ var uiIndexHint: Int = 0
var icon: String? = null
var modId: Long? = null
@@ -52,6 +85,12 @@ class BuildingAddon {
addonCostSouls = addonCostSouls,
addonCostTime = addonCostTime,
addonModifiers = addonModifiers?.sortedBy { it.reference }?.map { it.toDto() }?.toSet() ?: emptySet(),
+ affectedData = AffectedDataDto(
+ affectedUnits.map { it.compressDto() }.toSet(),
+ affectedSergeants.toShortDtoSet(),
+ affectedBuildings.map { it.compressDto() }.toSet(),
+ affectedWeapons.toShortDtoSet(),
+ ),
addonRequirement = addonRequirementDto,
icon = icon
)
diff --git a/src/main/kotlin/com/dowstats/data/entities/research/Research.kt b/src/main/kotlin/com/dowstats/data/entities/research/Research.kt
index 2098a60..31f34eb 100644
--- a/src/main/kotlin/com/dowstats/data/entities/research/Research.kt
+++ b/src/main/kotlin/com/dowstats/data/entities/research/Research.kt
@@ -1,10 +1,11 @@
package com.dowstats.data.entities.research
+import com.dowstats.data.dto.controllers.AffectedDataDto
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.SergeantUnitShortDtoObject.toShortDtoSet
+import com.dowstats.data.dto.controllers.WeaponUnitShortDtoObject.toShortDtoSet
import com.dowstats.data.dto.controllers.research.ResearchDto
import com.dowstats.data.dto.controllers.research.ResearchShortDto
import com.dowstats.data.entities.Building
@@ -30,6 +31,7 @@ class Research {
var costFaith: Double? = null
var costSouls: Double? = null
var costTime: Int? = null
+ var uiIndexHint: Int = 0
var icon: String? = null
var modId: Long? = null
@@ -37,7 +39,7 @@ class Research {
var researchModifiers: MutableSet = mutableSetOf()
@OneToMany(mappedBy = "research", cascade = [CascadeType.ALL])
- var addonRequirements: MutableSet = mutableSetOf()
+ var researchRequirements: MutableSet = mutableSetOf()
@ManyToMany
@JoinTable(name = "researches_affected_units",
@@ -80,6 +82,7 @@ class Research {
id = id!!,
name = name,
icon = icon,
+ uiIndexHint = uiIndexHint,
filename = filename,
description = description,
costRequisition = costRequisition,
@@ -97,41 +100,12 @@ class Research {
)
}.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(),
+ affectedData = AffectedDataDto(
+ affectedUnits.map { it.compressDto() }.toSet(),
+ affectedSergeants.toShortDtoSet(),
+ affectedBuildings.map { it.compressDto() }.toSet(),
+ affectedWeapons.toShortDtoSet(),
+ ),
modId = modId,
)
-
}
diff --git a/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt
index fd60691..5ee7d6c 100644
--- a/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt
+++ b/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt
@@ -1,8 +1,10 @@
package com.dowstats.data.repositories
import com.dowstats.data.entities.addon.BuildingAddon
+import com.dowstats.data.entities.research.Research
import org.springframework.data.repository.CrudRepository
interface AddonRepository : CrudRepository{
+ fun findAllByModId(modId: Long): List
fun findFirstByModIdAndFilename(modId: Long, fileName: String): BuildingAddon?
}
\ 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
index 0c8aa74..d108151 100644
--- a/src/main/kotlin/com/dowstats/service/datamaps/CommonMapping.kt
+++ b/src/main/kotlin/com/dowstats/service/datamaps/CommonMapping.kt
@@ -7,18 +7,20 @@ 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
- )
- }
+ .sortedBy { it.uiIndexHint }
+ .mapNotNull {it.toBuildingShortDto() }
+
+ fun Building.toBuildingShortDto(): BuildingShortDto? {
+ val name = this.name ?: this.filename?.replace(".rgd", "")?.replace("_", " ")
+ val icon = this.icon
+ return if (name == null || icon == null) null else BuildingShortDto(
+ name, icon, this.id!!,
+ this.filename!!,
+ this.units?.toList()?.sortedBy { it.uiIndexHint }?.toUnitDto() ?: emptyList(),
+ this.armorType?.name!!,
+ (this.detectRadius ?: 0) > 0,
+ )
+ }
fun isNotCompanyEntity(fileName: String): Boolean =
!fileName.contains("_dxp3.") &&
diff --git a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt
index 6b14acd..7eef4f4 100644
--- a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt
+++ b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt
@@ -6,7 +6,6 @@ import com.dowstats.data.dto.controllers.building.RaceBuildings
import com.dowstats.data.entities.Building
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
@@ -19,20 +18,23 @@ class DowBuildingMappingService @Autowired constructor(
) {
fun findBuildingsByMod(modId: Long): List {
- return getAllBuildings(modId).groupBy { it.race }.mapNotNull { raceUnits ->
- RaceBuildings(raceUnits.key?.toDto() ?: throw Exception("Race is null"), raceUnits.value.toBuildingShortDto())
+ return getAllBuildings(modId).groupBy { it.race }.mapNotNull { raceBuildings ->
+ RaceBuildings(raceBuildings.key?.toDto() ?: throw Exception("Race is null"),
+ raceBuildings.value.filter { !it.advancedBuildOption }.toBuildingShortDto(),
+ raceBuildings.value.filter { it.advancedBuildOption }.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.toBuildingShortDto())
+ return RaceBuildings(raceEntity.toDto(), buildings.filter { !it.advancedBuildOption }.toBuildingShortDto(),
+ buildings.filter { it.advancedBuildOption }.toBuildingShortDto())
}
fun mapToDto(building: Building): BuildingFullDto {
- val buildingAddons = building.addons?.map { addon ->
+ val buildingAddons = building.addons?.sortedBy { it.uiIndexHint }?.map { addon ->
val replaceWhenDone = addon.addonRequirements?.find { it.reference == Requirements.REFERENCE_REQUIREMENT_ADDON }?.replaceWhenDone ?: false
val requirement = requirementsMappingComponent
@@ -45,18 +47,27 @@ class DowBuildingMappingService @Autowired constructor(
replaceWhenDone = replaceWhenDone,
requirementBuildings = requirement.requirementBuildings.filter { it.id != building.id }.toSet())
)
- }?.sortedBy { it.name }?.toSet()
+ }
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 }
+ val requirements = requirementsMappingComponent
+ .getRequirements(research.researchRequirements.toList() ?: emptyList(),
+ building.modId!!)
+ research.toResearchDto(requirements)
+ }?.sortedBy { it.uiIndexHint }
- return building.toDto(buildingAddons, researches)
+ val requirementDto = requirementsMappingComponent
+ .getRequirements(building.buildingRequirements.toList(),
+ building.modId!!)
+
+ val weapons = building.weapons?.map { buildingWeapon ->
+ val requirements = requirementsMappingComponent
+ .getRequirements(buildingWeapon.weapon?.weaponRequirements?.toList() ?: emptyList(),
+ building.modId!!)
+ buildingWeapon.toWeaponSlotDto(requirements)
+ }?.toSet() ?: emptySet()
+
+ return building.toDto(buildingAddons, researches, weapons, requirementDto)
}
diff --git a/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt b/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt
index 9f51043..309e56b 100644
--- a/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt
+++ b/src/main/kotlin/com/dowstats/service/datamaps/DowUnitMappingService.kt
@@ -1,9 +1,12 @@
package com.dowstats.service.datamaps
import com.dowstats.data.dto.controllers.RaceUnits
+import com.dowstats.data.dto.controllers.SergeantDto
+import com.dowstats.data.dto.controllers.UnitFullDto
import com.dowstats.data.entities.DowUnit
import com.dowstats.data.entities.DowUnitObject.toUnitDto
import com.dowstats.data.entities.Race
+import com.dowstats.data.entities.Sergeant
import com.dowstats.data.repositories.RaceRepository
import com.dowstats.data.repositories.UnitRepository
import org.springframework.beans.factory.annotation.Autowired
@@ -12,7 +15,8 @@ import org.springframework.stereotype.Service
@Service
class DowUnitMappingService @Autowired constructor(
val unitRepository: UnitRepository,
- val raceRepository: RaceRepository
+ val raceRepository: RaceRepository,
+ val requirementsMappingComponent: RequirementsMappingComponent,
) {
fun findUnitsByMod(modId: Long): List {
@@ -22,12 +26,51 @@ class DowUnitMappingService @Autowired constructor(
}
}
+ fun getUnitFullDto(unitId: Long): UnitFullDto {
+ val unit = unitRepository.findById(unitId).get()
+ val requirementDto = requirementsMappingComponent
+ .getRequirements(unit.unitRequirements.toList(),
+ unit.modId!!,
+ )
+
+ val weapons = unit.weapons?.map { unitWeapon ->
+ val requirements = requirementsMappingComponent
+ .getRequirements(unitWeapon.weapon?.weaponRequirements?.toList() ?: emptyList(),
+ unit.modId!!,
+ )
+ unitWeapon.toWeaponSlotDto(requirements)
+ }?.toSet() ?: emptySet()
+
+ return unitRepository.findById(unitId).get().toDto(
+ weapons,
+ unit.sergeants?.map { getSergeantFullDto(it) }?.toSet() ?: emptySet(),
+ requirementDto
+ )
+ }
+
fun findUnitsByModAndRace(modId: Long, race: String): RaceUnits {
val units = getAllUnits(modId, race)
val raceEntity = race.let{ raceRepository.findById(race) ?: throw Exception("Race $race not found") }
return toRaceUnitsDto(units, raceEntity)
}
+ private fun getSergeantFullDto(sergeant: Sergeant): SergeantDto {
+ val requirementDto = requirementsMappingComponent
+ .getRequirements(sergeant.sergeantRequirements.toList(),
+ sergeant.modId!!,
+ )
+
+ val weapons = sergeant.weapons?.map { sergeantWeapon ->
+ val requirements = requirementsMappingComponent
+ .getRequirements(sergeantWeapon.weapon?.weaponRequirements?.toList() ?: emptyList(),
+ sergeant.modId!!,
+ )
+ sergeantWeapon.toWeaponSlotDto(requirements)
+ }?.toSet() ?: emptySet()
+
+ return sergeant.toDto(weapons, requirementDto)
+ }
+
private fun toRaceUnitsDto(units: List, race: Race): RaceUnits {
val infantry = units
.filter { it.capInfantry?.let { it > 0 } ?: false || it.reinforceCostPopulation?.let { it > 0 } ?: false }
diff --git a/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt b/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt
index bc9b12f..13d26d9 100644
--- a/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt
+++ b/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt
@@ -2,6 +2,7 @@ package com.dowstats.service.datamaps
import com.dowstats.Metadata.Requirements
import com.dowstats.data.dto.controllers.RequirementDto
+import com.dowstats.data.dto.controllers.RequirementLimitByBuildingDto
import com.dowstats.data.dto.controllers.RequirementResearchDto
import com.dowstats.data.entities.RequirementBase
import com.dowstats.data.entities.addon.BuildingAddon
@@ -23,11 +24,22 @@ class RequirementsMappingComponent(
requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble()
?.toInt()
+ val requiredOwnership =
+ requirements.filter { it.reference == Requirements.REFERENCE_REQUIREMENT_OWNERSHIP }
+ .mapNotNull { rro ->
+ rro.value
+ }.toSet()
+
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 addonFileName = it.split("\\").last().replace(".lua", ".rgd")
+ addonFileName.let {
+ addonRepository.findFirstByModIdAndFilename(
+ modId,
+ it.split("\\").last().replace(".lua", ".rgd")
+ )?.toShortDto()
+ }
+ }
val requirementAddonGlobal =
requirements.filter { it.reference == Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON }
@@ -49,6 +61,20 @@ class RequirementsMappingComponent(
}
}.distinct().toBuildingShortDto().toSet()
+ val limitByBuilding = requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_RATIO }?.let {
+ val buildingFileName = it.value?.split(";")?.first()?.replace(".lua", ".rgd")
+ val limitPerBuilding = it.value?.split(";")?.last()?.toInt() ?: 0
+
+ buildingFileName
+ ?.let {buildingRepository.findByModIdAndFilename(modId, it.split("\\").last().replace(".lua", ".rgd"))?.toBuildingShortDto()}
+ ?.let {
+ RequirementLimitByBuildingDto(
+ it,
+ limitPerBuilding
+ )
+ }
+ }
+
val requirementBuildingsEither =
requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let {
it.value?.split(";")?.mapNotNull { bPath ->
@@ -87,7 +113,9 @@ class RequirementsMappingComponent(
requirementResearches,
requirementAddon,
requirementAddonGlobal,
- requireCap
+ requireCap,
+ limitByBuilding,
+ requiredOwnership
)
} else null
}
diff --git a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt
index c98918b..eaa4cf8 100644
--- a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt
+++ b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt
@@ -69,6 +69,7 @@ class ModStorageIntegrationService(
it.name = "Dowstats balance mod"
it.technicalName = toSave.technicalName
})
+ convertAllToLowercase(savedMod)
modParserService.parseModFilesAndSaveToDb(savedMod)
} catch (e: Exception) {
log.error("Error while download and extract mod", e)
@@ -94,6 +95,7 @@ class ModStorageIntegrationService(
val mod = modRepository.findById(modId).orElseThrow { IllegalArgumentException("Mod not found") }
modRepository.clearModData(modId)
checkSgaAndExtract(mod)
+ convertAllToLowercase(mod)
modParserService.parseModFilesAndSaveToDb(mod)
}
@@ -141,6 +143,44 @@ class ModStorageIntegrationService(
}
}
+ private fun convertAllToLowercase(mod: Mod){
+ val iconDirectory = "${storageConfig.modStorage.replace("/", File.separator)}${File.separator}${mod.technicalName}${mod.version}${File.separator}Data${File.separator}art${File.separator}ui${File.separator}ingame"
+ File(iconDirectory).listFiles()?.forEach { raceIconDirectory ->
+ raceIconDirectory.listFiles()?.forEach { iconFile ->
+ if(iconFile.name != iconFile.name.lowercase()){
+ iconFile.renameTo(File( raceIconDirectory.path + File.separator + iconFile.name.lowercase()))
+ }
+ }
+ }
+
+ val attribDirectory = "${storageConfig.modStorage.replace("/", File.separator)}${File.separator}${mod.technicalName}${mod.version}${File.separator}Data${File.separator}attrib"
+ File(attribDirectory).listFiles()?.forEach { attribFolder ->
+ attribFolder.listFiles()?.forEach { attribFile ->
+ if(attribFile.name != attribFile.name.lowercase()){
+ attribFile.renameTo(File( attribFolder.path + File.separator + attribFile.name.lowercase()))
+ }
+ }
+ }
+ val spbsDirectory = "${storageConfig.modStorage.replace("/", File.separator)}${File.separator}${mod.technicalName}${mod.version}${File.separator}Data${File.separator}attrib${File.separator}sbps${File.separator}races"
+ File(spbsDirectory).listFiles()?.forEach { raceFolder ->
+ raceFolder.listFiles()?.forEach { spbsFile ->
+ if(spbsFile.name != spbsFile.name.lowercase()){
+ spbsFile.renameTo(File( raceFolder.path + File.separator + spbsFile.name.lowercase()))
+ }
+ }
+ }
+ val ebpsDirectory = "${storageConfig.modStorage.replace("/", File.separator)}${File.separator}${mod.technicalName}${mod.version}${File.separator}Data${File.separator}attrib${File.separator}ebps${File.separator}races"
+ File(ebpsDirectory).listFiles()?.forEach { raceFolder ->
+ raceFolder.listFiles()?.forEach { typeFolder ->
+ typeFolder.listFiles()?.forEach { ebpsFile ->
+ if(ebpsFile.name != ebpsFile.name.lowercase()){
+ ebpsFile.renameTo(File( raceFolder.path + File.separator + ebpsFile.name.lowercase()))
+ }
+ }
+ }
+ }
+ }
+
private fun downloadAndExtractMod(modTechName: String, version: String) {
log.info("Downloading mod $modTechName")
val urlString = "http://crosspick.ru/dow_stats_client/dow_stats_balance_mod/$modTechName.zip"
diff --git a/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt b/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt
index ea73ef3..0b857dd 100644
--- a/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt
+++ b/src/main/kotlin/com/dowstats/service/postparsing/PostParsingService.kt
@@ -2,6 +2,7 @@ package com.dowstats.service.postparsing
import com.dowstats.configuration.StorageConfig
import com.dowstats.data.entities.*
+import com.dowstats.data.entities.addon.BuildingAddon
import com.dowstats.data.entities.research.Research
import com.dowstats.data.repositories.*
import org.slf4j.LoggerFactory
@@ -17,6 +18,7 @@ import kotlin.io.path.exists
@Service
class PostParsingService @Autowired constructor(
val researchRepository: ResearchRepository,
+ val addonRepository: AddonRepository,
val unitRepository: UnitRepository,
val sergeantRepository: SergeantRepository,
val buildingRepository: BuildingRepository,
@@ -29,6 +31,7 @@ class PostParsingService @Autowired constructor(
try {
val modId = mod.id!!
val researches = researchRepository.findAllByModId(modId)
+ val addons = addonRepository.findAllByModId(modId)
val units = unitRepository.findByModIdAndRace(modId, null)
val sergeants = sergeantRepository.findAllByModId(modId)
val buildings = buildingRepository.findByModIdAndRace(modId, null)
@@ -39,6 +42,11 @@ class PostParsingService @Autowired constructor(
bindResearchBuildings(buildings, researches)
bindResearchWeapons(weapons, researches)
+ bindAddonUnits(units, addons)
+ bindAddonSergeants(sergeants, addons)
+ bindAddonBuildings(buildings, addons)
+ bindAddonWeapons(weapons, addons)
+
} catch (e: Exception) {
log.warn("Error occurred during bind researches", e)
}
@@ -104,4 +112,64 @@ class PostParsingService @Autowired constructor(
weaponRepository.saveAll(weaponsWithBindings)
log.info("Successfully bind researches to weapons")
}
+
+ private fun bindAddonUnits(units: List, addons: List) {
+
+ val unitsWithBindings: List = addons.flatMap { addon ->
+ addon.addonModifiers.mapNotNull { modifier ->
+ units.find {
+ it.filenameSquad?.replace(".rgd", "") == modifier.target ||
+ it.filenameUnit?.replace(".rgd", "") == modifier.target
+ }
+ ?.let {
+ it.affectedAddons.add(addon)
+ it
+ }
+ }
+ }
+ unitRepository.saveAll(unitsWithBindings)
+ log.info("Successfully bind addons to units")
+ }
+
+ private fun bindAddonSergeants(sergeants: List, addons: List) {
+
+ val sergeantsWithBindings: List = addons.flatMap { addon ->
+ addon.addonModifiers.mapNotNull { modifier ->
+ sergeants.find { it.filename.replace(".rgd", "") == modifier.target }?.let {
+ it.affectedAddons.add(addon)
+ it
+ }
+ }
+ }
+ sergeantRepository.saveAll(sergeantsWithBindings)
+ log.info("Successfully bind addons to sergeants")
+ }
+
+ private fun bindAddonBuildings(buildings: List, addons: List) {
+
+ val buildingsWithBindings: List = addons.flatMap { addon ->
+ addon.addonModifiers.mapNotNull { modifier ->
+ buildings.find { it.filename?.replace(".rgd", "") == modifier.target }?.let {
+ it.affectedAddons.add(addon)
+ it
+ }
+ }
+ }
+ buildingRepository.saveAll(buildingsWithBindings)
+ log.info("Successfully bind addons to buildings")
+ }
+
+ private fun bindAddonWeapons(weapons: List, addons: List) {
+
+ val weaponsWithBindings: List = addons.flatMap { addon ->
+ addon.addonModifiers.mapNotNull { modifier ->
+ weapons.find { it.filename?.replace(".rgd", "") == modifier.target }?.let {
+ it.affectedAddons.add(addon)
+ it
+ }
+ }
+ }
+ weaponRepository.saveAll(weaponsWithBindings)
+ log.info("Successfully bind addons 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 9443cff..b88a299 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt
@@ -1,5 +1,6 @@
package com.dowstats.service.w40k
+import com.dowstats.Metadata
import com.dowstats.data.entities.*
import com.dowstats.data.entities.addon.AddonModifiers
import com.dowstats.data.entities.addon.AddonRequirements
@@ -7,6 +8,7 @@ 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
+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
@@ -35,6 +37,7 @@ class BuildingAddonRgdExtractService @Autowired constructor(
val uiInfo = commonParseRgdService.getUiInfo(uiInfoRgd, modDictionary, modFolderData, mod, log)
addon.name = uiInfo.name
addon.description = uiInfo.description
+ addon.uiIndexHint = addonRgdData.getIntByName("ui_index_hint") ?: 0
addon.icon = uiInfo.iconPath
addon.filename = fileName
@@ -62,6 +65,7 @@ class BuildingAddonRgdExtractService @Autowired constructor(
AddonModifiers().also {
it.addon = addon
it.reference = mTable.getStringByName("\$REF")
+ it.target = mTable.getStringByName("target_type_name")
it.usageType = mTable.getRgdTableByName("usage_type")?.getStringByName("\$REF")
it.value = mTable.getDoubleByName("value")
}
@@ -75,7 +79,7 @@ class BuildingAddonRgdExtractService @Autowired constructor(
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 {
+ if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else {
AddonRequirements().also {
it.addon = addon
it.reference = rTable.getStringByName("\$REF")
diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt
index a83ebd6..39c90a3 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt
@@ -1,9 +1,11 @@
package com.dowstats.service.w40k
+import com.dowstats.Metadata
import com.dowstats.data.dto.BuildingDataToSave
import com.dowstats.data.entities.*
import com.dowstats.data.entities.research.Research
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
@@ -61,6 +63,8 @@ class BuildingRgdExtractService @Autowired constructor(
building.name = buildingUiData.name
building.description = buildingUiData.description
building.icon = buildingUiData.iconPath
+ building.uiIndexHint = buildingData.getRgdTableByName("ui_ext")?.getIntByName("ui_index_hint") ?: 0
+ building.advancedBuildOption = buildingData.getRgdTableByName("structure_buildable_ext")?.getBooleanByName("advanced_build_option") ?: false
val buildCost = commonParseRgdService.getBuildCost(buildingData.getRgdTableByName("cost_ext")?.getRgdTableByName("time_cost"))
building.buildCostRequisition = buildCost.requisition
@@ -89,6 +93,8 @@ class BuildingRgdExtractService @Autowired constructor(
building.units = getUnits(buildingData, units).toMutableSet()
building.researches = getResearches(buildingData, researches).toMutableSet()
+ building.buildingRequirements = getBuildingRequirements(building, buildingData).toMutableSet()
+
val addons = getAddons(buildingData)
building.addons = addons?.mapNotNull {addonFileName ->
val addonRgdData = addonsRgdData[addonFileName]
@@ -202,4 +208,20 @@ class BuildingRgdExtractService @Autowired constructor(
} else null
} ?: emptyList()
}
+
+ private fun getBuildingRequirements(building: Building, buildingData: List): List {
+ val requirements = buildingData.getRgdTableByName("requirement_ext")?.getRgdTableByName("requirements")
+ return requirements?.mapNotNull { r ->
+ if (r.name.contains("required_")) {
+ val rTable = r.value as List
+ if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else {
+ BuildingRequirements().also {
+ it.building = building
+ it.reference = rTable.getStringByName("\$REF")
+ it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, building.filename!!, log)
+ }
+ }
+ } 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
index e2ed2c4..de40d8b 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt
@@ -9,6 +9,7 @@ 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.getIntByName
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
import org.slf4j.Logger
@@ -26,13 +27,17 @@ class CommonParseRgdService @Autowired constructor(
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_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"
- )
+ Requirements.REFERENCE_REQUIREMENT_RESEARCH -> rTable.getStringByName("research_name") + ";" +
+ rTable.getBooleanByName("research_must_not_be_complete")
+ Requirements.REFERENCE_REQUIREMENT_OWNERSHIP -> rTable.getStringByName("own_name")
+ Requirements.REFERENCE_REQUIREMENT_CAP -> rTable.getIntByName("max_cap").toString()
+ Requirements.REFERENCE_REQUIREMENT_SQUAD_CAP -> rTable.getIntByName("max_squad_cap").toString()
+ Requirements.REFERENCE_REQUIREMENT_CUM_SQUAD_CAP -> rTable.getIntByName("max_cumulative_squad_cap").toString()
+ Requirements.REFERENCE_REQUIREMENT_STRUCTURE_RATIO -> rTable.getStringByName("required_structure_name") + ";" +
+ rTable.getIntByName("this_structure_count").toString()
else -> {
log.warn("Unknown requirement reference $ref at $fileName")
null
@@ -64,7 +69,7 @@ class CommonParseRgdService @Autowired constructor(
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 name = nameRef?.let { try { modDictionary[it.toInt()] } catch (e: Exception) { it } }
val descriptionRefs = uiInfoRgdData.getRgdTableByName("help_text_list")
?.mapNotNull{try {
@@ -77,7 +82,7 @@ class CommonParseRgdService @Autowired constructor(
?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } }
val description = try {
- descriptionRefs?.map { try { modDictionary[it.toInt()] } catch (e: Exception) { "" } }?.joinToString ( "\n" )
+ descriptionRefs?.map { try { modDictionary[it.toInt()] } catch (e: Exception) { it } }?.joinToString ( "\n" )
} catch(e:Exception) {
log.warn("Error parsing ui description weapon $name", e)
null
@@ -89,7 +94,7 @@ class CommonParseRgdService @Autowired constructor(
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)
+ log.error("Error parsing ui icon path for $name", e)
null
}
diff --git a/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt b/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt
index bf03ccf..cf5c374 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/IconsService.kt
@@ -6,9 +6,7 @@ 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
@@ -22,19 +20,29 @@ class IconsService @Autowired constructor(
* @param pathToTgaIcon - путь до иконки
* @return путь до сконвертированной иконки
*/
- fun convertTgaToJpegImage(iconPathInMod: String, pathToTgaIcon: String, modName: String? = null): String? {
+ fun convertTgaToJpegImage(iconPathInMod: String, pathToTgaIcon: String, modName: String? = null, convertHere: Boolean = false): String? {
try{
val image: BufferedImage = if(File(pathToTgaIcon).exists()) {
- ImageIO.read(File(pathToTgaIcon))
+ try {
+ ImageIO.read(File(pathToTgaIcon))
+ } catch (e: NoClassDefFoundError) {
+ log.warn("Can't convert icon $iconPathInMod", e)
+ return null
+ }
+
} else if (File(pathToTgaIcon.lowercase()).exists()) {
ImageIO.read(File(pathToTgaIcon.lowercase()))
} else return null
val modFolder = modName?.let { "${File.separator}$modName" } ?: ""
- val pathToSave = "${storageConfig.iconsStorage.replace("/", File.separator)}$modFolder" +
- "${File.separator}${iconPathInMod.replace("/", File.separator).replace("\\", File.separator)}.png"
+ val pathToSave = if(!convertHere){
+ "${storageConfig.iconsStorage.replace("/", File.separator)}$modFolder" +
+ "${File.separator}${iconPathInMod.lowercase().replace("/", File.separator).replace("\\", File.separator)}.png"
+ } else {
+ pathToTgaIcon.replace(".dds", ".tga")
+ }
val directoryToSave = File(pathToSave.split(File.separator).dropLast(1).joinToString (File.separator))
if(!directoryToSave.exists()) directoryToSave.mkdirs()
@@ -53,7 +61,7 @@ class IconsService @Autowired constructor(
}
fun returnIcon(modName: String, raceIconFolder: String, iconName: String): ByteArray? {
- val pathToIcon = "${storageConfig.iconsStorage.replace("/", File.separator)}${File.separator}$modName${File.separator}$raceIconFolder${File.separator}$iconName"
+ val pathToIcon = "${storageConfig.iconsStorage.replace("/", File.separator)}${File.separator}$modName${File.separator}$raceIconFolder${File.separator}${iconName.lowercase()}"
return File(pathToIcon).readBytes()
}
diff --git a/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt b/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt
index 6510ffb..275edf5 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt
@@ -46,13 +46,17 @@ class ModAttribPathService @Autowired constructor(
fun getIconPath(modFolderData: String, iconPath: String): String {
- val iconValidEndPath = iconPath.replace("\\", File.separator).replace("/", File.separator)
+ val iconValidEndPath = iconPath.replace("\\", File.separator).replace("/", File.separator).replace(".tga", "")
val pathToIcon = "${File.separator}art${File.separator}ui${File.separator}ingame${File.separator}$iconValidEndPath.tga"
val modIcon = "$modFolderData$pathToIcon"
+ val lowercaseModIcon = "$modFolderData${pathToIcon.lowercase()}"
+
+ val wanilaModIcon = "$pathToWanilaData$pathToIcon"
return if (Path.of(modIcon).exists()) modIcon else
- "$pathToWanilaData$pathToIcon"
+ if (Path.of(lowercaseModIcon).exists()) lowercaseModIcon else
+ wanilaModIcon
}
}
diff --git a/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt
index a871ede..3c0f8cb 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt
@@ -1,11 +1,13 @@
package com.dowstats.service.w40k
+import com.dowstats.Metadata
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.getIntByName
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
import org.slf4j.LoggerFactory
@@ -34,6 +36,7 @@ class ResearchRgdExtractService @Autowired constructor(
val researchUiInfo = commonParseRgdService.getUiInfo(uiInfo, modDictionary, modFolderData, mod, log)
research.name = researchUiInfo.name
research.description = researchUiInfo.description
+ research.uiIndexHint = researchData.getIntByName("ui_index_hint") ?: 0
research.icon = researchUiInfo.iconPath
val cost = commonParseRgdService.getBuildCost(researchData.getRgdTableByName("time_cost"))
@@ -44,7 +47,7 @@ class ResearchRgdExtractService @Autowired constructor(
research.costSouls = cost.souls
research.costTime = cost.time
research.researchModifiers = getResearchModifiers(research, researchData).toMutableSet()
- research.addonRequirements = getResearchRequirements(research, researchData).toMutableSet()
+ research.researchRequirements = getResearchRequirements(research, researchData).toMutableSet()
research.modId = mod.id
@@ -74,7 +77,7 @@ class ResearchRgdExtractService @Autowired constructor(
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 {
+ if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else {
ResearchRequirements().also {
it.research = research
it.reference = rTable.getStringByName("\$REF")
diff --git a/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt
index 9d5fb0e..217a56f 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt
@@ -1,5 +1,6 @@
package com.dowstats.service.w40k
+import com.dowstats.Metadata
import com.dowstats.data.dto.BuildCost
import com.dowstats.data.entities.*
import com.dowstats.data.rgd.RgdData
@@ -62,7 +63,7 @@ class SergeantRgdExtractService @Autowired constructor(
sergeant.filename = fileName
val sergeantUiRgd = sergeantData.getRgdTableByName("ui_ext")
- ?.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileName")
+ ?.getRgdTableByName("ui_info") ?: throw Exception("$fileName")
val sergeantUiInfo = commonParseRgdService.getUiInfo(sergeantUiRgd, modDictionary, modFolderData, mod, log)
sergeant.name = sergeantUiInfo.name
sergeant.description = sergeantUiInfo.description
@@ -89,6 +90,8 @@ class SergeantRgdExtractService @Autowired constructor(
sergeant.modId = mod.id!!
+ sergeant.sergeantRequirements = getSergeantRequirements(sergeant, sergeantData).toMutableSet()
+
val sergeantWeapons = getSergeantWeapons(sergeantData)?.mapNotNull { weaponData ->
weapons.find {
it.filename == weaponData.weaponFilename + ".rgd"
@@ -163,4 +166,20 @@ class SergeantRgdExtractService @Autowired constructor(
} else null
}?.flatten()
+ private fun getSergeantRequirements(sergeant: Sergeant, sergeantData: List): List {
+ val requirements = sergeantData.getRgdTableByName("requirement_ext")?.getRgdTableByName("requirements")
+ return requirements?.mapNotNull { r ->
+ if (r.name.contains("required_")) {
+ val rTable = r.value as List
+ if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else {
+ SergeantRequirements().also {
+ it.sergeant = sergeant
+ it.reference = rTable.getStringByName("\$REF")
+ it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, sergeant.filename, log)
+ }
+ }
+ } else null
+ } ?: emptyList()
+ }
+
}
diff --git a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt
index 805d762..42cd0f5 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt
@@ -1,5 +1,6 @@
package com.dowstats.service.w40k
+import com.dowstats.Metadata
import com.dowstats.data.dto.BuildCost
import com.dowstats.data.dto.UnitDataToSave
import com.dowstats.data.dto.WeaponsData
@@ -82,6 +83,8 @@ class UnitRgdExtractService @Autowired constructor(
unit.icon = squadUiData.iconPath
unit.filenameSquad = fileNameSquad
unit.filenameUnit = fileNameUnit
+ unit.uiIndexHint = unitData.getRgdTableByName("ui_ext")?.getIntByName("ui_index_hint") ?: 0
+ unit.haveReinforceMenu = squadData.getRgdTableByName("squad_reinforce_ext") != null
val buildCost = getBuildCost(unitData, squadData)
unit.buildCostRequisition = buildCost.requisition
@@ -138,6 +141,7 @@ class UnitRgdExtractService @Autowired constructor(
unit.reinforceCostSouls = reinforceCostData.souls
unit.reinforceTime = reinforceCostData.time
+ unit.unitRequirements = getUnitRequirements(unit, squadData).toMutableSet()
val sergeantsData = getSergeantsData(squadData)
@@ -360,4 +364,20 @@ class UnitRgdExtractService @Autowired constructor(
return Pair(sergeantsData, maxSergeants)
}
+
+ private fun getUnitRequirements(unit: DowUnit, squadData: List): List {
+ val requirements = squadData.getRgdTableByName("squad_requirement_ext")?.getRgdTableByName("requirements")
+ return requirements?.mapNotNull { r ->
+ if (r.name.contains("required_")) {
+ val rTable = r.value as List
+ if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else {
+ UnitRequirements().also {
+ it.unit = unit
+ it.reference = rTable.getStringByName("\$REF")
+ it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, unit.filenameSquad!!, log)
+ }
+ }
+ } else null
+ } ?: emptyList()
+ }
}
diff --git a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt
index af21074..0d06561 100644
--- a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt
+++ b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt
@@ -1,13 +1,12 @@
package com.dowstats.service.w40k
-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.Metadata
+import com.dowstats.data.entities.*
import com.dowstats.data.rgd.RgdData
import com.dowstats.data.rgd.RgdDataUtil.getBooleanByName
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
+import com.dowstats.data.rgd.RgdDataUtil.getStringByName
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
@@ -27,12 +26,12 @@ class WeaponRgdExtractService @Autowired constructor(
weapon.filename = weaponFileName
- 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 = weaponUiInfo.getBooleanByName("no_button")?.let { !it } ?: false
+ val weaponUiInfo = weaponData.getRgdTableByName("ui_info")
+ val weaponUiData = weaponUiInfo?.let{ commonParseRgdService.getUiInfo(weaponUiInfo, modDictionary, modFolderData, mod, log)}
+ weapon.name = weaponUiData?.name
+ weapon.icon = weaponUiData?.iconPath
+ weapon.description = weaponUiData?.description
+ weapon.showInReinforce = weaponUiInfo?.getBooleanByName("show_in_reinforce") ?: false
val cost = commonParseRgdService.getBuildCost(weaponData.getRgdTableByName("cost"))
weapon.costRequisition = cost.requisition ?: 0.0
@@ -70,11 +69,28 @@ class WeaponRgdExtractService @Autowired constructor(
weapon.weaponPiercings = armoursPiercing
weapon.damageRadius = areaEffectData.damageRadius
weapon.modId = mod.id
+ weapon.weaponRequirements = getWeaponRequirements(weapon, weaponData).toMutableSet()
return if(weapon.minDamage == 0.0 && weapon.maxDamage == 0.0 && weapon.moraleDamage == 0.0){
null
} else weapon
}
+ private fun getWeaponRequirements(weapon: Weapon, weaponData: List): List {
+ val requirements = weaponData.getRgdTableByName("requirements")
+ return requirements?.mapNotNull { r ->
+ if (r.name.contains("required_")) {
+ val rTable = r.value as List
+ if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else {
+ WeaponRequirements().also {
+ it.weapon = weapon
+ it.reference = rTable.getStringByName("\$REF")
+ it.value = commonParseRgdService.getRequirementReference(it.reference, rTable, weapon.filename!!, log)
+ }
+ }
+ } else null
+ } ?: emptyList()
+ }
+
}
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
index 2ce5684..17b6eac 100644
--- 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
@@ -3,9 +3,16 @@ CREATE OR REPLACE PROCEDURE delete_campaign_entities(mod_id_p bigint)
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 buildings USING building_requirements WHERE mod_id = mod_id_p AND buildings.id = building_requirements.building_id AND building_requirements.reference = 'requirements\required_cap.lua' AND building_requirements.value = '0';
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 weapons WHERE EXISTS (SELECT 1 FROM weapons AS w2
+ LEFT JOIN buildings_weapons ON w2.id = buildings_weapons.weapon_id
+ LEFT JOIN units_weapons ON w2.id = units_weapons.weapon_id
+ LEFT JOIN sergeants_weapons ON w2.id = sergeants_weapons.weapon_id
+ WHERE mod_id = mod_id_p AND weapons.id = w2.id AND buildings_weapons.building_id IS NULL AND units_weapons.unit_id IS NULL AND sergeants_weapons.sergeant_id IS NULL) AND mod_id = mod_id_p;
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 research_modifiers USING researches WHERE researches.mod_id = mod_id_p 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 '%\_clone%' OR target LIKE '%\_sp%' OR target LIKE '%\_dxp3');
+DELETE FROM addon_modifiers USING building_addons WHERE building_addons.mod_id = mod_id_p AND building_addons.id = addon_modifiers.addon_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 '%\_clone%' OR target LIKE '%\_sp%' OR target LIKE '%\_dxp3');
+DELETE FROM building_addons USING buildings WHERE buildings.mod_id = mod_id_p 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/schema/addon_affected_buildings.json b/src/main/resources/db/0.0.3/schema/addon_affected_buildings.json
new file mode 100644
index 0000000..5fa383e
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/addon_affected_buildings.json
@@ -0,0 +1,66 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add addon_affected_buildings table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "addon_affected_buildings",
+ "columns": [
+ {
+ "column": {
+ "name": "addon_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ },
+ {
+ "column": {
+ "name": "building_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addUniqueConstraint": {
+ "columnNames": "addon_id, building_id",
+ "constraintName": "uc_addon_affected_buildings_addon_id_building_id",
+ "tableName": "addon_affected_buildings"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "addon_id",
+ "baseTableName": "addon_affected_buildings",
+ "constraintName": "fk_addon_addon_affected_buildings",
+ "referencedColumnNames": "id",
+ "referencedTableName": "building_addons",
+ "onDelete": "CASCADE"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "building_id",
+ "baseTableName": "addon_affected_buildings",
+ "constraintName": "fk_buildings_addon_affected_buildings",
+ "referencedColumnNames": "id",
+ "referencedTableName": "buildings",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/addon_affected_sergeants.json b/src/main/resources/db/0.0.3/schema/addon_affected_sergeants.json
new file mode 100644
index 0000000..3e9d626
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/addon_affected_sergeants.json
@@ -0,0 +1,66 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add addon_affected_sergeants table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "addon_affected_sergeants",
+ "columns": [
+ {
+ "column": {
+ "name": "addon_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ },
+ {
+ "column": {
+ "name": "sergeant_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addUniqueConstraint": {
+ "columnNames": "addon_id, sergeant_id",
+ "constraintName": "uc_addon_affected_sergeants_addon_id_sergeant_id",
+ "tableName": "addon_affected_sergeants"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "addon_id",
+ "baseTableName": "addon_affected_sergeants",
+ "constraintName": "fk_addon_addon_affected_sergeants",
+ "referencedColumnNames": "id",
+ "referencedTableName": "building_addons",
+ "onDelete": "CASCADE"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "sergeant_id",
+ "baseTableName": "addon_affected_sergeants",
+ "constraintName": "fk_sergeants_addon_affected_sergeants",
+ "referencedColumnNames": "id",
+ "referencedTableName": "sergeants",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/addon_affected_units.json b/src/main/resources/db/0.0.3/schema/addon_affected_units.json
new file mode 100644
index 0000000..9c3e1e1
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/addon_affected_units.json
@@ -0,0 +1,66 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add addon_affected_units table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "addon_affected_units",
+ "columns": [
+ {
+ "column": {
+ "name": "addon_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ },
+ {
+ "column": {
+ "name": "unit_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addUniqueConstraint": {
+ "columnNames": "addon_id, unit_id",
+ "constraintName": "uc_addon_affected_units_addon_id_unit_id",
+ "tableName": "addon_affected_units"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "addon_id",
+ "baseTableName": "addon_affected_units",
+ "constraintName": "fk_addon_addon_affected_units",
+ "referencedColumnNames": "id",
+ "referencedTableName": "building_addons",
+ "onDelete": "CASCADE"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "unit_id",
+ "baseTableName": "addon_affected_units",
+ "constraintName": "fk_units_addon_affected_units",
+ "referencedColumnNames": "id",
+ "referencedTableName": "units",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/addon_affected_weapons.json b/src/main/resources/db/0.0.3/schema/addon_affected_weapons.json
new file mode 100644
index 0000000..5d2737c
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/addon_affected_weapons.json
@@ -0,0 +1,66 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add addon_affected_weapons table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "addon_affected_weapons",
+ "columns": [
+ {
+ "column": {
+ "name": "addon_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ },
+ {
+ "column": {
+ "name": "weapon_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addUniqueConstraint": {
+ "columnNames": "addon_id, weapon_id",
+ "constraintName": "uc_addon_affected_weapons_addon_id_weapon_id",
+ "tableName": "addon_affected_weapons"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "addon_id",
+ "baseTableName": "addon_affected_weapons",
+ "constraintName": "fk_addon_addon_affected_weapons",
+ "referencedColumnNames": "id",
+ "referencedTableName": "building_addons",
+ "onDelete": "CASCADE"
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "weapon_id",
+ "baseTableName": "addon_affected_weapons",
+ "constraintName": "fk_weapons_addon_affected_weapons",
+ "referencedColumnNames": "id",
+ "referencedTableName": "weapons",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/addon_modifiers.json b/src/main/resources/db/0.0.3/schema/addon_modifiers.json
new file mode 100644
index 0000000..df62355
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/addon_modifiers.json
@@ -0,0 +1,25 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add target to addon modifiers",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "target",
+ "type": "varchar(255)"
+ }
+ }
+ ],
+ "tableName": "addon_modifiers"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/building_addons.json b/src/main/resources/db/0.0.3/schema/building_addons.json
new file mode 100644
index 0000000..15203c8
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/building_addons.json
@@ -0,0 +1,29 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add ui_index_hint column to building_addons",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "ui_index_hint",
+ "type": "int",
+ "value": 0,
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ],
+ "tableName": "building_addons"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/building_requirements.json b/src/main/resources/db/0.0.3/schema/building_requirements.json
new file mode 100644
index 0000000..b16a54e
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/building_requirements.json
@@ -0,0 +1,59 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add building_requirements table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "building_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": "building_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "building_id",
+ "baseTableName": "building_requirements",
+ "constraintName": "fk_building_requirements_buildings",
+ "referencedColumnNames": "id",
+ "referencedTableName": "buildings",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/buildings.json b/src/main/resources/db/0.0.3/schema/buildings.json
new file mode 100644
index 0000000..e668536
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/buildings.json
@@ -0,0 +1,54 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add ui_index_hint column to buildings",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "ui_index_hint",
+ "type": "int",
+ "value": 0,
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ],
+ "tableName": "buildings"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "changeSet": {
+ "id": "Add advanced_build_option column to buildings",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "advanced_build_option",
+ "type": "boolean",
+ "value": false,
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ],
+ "tableName": "buildings"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/researches.json b/src/main/resources/db/0.0.3/schema/researches.json
index a105dde..509d704 100644
--- a/src/main/resources/db/0.0.3/schema/researches.json
+++ b/src/main/resources/db/0.0.3/schema/researches.json
@@ -94,6 +94,31 @@
}
]
}
+ },
+ {
+ "changeSet": {
+ "id": "Add ui_index_hint column to researches",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "ui_index_hint",
+ "type": "int",
+ "value": 0,
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ],
+ "tableName": "researches"
+ }
+ }
+ ]
+ }
}
]
}
diff --git a/src/main/resources/db/0.0.3/schema/sergeant_requirements.json b/src/main/resources/db/0.0.3/schema/sergeant_requirements.json
new file mode 100644
index 0000000..a4d11af
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/sergeant_requirements.json
@@ -0,0 +1,59 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add sergeant_requirements table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "sergeant_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": "sergeant_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "sergeant_id",
+ "baseTableName": "sergeant_requirements",
+ "constraintName": "fk_sergeant_requirements_buildings",
+ "referencedColumnNames": "id",
+ "referencedTableName": "sergeants",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/unit_requirements.json b/src/main/resources/db/0.0.3/schema/unit_requirements.json
new file mode 100644
index 0000000..3c147c7
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/unit_requirements.json
@@ -0,0 +1,59 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add unit_requirements table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "unit_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": "unit_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "unit_id",
+ "baseTableName": "unit_requirements",
+ "constraintName": "fk_unit_requirements_units",
+ "referencedColumnNames": "id",
+ "referencedTableName": "units",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/units.json b/src/main/resources/db/0.0.3/schema/units.json
index 6923e05..25aaf4c 100644
--- a/src/main/resources/db/0.0.3/schema/units.json
+++ b/src/main/resources/db/0.0.3/schema/units.json
@@ -31,6 +31,56 @@
}
]
}
+ },
+ {
+ "changeSet": {
+ "id": "Add ui_index_hint column to unit",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "ui_index_hint",
+ "type": "int",
+ "value": 0,
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ],
+ "tableName": "units"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "changeSet": {
+ "id": "Add have_reinforce_menu column to unit",
+ "author": "anibus",
+ "changes": [
+ {
+ "addColumn": {
+ "columns": [
+ {
+ "column": {
+ "name": "have_reinforce_menu",
+ "type": "boolean",
+ "value": false,
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ],
+ "tableName": "units"
+ }
+ }
+ ]
+ }
}
]
}
diff --git a/src/main/resources/db/0.0.3/schema/weapon_requirements.json b/src/main/resources/db/0.0.3/schema/weapon_requirements.json
new file mode 100644
index 0000000..b98c1d8
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/weapon_requirements.json
@@ -0,0 +1,59 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Add weapon_requirements table",
+ "author": "anibus",
+ "changes": [
+ {
+ "createTable": {
+ "tableName": "weapon_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": "weapon_id",
+ "type": "int",
+ "constraints": {
+ "nullable": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "addForeignKeyConstraint":
+ {
+ "baseColumnNames": "weapon_id",
+ "baseTableName": "weapon_requirements",
+ "constraintName": "fk_weapon_requirements_buildings",
+ "referencedColumnNames": "id",
+ "referencedTableName": "weapons",
+ "onDelete": "CASCADE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/0.0.3/schema/weapons.json b/src/main/resources/db/0.0.3/schema/weapons.json
new file mode 100644
index 0000000..6af146d
--- /dev/null
+++ b/src/main/resources/db/0.0.3/schema/weapons.json
@@ -0,0 +1,19 @@
+{
+ "databaseChangeLog": [
+ {
+ "changeSet": {
+ "id": "Rename addon columns",
+ "author": "anibus",
+ "changes": [
+ {
+ "renameColumn": {
+ "newColumnName": "show_in_reinforce",
+ "oldColumnName": "have_equip_button",
+ "tableName": "weapons"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/src/main/resources/db/changelog-master.json b/src/main/resources/db/changelog-master.json
index 34e7ac7..caeb84f 100644
--- a/src/main/resources/db/changelog-master.json
+++ b/src/main/resources/db/changelog-master.json
@@ -168,6 +168,55 @@
"include": {
"file": "db/0.0.3/schema/sergeants.json"
}
+ },
+ {
+ "include": {
+ "file": "db/0.0.3/schema/addon_modifiers.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/addon_affected_units.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/addon_affected_sergeants.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/addon_affected_buildings.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/addon_affected_weapons.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/building_requirements.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/unit_requirements.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/sergeant_requirements.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/weapon_requirements.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/buildings.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/building_addons.json"
+ }
+ },{
+ "include": {
+ "file": "db/0.0.3/schema/weapons.json"
+ }
}
]
}
diff --git a/src/test/kotlin/com/example/dowstats/service/IconConvertScript.kt b/src/test/kotlin/com/example/dowstats/service/IconConvertScript.kt
new file mode 100644
index 0000000..d372fc6
--- /dev/null
+++ b/src/test/kotlin/com/example/dowstats/service/IconConvertScript.kt
@@ -0,0 +1,35 @@
+import com.dowstats.configuration.StorageConfig
+import com.dowstats.data.rgd.RgdData
+import com.dowstats.service.w40k.IconsService
+import org.junit.jupiter.api.Test
+import java.io.DataInputStream
+import java.io.File
+import java.io.PrintWriter
+import java.math.RoundingMode
+import java.nio.ByteBuffer
+import java.nio.file.Paths
+
+class IconConvertScript {
+
+
+
+ @Test
+ fun testSum() {
+
+ val iconsService = IconsService(StorageConfig())
+
+ val folder = "D:\\home\\cnb\\mods\\Definitive_Edition2.1.1\\Data\\art\\ui\\swf"
+ File(folder).walkTopDown().map {fileOrFolder ->
+ println("Convert ${fileOrFolder.name}")
+ if(fileOrFolder.isFile ){
+ println("Convert ${fileOrFolder.name}")
+ iconsService.convertTgaToJpegImage("" + fileOrFolder.name.replace(".dds", ""), fileOrFolder.path, "Converted")
+ } else {
+ null
+ }
+
+ }.toList()
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/kotlin/com/example/dowstats/service/RtxConvertScript.kt b/src/test/kotlin/com/example/dowstats/service/RtxConvertScript.kt
new file mode 100644
index 0000000..e1dc0fa
--- /dev/null
+++ b/src/test/kotlin/com/example/dowstats/service/RtxConvertScript.kt
@@ -0,0 +1,144 @@
+import com.dowstats.configuration.StorageConfig
+import com.dowstats.service.w40k.IconsService
+import org.junit.jupiter.api.Test
+import java.awt.image.BufferedImage
+import java.io.File
+import java.nio.ByteBuffer
+import java.nio.charset.StandardCharsets
+import javax.imageio.ImageIO
+
+
+class RtxConvertScript {
+
+ val headersAndTypesByteSize = 20
+
+ var imageBytes: List = emptyList()
+ var width: Int = 0
+ var height: Int = 0
+ var format: Int = 0
+ var numMips: Int = 0
+
+ val iconsService = IconsService(StorageConfig())
+
+
+ @Test
+ fun convertAllRtx(){
+ val folder = "D:\\home\\cnb\\wanila\\art\\ui\\ingame"
+ File(folder).walkTopDown().map {fileOrFolder ->
+ if(fileOrFolder.isFile && fileOrFolder.name.endsWith(".dds") ){
+ try {
+ convertFile(fileOrFolder.path)
+ } catch (e: Exception) {
+ println(e.message)
+ }
+
+ } else {
+ null
+ }
+
+ }.toList()
+ }
+
+
+ fun convertFile(fileName: String) {
+
+ convertRtx(fileName)
+ /*val file = fileName
+ val data = File(file).readBytes().toList()
+
+ getDDSHeader()
+ File(fileName.replace(".rtx", ".dds")).writeBytes((getDDSHeader() + data.drop(128)).toByteArray())*/
+ iconsService.convertTgaToJpegImage(fileName, File(fileName).path, "Converted", true)
+
+ val image = ImageIO.read(File(fileName.replace(".rtx", ".tga")))
+
+ val outputImage = BufferedImage(image.height, image.width, image.type)
+
+ val g2d = outputImage.createGraphics()
+ g2d.rotate(Math.toRadians(180.0), (image.width / 2).toDouble(), (image.height / 2).toDouble())
+ g2d.drawImage(image, 0 + image.width, 0, -image.width, image.height, null)
+ g2d.dispose()
+
+ ImageIO.write(outputImage, "tga", File(fileName.replace(".dds", ".tga")));
+
+ }
+
+ fun getDDSHeader(): List {
+ val _DOW_DXT_FLAGS = 0x000A1007
+ val _ddsF_FOURCC = 0x00000004
+ val _DOW_DDSCAPS_FLAGS = 0x401008
+ val signature = "DDS ".toByteArray(Charsets.US_ASCII)
+ signature + ByteBuffer.allocate(4).putInt(124).array()
+ val fourCC = when(format) {
+ 8 -> "DXT1"
+ 10 -> "DXT3"
+ 11 -> "DXT5"
+ else -> "----"
+ }.toByteArray(Charsets.US_ASCII)
+ return (signature + to32Bit(124) + to32Bit(_DOW_DXT_FLAGS) + to32Bit(height) + to32Bit(width) + to32Bit(imageBytes.size) + to32Bit(0) + to32Bit(numMips)
+ + ByteBuffer.allocate(44).array() + to32Bit(32) + to32Bit(_ddsF_FOURCC) + fourCC
+ + ByteBuffer.allocate(20).array() + to32Bit(_DOW_DDSCAPS_FLAGS) + ByteBuffer.allocate(16).array()).toList()
+ }
+
+ fun to32Bit(i: Int): List {
+ return ByteBuffer.allocate(4).putInt(i).array().reversed()
+ }
+
+ private fun convertRtx(fileName: String) {
+
+ File(fileName).readBytes().size
+ var byteArrayParse = File(fileName).readBytes().toList().drop(24)
+
+ readHeader(byteArrayParse)
+
+ }
+
+ private fun readHeader(bytes: List, lvl: Int = 0): Int{
+ val type1 = String(bytes.take(4).toByteArray(), StandardCharsets.UTF_8)
+ val type2 = String(bytes.subList(4, 8).toByteArray(), StandardCharsets.UTF_8)
+
+ val arrSize = bytes.subList(8, 12).reversed().toByteArray().getUIntAt(0)
+ val bytesSize = bytes.subList(12, 16).reversed().toByteArray().getUIntAt(0)
+ val headerValueSize = bytes.subList(16, 20).reversed().toByteArray().getUIntAt(0)
+
+ val header = String(bytes.subList(headersAndTypesByteSize, headersAndTypesByteSize + headerValueSize.toInt()).toByteArray(), StandardCharsets.UTF_8)
+
+ val dataBytes = bytes.subList(headersAndTypesByteSize + headerValueSize.toInt(), headersAndTypesByteSize + headerValueSize.toInt() + bytesSize.toInt())
+
+ println("Type1: $type1, Type2: $type2, ArrSize: $arrSize BytesSize: $bytesSize HeaderValueSize: $headerValueSize Header: $header Bytes: ${dataBytes.size}")
+
+ var i = 0
+ if(type1 == "FOLD") {
+ while (i < bytesSize.toInt()){
+ val bytesSublist = bytes.subList(headersAndTypesByteSize + headerValueSize.toInt() + i, headersAndTypesByteSize + headerValueSize.toInt() + bytesSize.toInt())
+ i += readHeader(bytesSublist, lvl + 1)
+ }
+ }
+ if(type2 == "ATTR"){
+ format = dataBytes.take(4).reversed().toByteArray().getUIntAt(0).toInt()
+ width = dataBytes.subList(4,8).reversed().toByteArray().getUIntAt(0).toInt()
+ height = dataBytes.subList(8,12).reversed().toByteArray().getUIntAt(0).toInt()
+ numMips = dataBytes.subList(12,16).reversed().toByteArray().getUIntAt(0).toInt()
+ println("Format: $format, Width: $width, Height: $height, NumMips: $numMips")
+ }
+ if(type2 == "DATA"){
+ imageBytes = dataBytes
+ }
+ return bytesSize.toInt() + headersAndTypesByteSize
+ }
+
+
+
+
+
+
+
+
+
+ private fun ByteArray.getUIntAt(idx: Int): UInt =
+ ((this[idx].toUInt() and 0xFFu) shl 24) or
+ ((this[idx + 1].toUInt() and 0xFFu) shl 16) or
+ ((this[idx + 2].toUInt() and 0xFFu) shl 8) or
+ (this[idx + 3].toUInt() and 0xFFu)
+
+}
\ No newline at end of file