From 9b12eb3f51f8959d4a34538f59a1a9a863f44277 Mon Sep 17 00:00:00 2001 From: Anibus Date: Sat, 11 Oct 2025 01:23:24 +0300 Subject: [PATCH] Global update - add requirements for units, sergeants, buildings and weapons - add uiIndexHint for units, buildings, researches and addons - add addon affects - improve campaign entities clear - add dds converter definitive edition - add all files lowercase function before mod parse - add addon modifiers info - add advanced build menu grid --- pom.xml | 5 + src/main/kotlin/com/dowstats/Metadata.kt | 6 + .../dowstats/controllers/UnitsController.kt | 2 +- .../data/dto/controllers/AffectedDataDto.kt | 9 ++ .../data/dto/controllers/RequirementDto.kt | 7 + .../data/dto/controllers/SergeantDto.kt | 1 + .../dto/controllers/SergeantUnitShortDto.kt | 16 ++ .../data/dto/controllers/UnitFullDto.kt | 4 + .../data/dto/controllers/UnitShortDto.kt | 6 +- .../data/dto/controllers/WeaponDto.kt | 5 +- .../dto/controllers/WeaponUnitShortDto.kt | 27 ++++ .../controllers/building/BuildingAddonDto.kt | 4 +- .../controllers/building/BuildingFullDto.kt | 12 +- .../controllers/building/BuildingShortDto.kt | 3 +- .../dto/controllers/research/ResearchDto.kt | 6 +- .../com/dowstats/data/entities/Building.kt | 21 ++- .../data/entities/BuildingRequirements.kt | 18 +++ .../dowstats/data/entities/BuildingWeapon.kt | 5 +- .../com/dowstats/data/entities/DowUnit.kt | 27 +++- .../com/dowstats/data/entities/Sergant.kt | 19 ++- .../dowstats/data/entities/SergantWeapon.kt | 5 +- .../data/entities/SergeantRequirements.kt | 18 +++ .../data/entities/UnitRequirements.kt | 18 +++ .../com/dowstats/data/entities/UnitWeapon.kt | 5 +- .../com/dowstats/data/entities/Weapon.kt | 21 ++- .../dowstats/data/entities/WeaponDamage.kt | 4 +- .../data/entities/WeaponRequirements.kt | 18 +++ .../data/entities/addon/AddonModifiers.kt | 2 + .../data/entities/addon/BuildingAddon.kt | 41 ++++- .../data/entities/research/Research.kt | 50 ++---- .../data/repositories/AddonRepository.kt | 2 + .../service/datamaps/CommonMapping.kt | 26 ++-- .../datamaps/DowBuildingMappingService.kt | 39 +++-- .../service/datamaps/DowUnitMappingService.kt | 45 +++++- .../datamaps/RequirementsMappingComponent.kt | 36 ++++- .../ModStorageIntegrationService.kt | 40 +++++ .../service/postparsing/PostParsingService.kt | 68 +++++++++ .../w40k/BuildingAddonRgdExtractService.kt | 6 +- .../service/w40k/BuildingRgdExtractService.kt | 22 +++ .../service/w40k/CommonParseRgdService.kt | 23 +-- .../com/dowstats/service/w40k/IconsService.kt | 22 ++- .../service/w40k/ModAttribPathService.kt | 8 +- .../service/w40k/ResearchRgdExtractService.kt | 7 +- .../service/w40k/SergantRgdExtractService.kt | 21 ++- .../service/w40k/UnitRgdExtractService.kt | 20 +++ .../service/w40k/WeaponRgdExtractService.kt | 36 +++-- .../procedures/delete_campaign_entities.sql | 11 +- .../schema/addon_affected_buildings.json | 66 ++++++++ .../schema/addon_affected_sergeants.json | 66 ++++++++ .../db/0.0.3/schema/addon_affected_units.json | 66 ++++++++ .../0.0.3/schema/addon_affected_weapons.json | 66 ++++++++ .../db/0.0.3/schema/addon_modifiers.json | 25 +++ .../db/0.0.3/schema/building_addons.json | 29 ++++ .../0.0.3/schema/building_requirements.json | 59 +++++++ .../resources/db/0.0.3/schema/buildings.json | 54 +++++++ .../resources/db/0.0.3/schema/researches.json | 25 +++ .../0.0.3/schema/sergeant_requirements.json | 59 +++++++ .../db/0.0.3/schema/unit_requirements.json | 59 +++++++ src/main/resources/db/0.0.3/schema/units.json | 50 ++++++ .../db/0.0.3/schema/weapon_requirements.json | 59 +++++++ .../resources/db/0.0.3/schema/weapons.json | 19 +++ src/main/resources/db/changelog-master.json | 49 ++++++ .../dowstats/service/IconConvertScript.kt | 35 +++++ .../dowstats/service/RtxConvertScript.kt | 144 ++++++++++++++++++ 64 files changed, 1599 insertions(+), 148 deletions(-) create mode 100644 src/main/kotlin/com/dowstats/data/dto/controllers/AffectedDataDto.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/BuildingRequirements.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/SergeantRequirements.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/UnitRequirements.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/WeaponRequirements.kt create mode 100644 src/main/resources/db/0.0.3/schema/addon_affected_buildings.json create mode 100644 src/main/resources/db/0.0.3/schema/addon_affected_sergeants.json create mode 100644 src/main/resources/db/0.0.3/schema/addon_affected_units.json create mode 100644 src/main/resources/db/0.0.3/schema/addon_affected_weapons.json create mode 100644 src/main/resources/db/0.0.3/schema/addon_modifiers.json create mode 100644 src/main/resources/db/0.0.3/schema/building_addons.json create mode 100644 src/main/resources/db/0.0.3/schema/building_requirements.json create mode 100644 src/main/resources/db/0.0.3/schema/buildings.json create mode 100644 src/main/resources/db/0.0.3/schema/sergeant_requirements.json create mode 100644 src/main/resources/db/0.0.3/schema/unit_requirements.json create mode 100644 src/main/resources/db/0.0.3/schema/weapon_requirements.json create mode 100644 src/main/resources/db/0.0.3/schema/weapons.json create mode 100644 src/test/kotlin/com/example/dowstats/service/IconConvertScript.kt create mode 100644 src/test/kotlin/com/example/dowstats/service/RtxConvertScript.kt 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