From 47a01f17cdb5c7d2518f9950760c0d7ebf9eba99 Mon Sep 17 00:00:00 2001 From: Anibus Date: Sun, 1 Jun 2025 20:10:54 +0300 Subject: [PATCH] - Add addon requirements - Add config to reload mods --- .../controllers/BuildingsController.kt | 2 +- .../controllers/CustomModsController.kt | 12 +++ .../building/AddonRequirementDto.kt | 9 +- .../controllers/building/BuildingAddonDto.kt | 9 +- .../data/entities/AddonRequirements.kt | 18 ++-- .../com/dowstats/data/entities/Building.kt | 5 +- .../dowstats/data/entities/BuildingAddon.kt | 14 +++- .../data/repositories/AddonRepository.kt | 4 +- .../data/repositories/BuildingRepository.kt | 2 + .../datamaps/DowBuildingMappingService.kt | 83 +++++++++++++++++-- .../ModStorageIntegrationService.kt | 12 +++ .../w40k/BuildingAddonRgdExtractService.kt | 12 ++- src/main/resources/db/0.0.2/schema/addon.json | 42 ++++++++++ 13 files changed, 196 insertions(+), 28 deletions(-) diff --git a/src/main/kotlin/com/dowstats/controllers/BuildingsController.kt b/src/main/kotlin/com/dowstats/controllers/BuildingsController.kt index 32fe738..935f459 100644 --- a/src/main/kotlin/com/dowstats/controllers/BuildingsController.kt +++ b/src/main/kotlin/com/dowstats/controllers/BuildingsController.kt @@ -33,7 +33,7 @@ class BuildingsController @Autowired constructor( @GetMapping("/{buildingId}") fun getById(@PathVariable buildingId: Long): BuildingFullDto { - return buildingRepository.findById(buildingId).get().toDto() + return dowBuildingMappingService.mapToDto(buildingRepository.findById(buildingId).get()) } @DeleteMapping diff --git a/src/main/kotlin/com/dowstats/controllers/CustomModsController.kt b/src/main/kotlin/com/dowstats/controllers/CustomModsController.kt index bdf969a..4066772 100644 --- a/src/main/kotlin/com/dowstats/controllers/CustomModsController.kt +++ b/src/main/kotlin/com/dowstats/controllers/CustomModsController.kt @@ -18,6 +18,18 @@ class CustomModsController @Autowired constructor( return "Successfully reload mod" } + @DeleteMapping("/data") + fun deleteAllModData(): String { + modStorageIntegrationService.deleteMods() + return "Successfully delete all mods data" + } + + @DeleteMapping("/data/{modId}") + fun deleteModData(@PathVariable modId: Long): String { + modStorageIntegrationService.deleteMod(modId) + return "Successfully delete mod data" + } + @PostMapping("/upload") fun uploadMod(@RequestParam("file") file: MultipartFile?, @RequestParam("name") name: String, diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt index f997f2d..6af6622 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/building/AddonRequirementDto.kt @@ -1,8 +1,9 @@ package com.dowstats.data.dto.controllers.building data class AddonRequirementDto ( - val id: Long, - val reference: String?, - val replaceWhenDone: Boolean, - val value: Double?, + val requirementBuildings: List, + val requirementBuildingsEither: List, + val requireAddon: BuildingAddonShortDto?, + val requirementsGlobalAddons: List?, + val requiredTotalPop: Int?, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingAddonDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingAddonDto.kt index a2cc848..ceab56c 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 @@ -12,6 +12,13 @@ data class BuildingAddonDto( val addonCostSouls: Double?, val addonCostTime: Int?, val addonModifiers: Set, - val addonRequirements: Set, + val addonRequirement: AddonRequirementDto?, val icon: String?, ) + +data class BuildingAddonShortDto( + val id: Long?, + val buildingId: Long?, + val name: String?, + val icon: String?, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt index c7a5429..0adb7a6 100644 --- a/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt +++ b/src/main/kotlin/com/dowstats/data/entities/AddonRequirements.kt @@ -19,14 +19,14 @@ class AddonRequirements { var addon: BuildingAddon? = null var reference: String? = null var replaceWhenDone: Boolean = false - var value: Double? = null - - fun toDto(): AddonRequirementDto { - return AddonRequirementDto( - id = id!!, - reference = reference, - replaceWhenDone = replaceWhenDone, - value = value - ) + var value: String? = null + + companion object { + val REFERENCE_REQUIREMENT_POP = "requirements\\required_total_pop.lua" + val REFERENCE_REQUIREMENT_ADDON = "requirements\\local_required_addon.lua" + val REFERENCE_GLOBAL_REQUIREMENT_ADDON = "requirements\\global_required_addon.lua" + val REFERENCE_REQUIREMENT_STRUCTURE_EITHER = "requirements\\required_structure_either.lua" + val REFERENCE_REQUIREMENT_STRUCTURE = "requirements\\required_structure.lua" } + } diff --git a/src/main/kotlin/com/dowstats/data/entities/Building.kt b/src/main/kotlin/com/dowstats/data/entities/Building.kt index 7fbdf54..3b11530 100644 --- a/src/main/kotlin/com/dowstats/data/entities/Building.kt +++ b/src/main/kotlin/com/dowstats/data/entities/Building.kt @@ -1,5 +1,6 @@ package com.dowstats.data.entities +import com.dowstats.data.dto.controllers.building.BuildingAddonDto import com.dowstats.data.dto.controllers.building.BuildingFullDto import jakarta.persistence.* @@ -47,7 +48,7 @@ class Building { @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL]) var weapons: MutableSet? = null - fun toDto(): BuildingFullDto = + fun toDto(buildingAddons: Set?): BuildingFullDto = BuildingFullDto( id!!, race?.toDto(), @@ -69,7 +70,7 @@ class Building { repairMax, icon, modId!!, - addons?.map { it.toDto() }?.toSet(), + buildingAddons, weapons?.map { it.toWeaponSlotDto() }?.toSet(), ) diff --git a/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt b/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt index d6406d0..767dcc7 100644 --- a/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt +++ b/src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt @@ -1,6 +1,8 @@ package com.dowstats.data.entities +import com.dowstats.data.dto.controllers.building.AddonRequirementDto import com.dowstats.data.dto.controllers.building.BuildingAddonDto +import com.dowstats.data.dto.controllers.building.BuildingAddonShortDto import com.fasterxml.jackson.annotation.JsonIgnore import jakarta.persistence.* @@ -35,8 +37,9 @@ class BuildingAddon { var addonRequirements: MutableSet? = null var icon: String? = null + var modId: Long? = null - fun toDto(): BuildingAddonDto = BuildingAddonDto( + fun toDto(addonRequirementDto: AddonRequirementDto?): BuildingAddonDto = BuildingAddonDto( id = id, name = name, description = description, @@ -48,7 +51,14 @@ class BuildingAddon { addonCostSouls = addonCostSouls, addonCostTime = addonCostTime, addonModifiers = addonModifiers?.map { it.toDto() }?.toSet() ?: emptySet(), - addonRequirements = addonRequirements?.map { it.toDto() }?.toSet() ?: emptySet(), + addonRequirement = addonRequirementDto, + icon = icon + ) + + fun toShortDto(): BuildingAddonShortDto = BuildingAddonShortDto( + id = id, + buildingId = building?.id, + name = name, icon = icon ) diff --git a/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt index 1e3ccc9..9c9749e 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/AddonRepository.kt @@ -7,4 +7,6 @@ import com.dowstats.data.entities.Race import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.CrudRepository -interface AddonRepository : CrudRepository \ No newline at end of file +interface AddonRepository : CrudRepository{ + fun findFirstByModIdAndFilename(modId: Long, fileName: String): BuildingAddon? +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/BuildingRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/BuildingRepository.kt index 460a5c7..c5f1f4d 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/BuildingRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/BuildingRepository.kt @@ -17,4 +17,6 @@ interface BuildingRepository : CrudRepository{ order by b.race.id desc """) fun findByModIdAndRace(modId: Long, race: Race?): List + + fun findByModIdAndFilename(modId: Long, fileName: String): Building? } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt index c1f8ed6..c79f026 100644 --- a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt +++ b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt @@ -1,8 +1,12 @@ package com.dowstats.service.datamaps +import com.dowstats.data.dto.controllers.building.AddonRequirementDto +import com.dowstats.data.dto.controllers.building.BuildingFullDto import com.dowstats.data.dto.controllers.building.BuildingShortDto import com.dowstats.data.dto.controllers.building.RaceBuildings +import com.dowstats.data.entities.AddonRequirements import com.dowstats.data.entities.Building +import com.dowstats.data.repositories.AddonRepository import com.dowstats.data.repositories.BuildingRepository import com.dowstats.data.repositories.RaceRepository import org.springframework.beans.factory.annotation.Autowired @@ -11,34 +15,103 @@ import org.springframework.stereotype.Service @Service class DowBuildingMappingService @Autowired constructor( val buildingRepository: BuildingRepository, + val addonRepository: AddonRepository, val raceRepository: RaceRepository ) { fun findBuildingsByMod(modId: Long): List { - return getAllBuildings(modId).groupBy { it.race }.mapNotNull {raceUnits -> + return getAllBuildings(modId).groupBy { it.race }.mapNotNull { raceUnits -> RaceBuildings(raceUnits.key?.toDto() ?: throw Exception("Race is null"), raceUnits.value.toBuildingDto()) } } 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") } + val raceEntity = race.let { raceRepository.findById(race) ?: throw Exception("Race $race not found") } return RaceBuildings(raceEntity.toDto(), buildings.toBuildingDto()) } + fun mapToDto(building: Building): BuildingFullDto { + + val buildingAddons = building.addons?.map { addon -> + + val requirements = addon.addonRequirements + + val requireCap = + requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble() + ?.toInt() + + val requirementAddon = + requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_ADDON }?.value?.let { + building.addons?.find { addon -> addon.filename == it.split("\\").last().replace(".lua", ".rgd") } + } + + val requirementAddonGlobal = + requirements?.filter { it.reference == AddonRequirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON } + ?.mapNotNull { rgra -> + val addonFileName = rgra.value?.split("\\")?.last()?.replace(".lua", ".rgd") + addonFileName?.let { + addonRepository.findFirstByModIdAndFilename( + building.modId!!, + it.split("\\").last().replace(".lua", ".rgd") + )?.toShortDto() + } + } + + val requirementBuildings = + requirements?.filter { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE }?.mapNotNull { + val buildingFileName = it.value?.split("\\")?.last()?.replace(".lua", ".rgd") + buildingFileName?.let { + buildingRepository.findByModIdAndFilename(building.modId!!, buildingFileName) + } + }?.filter { it.id != building.id }?.distinct()?.toBuildingDto() + + val requirementBuildingsEither = + requirements?.find { it.reference == AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let { + it.value?.split(";")?.mapNotNull { bPath -> + buildingRepository.findByModIdAndFilename( + building.modId!!, + bPath.split("\\").last().replace(".lua", ".rgd") + ) + } + }?.toBuildingDto() + + val addonRequirement = if (requireCap != null || + requirementAddon != null || + (requirementBuildings?.size ?: 0) > 0 || + (requirementBuildingsEither?.size ?: 0) > 0 || + (requirementAddonGlobal?.size ?: 0) > 0 + ) { + AddonRequirementDto( + requirementBuildings ?: emptyList(), + requirementBuildingsEither ?: emptyList(), + requirementAddon?.toShortDto(), + requirementAddonGlobal, + requireCap + ) + } else null + + addon.toDto(addonRequirement) + }?.sortedBy { it.id }?.toSet() + + return building.toDto(buildingAddons) + } + private fun List.toBuildingDto(): List = this.mapNotNull { val name = it.name ?: it.filename val icon = it.icon - if (name == null || icon == null) null else BuildingShortDto(name, icon, it.id!!, + if (name == null || icon == null) null else BuildingShortDto( + name, icon, it.id!!, it.armorType?.name!!, - (it.detectRadius ?: 0) > 0) + (it.detectRadius ?: 0) > 0 + ) } private fun getAllBuildings(modId: Long, race: String? = null): List { - val raceEntity = race?.let{ raceRepository.findById(race) ?: throw Exception("Race $race not found") } + val raceEntity = race?.let { raceRepository.findById(race) ?: throw Exception("Race $race not found") } return filterCompanyUnits(buildingRepository.findByModIdAndRace(modId, raceEntity)) } diff --git a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt index 8bfbedc..c98918b 100644 --- a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt +++ b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt @@ -77,6 +77,18 @@ class ModStorageIntegrationService( } } + @Transactional + fun deleteMod(modId: Long) { + modRepository.clearModData(modId) + } + + @Transactional + fun deleteMods() { + modRepository.findAll().forEach{ + modRepository.clearModData(it.id!!) + } + } + @Transactional fun reloadMod(modId: Long) { val mod = modRepository.findById(modId).orElseThrow { IllegalArgumentException("Mod not found") } diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt index 71c0013..e6a0920 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt @@ -56,6 +56,7 @@ class BuildingAddonRgdExtractService @Autowired constructor( val addonIcon = convertIconAndReturnPath(addonRgdData, modFolderData, mod.name) addon.icon = addonIcon + addon.modId = mod.id return addon } @@ -87,9 +88,14 @@ class BuildingAddonRgdExtractService @Autowired constructor( it.addon = addon it.reference = rTable.getStringByName("\$REF") it.replaceWhenDone = rTable.getBooleanByName("replace_when_done") == true - // TODO - что-то придумать с этим - it.value = - if (it.reference == "requirements\\required_total_pop.lua") rTable.getDoubleByName("population_required") else null + it.value = when(it.reference){ + AddonRequirements.REFERENCE_REQUIREMENT_POP -> rTable.getDoubleByName("population_required").toString() + AddonRequirements.REFERENCE_REQUIREMENT_ADDON -> rTable.getStringByName("addon_name") + AddonRequirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON -> rTable.getStringByName("global_addon_name") + AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER -> rTable.getStringByName("structure_name_or") + ";" + rTable.getStringByName("structure_name_either") + AddonRequirements.REFERENCE_REQUIREMENT_STRUCTURE -> rTable.getStringByName("structure_name") + else -> null + } } } } else null diff --git a/src/main/resources/db/0.0.2/schema/addon.json b/src/main/resources/db/0.0.2/schema/addon.json index 69691b5..b51f88b 100644 --- a/src/main/resources/db/0.0.2/schema/addon.json +++ b/src/main/resources/db/0.0.2/schema/addon.json @@ -67,6 +67,48 @@ } ] } + }, + { + "changeSet": { + "id": "Change addon_requirements value type (2)", + "author": "anibus", + "changes": [ + { + "dropColumn": { + "columns": [ + { + "column": { + "name": "value" + } + } + ], + "tableName": "addon_requirements" + } + }, + { + "addColumn": { + "columns": [ + { + "column": { + "name": "value", + "type": "varchar(256)" + } + }, + { + "column": { + "name": "mod_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ], + "tableName": "addon_requirements" + } + } + ] + } } ] }