2025-03-15 21:49:52 +03:00

212 lines
8.6 KiB
Kotlin

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<Int, String> = 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<Int, String> = 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<Weapon>, racesList: List<String>, modId: Long, modDictionary: Map<Int, String>) {
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<RgdData> =
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<Int, String>): Set<Weapon> {
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
}
}
}