Small refactoring + correct delete mod data

This commit is contained in:
Anibus 2025-05-09 13:37:12 +03:00
parent 97537b6ccf
commit fb94b26c83
21 changed files with 146 additions and 78 deletions

View File

@ -0,0 +1,29 @@
package com.dowstats.controllers
import com.dowstats.service.integrations.ModStorageIntegrationService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
@RestController
@RequestMapping("api/v1/custom-mod")
class CustomModsController @Autowired constructor(
val modStorageIntegrationService: ModStorageIntegrationService
) {
@PostMapping("/reload/{modId}")
fun reloadMod(@PathVariable modId: Long): String {
modStorageIntegrationService.reloadMod(modId)
return "Successfully reload mod"
}
@PostMapping("/upload")
fun uploadMod(@RequestParam("file") file: MultipartFile?,
@RequestParam("name") name: String,
@RequestParam("technicalName") technicalName: String,
@RequestParam("version") version: String?): String {
modStorageIntegrationService.saveModFromRequest(file, name, technicalName, version?:"1.0.0")
return "Successfully upload mod"
}
}

View File

@ -1,33 +0,0 @@
package com.dowstats.controllers
import com.dowstats.service.integrations.ModStorageIntegrationService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.multipart.MultipartFile
@RestController
@RequestMapping("api/v1/upload-mod")
class UploadCustomModController @Autowired constructor(
val modStorageIntegrationService: ModStorageIntegrationService
) {
@PostMapping
fun uploadMod(@RequestParam("file") file: MultipartFile,
@RequestParam("name") name: String,
@RequestParam("technicalName") technicalName: String,
@RequestParam("version") version: String?): String {
val log = LoggerFactory.getLogger(UploadCustomModController::class.java)
modStorageIntegrationService.saveModFromRequest(file.bytes.inputStream(), name, technicalName, version?:"1.0.0")
log.info("${file.originalFilename} successfull uploaded. Name: $name, version: $version")
return "Successfull upload mod"
}
}

View File

@ -1,8 +1,16 @@
package com.dowstats.data.repositories
import com.dowstats.data.entities.Mod
import org.springframework.data.jpa.repository.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.*
interface ModRepository : CrudRepository<Mod, Long>{
fun findByTechnicalNameAndVersion(techName: String, version: String): Mod?
@Query("""
CALL delete_mod_data(:modId)
""", nativeQuery = true)
@Modifying
fun clearModData(modId: Long)
}

View File

