package com.dowstats.service.w40k import com.dowstats.data.entities.* import com.dowstats.data.repositories.* import com.dowstats.data.rgd.RgdData import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.lang.Exception import jakarta.transaction.Transactional import org.slf4j.LoggerFactory import java.io.File import java.nio.file.Files import kotlin.io.path.Path import kotlin.io.path.name @Service class ModParserService @Autowired constructor( val rgdParserService: RgdParserService, val unitRgdExtractService: UnitRgdExtractService, val raceRepository: RaceRepository, val armorTypeRepository: ArmorTypeRepository, val unitRepository: UnitRepository, val sergeantRepository: SergeantRepository, val weaponRgdExtractService: WeaponRgdExtractService, val weaponRepository: WeaponRepository, val modAttribPathService: ModAttribPathService, ) { val defaultDictionary: MutableMap = mutableMapOf() init { RgdParserService::class.java.getClassLoader().getResourceAsStream("DXP2.ucs").bufferedReader(Charsets.UTF_8).lines().forEach { val kv = it.split("\\s+".toRegex()) if (kv.size < 2) return@forEach val key = kv.first().filter { it.isDigit() }.toInt() val value = kv.drop(1).joinToString(" ").replace("\u0000","") defaultDictionary[key] = value } RgdParserService::class.java.getClassLoader().getResourceAsStream("W40k.ucs").bufferedReader(Charsets.UTF_8).lines().forEach { val kv = it.split("\\s+".toRegex()) if (kv.size < 2) return@forEach val key = kv.first().filter { it.isDigit() }.toInt() val value = kv.drop(1).joinToString(" ").replace("\u0000","") defaultDictionary[key] = value } } val log = LoggerFactory.getLogger(ModParserService::class.java) @Transactional fun parceModFilesAndSaveToDb(mod: Mod) { log.info("Start parse mod files ${mod.technicalName}:${mod.version}") val modId = mod.id!! val modFolderData = modAttribPathService.getModFolderData(mod.technicalName!!, mod.version!!) val racesList = Files.walk(Path(modAttribPathService.getSbpsAttribsFolderPath(modFolderData)), 1) .toList() .drop(1) .filter { Files.isDirectory(it) }.map { it.name }.toList() racesList.forEach{ unitRepository.deleteAllByModIdAndRaceId(modId, it) } val modDictionary: MutableMap = mutableMapOf() log.info("Extract dictionaries from $modFolderData") File(modAttribPathService.getUcsFolder(modFolderData)).listFiles().forEach { it.bufferedReader(Charsets.UTF_8).lines().forEach { val kv = it.split("\\s+".toRegex()) if (kv.size < 2) return@forEach val key = kv.first().filter { it.isDigit() }.toInt() val value = kv.drop(1).joinToString(" ").replace("\u0000","") modDictionary[key] = value } } val enrichedModDictionary = modDictionary + defaultDictionary val weapons = saveWeapons(modFolderData, modId, enrichedModDictionary) saveUnits(modFolderData, weapons, racesList, modId, enrichedModDictionary) } fun saveUnits(modFolderData: String, weapons: Set, racesList: List, modId: Long, modDictionary: Map) { val races = raceRepository.findAll().toList() val armorTypes = armorTypeRepository.findAll().toList() racesList.forEach { raceFolder -> if( raceRepository.findById(raceFolder) == null){ val race = Race().also { it.id = raceFolder; it.name = raceFolder } raceRepository.save(race) } println(raceFolder) val classicRgdDataSquads = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getSbpsAttribsPath(modAttribPathService.pathToWanilaData, raceFolder)) val modRgdDataSquads = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getSbpsAttribsPath(modFolderData, raceFolder)) val classicRgdDataUnits = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getEbpsTroopsAttribsPath(modAttribPathService.pathToWanilaData, raceFolder)) val modRgdDataUnits = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getEbpsTroopsAttribsPath(modFolderData, raceFolder)) val modSquadsFull = classicRgdDataSquads + modRgdDataSquads val modUnitsFull = classicRgdDataUnits + modRgdDataUnits modSquadsFull.forEach { squadRgdData -> val baseUnitName = unitRgdExtractService.getUnitRgdFileNameFromSquadData(squadRgdData.value) ?: throw Exception("Can't extract unit name from squad ${squadRgdData.key}") log.info("Start extracting $raceFolder: $baseUnitName") val unitRgdData: List = modUnitsFull[baseUnitName] ?: emptyList() if(unitRgdData.isEmpty()){ log.warn("Can't find rgd data for unit $baseUnitName") return@forEach } val unitDataToSave = try { unitRgdExtractService.extractToUnitEntity( squadRgdData.key, modDictionary, squadRgdData.value, unitRgdData, weapons, raceFolder, modFolderData, modId, races, armorTypes, modUnitsFull ) } catch (e: Exception) { log.error("Can't extract $baseUnitName", e) return@forEach } try { val unit = unitRepository.save(unitDataToSave.unit) unit.weapons = unitDataToSave.unitWeapons.map {weapon -> UnitWeapon().also { it.unit = unit it.weapon = weapon it.hardpoint = weapon.hardpoint it.hardpointOrder = weapon.hardpointOrder it.unitWeaponKey = UnitWeaponKey().also { it.unitId = unit.id it.weaponId = weapon.id } } }.toMutableSet() unitRepository.save(unit) unitDataToSave.sergeants?.forEach { sergeantToSave -> val sergeant = sergeantRepository.save(sergeantToSave.first.also { it.unit = unit }) sergeant.weapons = sergeantToSave.second.map {weapon -> SergeantWeapon().also { it.sergeant = sergeant it.weapon = weapon it.hardpoint = weapon.hardpoint it.hardpointOrder = weapon.hardpointOrder it.sergeantWeaponKey = SergeantWeaponKey().also { swk -> swk.sergeantId = sergeant.id swk.weaponId = weapon.id } } }.toMutableSet() sergeantRepository.save(sergeant) } } catch (e: Exception) { throw e } } } } fun saveWeapons(modFolderData: String, modId: Long, modDictionary: Map): Set { val classicWeapons = rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/weapon") val modWeapons = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getWeaponAttribsPath(modFolderData)) val allWeapons = classicWeapons + modWeapons val weaponsToSave = allWeapons.mapNotNull { weaponRgdExtractService.extractToWeaponEntity(it.key, it.value, modId, modFolderData, modDictionary) } return try { weaponRepository.saveAll(weaponsToSave).toSet() } catch (e: Exception) { throw e } } }