@ -9,7 +9,9 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.util.FileSystemUtils
import org.springframework.web.multipart.MultipartFile
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
@ -70,9 +72,16 @@ class ModStorageIntegrationService(
}
}
fun saveModFromRequest(fileStream: InputStream, name: String, techName: String, version: String) {
val modDirectoryTo = "$name$version"
unzip(fileStream, modDirectoryTo)
@Transactional
fun reloadMod(modId: Long) {
val mod = modRepository.findById(modId).orElseThrow { IllegalArgumentException("Mod not found") }
modRepository.clearModData(modId)
modParserService.parceModFilesAndSaveToDb(mod)
}
fun saveModFromRequest(file: MultipartFile?, name: String, techName: String, version: String) {
val uploadingMod = modRepository.findByTechnicalNameAndVersion(techName, version)
val savedMod = uploadingMod ?: modRepository.save(Mod().also {
it.version = version
@ -80,7 +89,14 @@ class ModStorageIntegrationService(
it.name = name
it.technicalName = techName
})
modParserService.parceModFilesAndSaveToDb(savedMod)
file?.let {
val modDirectoryTo = "$name$version"
val fileStream = file.bytes.inputStream()
unzip(fileStream, modDirectoryTo)
modParserService.parceModFilesAndSaveToDb(savedMod)
log.info("${file.originalFilename} successfull uploaded. Name: $name, version: $version")
}
}
private fun downloadAndExtractMod(modTechName: String, version: String) {

View File

@ -11,8 +11,6 @@ class Schedulers (
val modStorageIntegrationService: ModStorageIntegrationService
) {
private val log = LogFactory.getLog(javaClass)
@Scheduled(fixedDelay = 600000)
fun synchronizeLastMods() {
modStorageIntegrationService.requestAvailableMods()

View File

@ -22,11 +22,12 @@ class IconsService @Autowired constructor(
*/
fun convertTgaToJpegImage(iconPathInMod: String, pathToTgaIcon: String, modName: String? = null): String? {
try{
val image: BufferedImage = try {
val image: BufferedImage = if(File(pathToTgaIcon).exists()) {
ImageIO.read(File(pathToTgaIcon))
} catch (e: Exception){
} else if (File(pathToTgaIcon.lowercase()).exists()) {
ImageIO.read(File(pathToTgaIcon.lowercase()))
}
} else return null
val modFolder = modName?.let { "${File.separator}$modName" } ?: ""

View File

@ -18,6 +18,9 @@ class ModAttribPathService @Autowired constructor(
fun getUcsFolder(modFolderData: String): String =
"${modFolderData.replace("Data", "")}Locale${File.separator}English${File.separator}"
fun getUcsFolderRus(modFolderData: String): String =
"${modFolderData.replace("Data", "")}Locale${File.separator}Russian${File.separator}"
fun getWeaponAttribsPath(modFolderData: String): String =
"$modFolderData${File.separator}attrib${File.separator}weapon"

View File

@ -65,11 +65,26 @@ class ModParserService @Autowired constructor(
unitRepository.deleteAllByModIdAndRaceId(mod.id!!, it)
}
val modDictionary: MutableMap<Int, String> = mutableMapOf()
val modDictionary: Map<Int, String> = getModDictionary(mod, modFolderData)
log.info("Extract dictionaries from $modFolderData")
File(modAttribPathService.getUcsFolder(modFolderData)).listFiles().forEach {
it.bufferedReader(Charsets.UTF_8).lines().forEach {
val enrichedModDictionary = defaultDictionary + modDictionary
val weapons = saveWeapons(modFolderData, mod, enrichedModDictionary)
saveUnits(modFolderData, weapons, racesList, mod, enrichedModDictionary)
saveBuildings(modFolderData, weapons, racesList, mod, enrichedModDictionary)
}
private fun getModDictionary(mod: Mod, modFolderData: String): Map<Int,String>{
val folder = if (mod.technicalName == "multidungeon_rightpocalypse") modAttribPathService.getUcsFolderRus(modFolderData) else modAttribPathService.getUcsFolder(modFolderData)
val modDictionary = mutableMapOf<Int, String>()
File(folder).listFiles()?.forEach {
it.bufferedReader(Charsets.UTF_16).lines().forEach {
val kv = it.split("\\s+".toRegex())
if (kv.size < 2) return@forEach
val key = try {kv.first().filter { it.isDigit() }.toInt()} catch(e: Exception) {
@ -81,16 +96,10 @@ class ModParserService @Autowired constructor(
}
}
val enrichedModDictionary = modDictionary + defaultDictionary
val weapons = saveWeapons(modFolderData, mod, enrichedModDictionary)
saveUnits(modFolderData, weapons, racesList, mod, enrichedModDictionary)
saveBuildings(modFolderData, weapons, racesList, mod, enrichedModDictionary)
return modDictionary
}
fun saveUnits(modFolderData: String, weapons: Set<Weapon>, racesList: List<String>, mod: Mod, modDictionary: Map<Int, String>) {
private fun saveUnits(modFolderData: String, weapons: Set<Weapon>, racesList: List<String>, mod: Mod, modDictionary: Map<Int, String>) {
val races = raceRepository.findAll().toList()
val armorTypes = armorTypeRepository.findAll().toList()
@ -186,7 +195,7 @@ class ModParserService @Autowired constructor(
}
}
fun saveBuildings(modFolderData: String,
private fun saveBuildings(modFolderData: String,
weapons: Set<Weapon>,
racesList: List<String>,
mod: Mod, modDictionary: Map<Int, String>) {
@ -249,7 +258,7 @@ class ModParserService @Autowired constructor(
}
}
fun getAddonsRgdData(modFolderData: String): Map<String, List<RgdData>> {
private fun getAddonsRgdData(modFolderData: String): Map<String, List<RgdData>> {
val classicAddons = rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/addons")
@ -259,7 +268,7 @@ class ModParserService @Autowired constructor(
return classicAddons + modAddons
}
fun saveWeapons(modFolderData: String, mod: Mod, modDictionary: Map<Int, String>): Set<Weapon> {
private fun saveWeapons(modFolderData: String, mod: Mod, modDictionary: Map<Int, String>): Set<Weapon> {
val classicWeapons = rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/weapon")

View File

@ -26,8 +26,6 @@ class ModsDiffService @Autowired constructor(
setOf(spaceMarinesPath, chaosPath, eldarPath, orksPath, guardPath, necronPath, tauPath, sistersPath)
fun getUnitsAndSquadsDiff(modFolderData: String, oldModFolderData: String? = null): String {
val oldModFolderPath =

View File

@ -115,23 +115,23 @@ class WeaponRgdExtractService @Autowired constructor(
val armourDamage = areaEffect
?.getRgdTableByName("weapon_damage")
?.getRgdTableByName("armour_damage")!!
val minDamage = armourDamage.getDoubleByName("min_damage")!!
val maxDamage = armourDamage.getDoubleByName("max_damage")!!
val minDamageValue = armourDamage.getDoubleByName("min_damage_value")!!
val moraleDamage = armourDamage.getDoubleByName("morale_damage")!!
?.getRgdTableByName("armour_damage")
val minDamage = armourDamage?.getDoubleByName("min_damage") ?: 0.0
val maxDamage = armourDamage?.getDoubleByName("max_damage") ?: 0.0
val minDamageValue = armourDamage?.getDoubleByName("min_damage_value") ?: 0.0
val moraleDamage = armourDamage?.getDoubleByName("morale_damage") ?: 0.0
val defaultArmourPiercing = armourDamage.getDoubleByName("armour_piercing")
val defaultArmourPiercing = armourDamage?.getDoubleByName("armour_piercing")
val weaponDmgMap: Map<String, Double> =
armourDamage.getRgdTableByName("armour_piercing_types")!!.mapNotNull { armour_piercing ->
armourDamage?.getRgdTableByName("armour_piercing_types")?.mapNotNull { armour_piercing ->
if (armour_piercing.name.contains("entry")) {
val entry = armour_piercing.value as List<RgdData>
val dmgType = entry.getRgdTableByName("armour_type")?.getStringByName("\$REF")?.replace("type_armour\\tp_","")?.replace(".lua","")
val dmgValue = entry.getDoubleByName("armour_piercing_value")
dmgType!! to dmgValue!!
} else null
}.toMap()
}?.toMap() ?: emptyMap()
val armoursPiercing = armorTypes.map {
val weaponArmourPiercing = WeaponArmorPiercing()

View File

@ -0,0 +1,7 @@
CREATE OR REPLACE PROCEDURE delete_mod_data(mod_id_p bigint)
LANGUAGE SQL
AS $$
DELETE FROM units WHERE mod_id = mod_id_p;
DELETE FROM buildings WHERE mod_id = mod_id_p;
DELETE FROM weapons WHERE mod_id = mod_id_p;
$$;

View File

@ -53,7 +53,8 @@
"baseTableName": "addon_modifiers",
"constraintName": "fk_building_addons_addon_modifiers",
"referencedColumnNames": "id",
"referencedTableName": "building_addons"
"referencedTableName": "building_addons",
"onDelete": "CASCADE"
}
}
]

View File

@ -53,7 +53,8 @@
"baseTableName": "addon_requires",
"constraintName": "fk_building_addons_addon_requires",
"referencedColumnNames": "id",
"referencedTableName": "building_addons"
"referencedTableName": "building_addons",
"onDelete": "CASCADE"
}
}
]

View File

@ -94,7 +94,8 @@
"baseTableName": "building_addons",
"constraintName": "fk_building_addons_buildings",
"referencedColumnNames": "id",
"referencedTableName": "buildings"
"referencedTableName": "buildings",
"onDelete": "CASCADE"
}
}
]

View File

@ -62,7 +62,8 @@
"baseTableName": "buildings_weapons",
"constraintName": "fk_buildings_buildings_weapons",
"referencedColumnNames": "id",
"referencedTableName": "buildings"
"referencedTableName": "buildings",
"onDelete": "CASCADE"
}
},
{
@ -72,7 +73,8 @@
"baseTableName": "buildings_weapons",
"constraintName": "fk_weapons_buildings_weapons",
"referencedColumnNames": "id",
"referencedTableName": "weapons"
"referencedTableName": "weapons",
"onDelete": "CASCADE"
}
}
]

View File

@ -0,0 +1,17 @@
{
"databaseChangeLog": [
{
"changeSet": {
"id": "Creade delete_mod_data_procedure",
"author": "anibus",
"changes": [
{
"createProcedure": {
"path": "db/0.0.1/procedures/delete_mod_data_procedure.sql"
}
}
]
}
}
]
}

View File

@ -149,7 +149,8 @@
"baseTableName": "sergeants",
"constraintName": "fk_sergeants_units",
"referencedColumnNames": "id",
"referencedTableName": "units"
"referencedTableName": "units",
"onDelete": "CASCADE"
}
}
]

View File

@ -62,7 +62,8 @@
"baseTableName": "sergeants_weapons",
"constraintName": "fk_sergeants_sergeants_weapons",
"referencedColumnNames": "id",
"referencedTableName": "sergeants"
"referencedTableName": "sergeants",
"onDelete": "CASCADE"
}
},
{
@ -72,7 +73,8 @@
"baseTableName": "sergeants_weapons",
"constraintName": "fk_weapons_sergeants_weapons",
"referencedColumnNames": "id",
"referencedTableName": "weapons"
"referencedTableName": "weapons",
"onDelete": "CASCADE"
}
}
]

View File

@ -62,7 +62,8 @@
"baseTableName": "units_weapons",
"constraintName": "fk_units_units_weapons",
"referencedColumnNames": "id",
"referencedTableName": "units"
"referencedTableName": "units",
"onDelete": "CASCADE"
}
},
{
@ -72,7 +73,8 @@
"baseTableName": "units_weapons",
"constraintName": "fk_weapons_units_weapons",
"referencedColumnNames": "id",
"referencedTableName": "weapons"
"referencedTableName": "weapons",
"onDelete": "CASCADE"
}
}
]

View File

@ -53,7 +53,8 @@
"baseColumnNames": "weapon_id",
"baseTableName": "weapons_armors_damage",
"referencedColumnNames": "id",
"referencedTableName": "weapons"
"referencedTableName": "weapons",
"onDelete": "CASCADE"
}
},{
"addForeignKeyConstraint":

View File

@ -55,7 +55,7 @@
}
},{
"include": {
"file": "db/0.0.1/schema/weapons_armors_damage.json"
"file": "db/0.0.1/schema/weapons_armors_piercing.json"
}
},{
"include": {
@ -69,6 +69,10 @@
"include": {
"file": "db/0.0.1/data/races.json"
}
},{
"include": {
"file": "db/0.0.1/schema/procedure_delete_mod_data.json"
}
}
]
}