380 lines
16 KiB
Kotlin
380 lines
16 KiB
Kotlin
import com.dowstats.data.rgd.RgdData
|
|
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
|
|
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
|
|
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
|
|
import com.dowstats.service.w40k.RgdParserService
|
|
import com.dowstats.service.w40k.RgdService
|
|
import org.junit.jupiter.api.Test
|
|
import java.io.DataInputStream
|
|
import java.io.File
|
|
import java.io.PrintWriter
|
|
import java.nio.ByteBuffer
|
|
|
|
class ModParserServiceTest {
|
|
|
|
val zeroByte: Byte = 0
|
|
|
|
val rgdDictionary: MutableMap<Int, String> = mutableMapOf()
|
|
|
|
val rgdParseService = RgdParserService()
|
|
|
|
val rgdService = RgdService()
|
|
|
|
val prevVersion = "Dowstats_Balance_Mod_1_0_97"
|
|
val currentVersion = "Dowstats_Balance_Mod_1_0_98"
|
|
|
|
val spaceMarinesPath = "space_marines"
|
|
val chaosPath = "chaos"
|
|
val eldarPath = "eldar"
|
|
val orksPath = "orks"
|
|
val guardPath = "guard"
|
|
val necronPath = "necrons"
|
|
val tauPath = "tau"
|
|
val sistersPath = "sisters"
|
|
val darkPath = "dark_eldar"
|
|
|
|
val racesWikiPaths = setOf(spaceMarinesPath, chaosPath, eldarPath, orksPath, guardPath, necronPath, tauPath, sistersPath)
|
|
val racesWikiPaths2 = setOf("black_templars")
|
|
|
|
fun readDictionary() {
|
|
File("src/test/resources/RGD_DIC.TXT").forEachLine {
|
|
if(it.isNotEmpty() && it[0] != '#'){
|
|
val kv = it.split('=')
|
|
val key = kv.first().drop(2).decodeHex().getUIntAt(0).toInt()
|
|
val value = kv.last()
|
|
rgdDictionary[key] = value
|
|
}
|
|
}
|
|
}
|
|
|
|
fun getUnitsAndSquadsDiff(out: PrintWriter) {
|
|
|
|
racesWikiPaths.forEach{racePath ->
|
|
val rgdDataOld = File("src/main/resources/static/mods/$prevVersion/attrib/sbps/races/$racePath").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
val rgdDataNew = File("src/main/resources/static/mods/$currentVersion/attrib/sbps/races/$racePath").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
}else{
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.sortedBy { it.first }
|
|
.toMap()
|
|
|
|
val rgdDataUnitsOld = File("src/main/resources/static/mods/$prevVersion/attrib/ebps/races/$racePath/troops").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
}else{
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
val rgdDataUnitsNew = File("src/main/resources/static/mods/$currentVersion/attrib/ebps/races/$racePath/troops").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
}else{
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
/*classicRgdData.mapValues { findStrategicPointCaptureRate( it.value?: listOf()) }.entries
|
|
.sortedByDescending { it.value }
|
|
.filter { it.value != null }
|
|
.filter { !it.key.contains("_sp") }
|
|
.forEach{println(it.key + " -> " + it.value )}*/
|
|
|
|
val changedSquadNames = rgdDataNew.map { }
|
|
|
|
rgdDataNew.forEach { newSquad ->
|
|
val oldSquad = rgdDataOld[newSquad.key]
|
|
|
|
val baseUnitPath = ((newSquad.value?.find { it.name == "squad_loadout_ext" }?.value as List<RgdData>)
|
|
.find { it.name == "trooper_base" }?.value as List<RgdData>)
|
|
.find { it.name == "type" }?.value as String
|
|
val baseUnitName = baseUnitPath.split("\\").last().replace(".lua", ".rgd")
|
|
|
|
val newUnit = rgdDataUnitsNew[baseUnitName]
|
|
val oldUnit = rgdDataUnitsOld[baseUnitName]
|
|
if(oldSquad != newSquad.value || oldUnit != newUnit){
|
|
out.println(newSquad.key.replace(".rgd", "").uppercase())
|
|
rgdService.printRgdDiff(newSquad.value, oldSquad, out = out)
|
|
if(oldSquad != newSquad.value && oldUnit != newUnit) out.println("-")
|
|
rgdService.printRgdDiff(newUnit, oldUnit, out = out)
|
|
out.println("---")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
data class UnitAsSquad(val squadData: List<RgdData>?,val uintData: List<RgdData>?)
|
|
|
|
fun getAllWeaponsDiff(out: PrintWriter) {
|
|
|
|
val wanillaRgdData = File("src/main/resources/static/mods/wanila/attrib/weapon").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
val classicRgdData = File("src/main/resources/static/mods/$prevVersion/attrib/weapon").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
val newRgdData = File("src/main/resources/static/mods/$currentVersion/attrib/weapon").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.sortedBy { it.first }
|
|
.toMap()
|
|
|
|
|
|
newRgdData.forEach {newWeapon ->
|
|
val oldWeapon = classicRgdData[newWeapon.key]
|
|
if(oldWeapon != newWeapon.value){
|
|
out.println(newWeapon.key.replace(".rgd", "").uppercase())
|
|
if(oldWeapon != null){
|
|
rgdService.printRgdDiff(newWeapon.value, oldWeapon, out = out)
|
|
}else{
|
|
out.println("NOT EXIST IN PREV VERSION")
|
|
rgdService.printRgdDiff(newWeapon.value, wanillaRgdData[newWeapon.key], out = out)
|
|
}
|
|
out.println("---")
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
fun getAllUnits(): Map<String, UnitAsSquad> {
|
|
|
|
return racesWikiPaths.map{racePath ->
|
|
|
|
val rgdData42 = File("src/main/resources/static/mods/$currentVersion/attrib/sbps/races/$racePath").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
}else{
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
val newUnits = File("src/main/resources/static/mods/$currentVersion/attrib/ebps/races/$racePath/troops").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
}else{
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
rgdData42.map {newSquad ->
|
|
|
|
val baseUnitPath = ((newSquad.value?.find { it.name == "squad_loadout_ext" }?.value as List<RgdData>)
|
|
.find { it.name == "trooper_base" }?.value as List<RgdData>)
|
|
.find { it.name == "type" }?.value as String
|
|
val baseUnitName = baseUnitPath.split("\\").last().replace(".lua", ".rgd")
|
|
|
|
baseUnitName to UnitAsSquad(newSquad.value, newUnits[baseUnitName])
|
|
}.toMap()
|
|
}.fold(emptyMap()){sum, map -> map + sum}
|
|
}
|
|
|
|
|
|
fun getWeaponRgdMap(): Map<String, List<RgdData>?> {
|
|
|
|
return File("src/main/resources/static/mods/$currentVersion/attrib/weapon").walkTopDown().map {
|
|
val rgdData = if(it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")){
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name.replace(".rgd", "") to rgdData
|
|
}.toMap()
|
|
}
|
|
|
|
@Test
|
|
fun getAllWeaponDamage() {
|
|
val weaponMap = getWeaponRgdMap()
|
|
|
|
getAllUnits().forEach {
|
|
println(it.key.replace(".rgd",""))
|
|
it.value.uintData
|
|
?.getRgdTableByName("combat_ext")
|
|
?.getRgdTableByName("hardpoints")
|
|
?.forEach { hardpoint ->
|
|
if (hardpoint.name.contains("hardpoint")) {
|
|
val hardpointWeapons = (hardpoint.value as List<RgdData>)?.getRgdTableByName("weapon_table")
|
|
?.mapNotNull { weapon ->
|
|
if (weapon.name.contains("weapon")) {
|
|
val weapon = (weapon.value as List<RgdData>).getStringByName("weapon")
|
|
if (weapon != "" && weapon?.contains("dummy_weapon") == false) {
|
|
weapon
|
|
} else null
|
|
} else null
|
|
}
|
|
|
|
if (hardpointWeapons?.isNotEmpty() == true) {
|
|
|
|
hardpointWeapons.forEach {
|
|
val weaponId = it.replace("weapon\\", "").replace(".lua", "")
|
|
println(":" + weaponId + ":")
|
|
val weaponRgd = weaponMap[weaponId]
|
|
val reloadTime: Double = weaponRgd?.getDoubleByName("reload_time")!!
|
|
val accuracy: Double = weaponRgd?.getDoubleByName("accuracy")!!
|
|
|
|
val armourDamage = weaponRgd?.getRgdTableByName("area_effect")
|
|
?.getRgdTableByName("weapon_damage")
|
|
?.getRgdTableByName("armour_damage")
|
|
|
|
val minDamage = armourDamage?.getDoubleByName("min_damage")!!
|
|
val maxDamage = armourDamage.getDoubleByName("max_damage")!!
|
|
val avgDamage = (minDamage + maxDamage) / 2
|
|
|
|
val weaponDmgMap: Map<String, Double>? =
|
|
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()?.toSortedMap()
|
|
println()
|
|
val dmgK = accuracy * (1/(reloadTime - reloadTime.mod(0.125)))
|
|
weaponDmgMap?.forEach {
|
|
val piercingK = it.value / 100
|
|
val totalDmg = piercingK * dmgK * avgDamage
|
|
print(it.key + "-" + (Math.round(totalDmg * 100.0) / 100.00).toString() + "|")
|
|
}
|
|
println()
|
|
println("-----")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
println("============================")
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
fun getAllBuildingsDiff(out: PrintWriter) {
|
|
racesWikiPaths.forEach { racePath ->
|
|
|
|
val classicRgdData =
|
|
File("src/main/resources/static/mods/$prevVersion/attrib/ebps/races/$racePath/structures").walkTopDown().map {
|
|
val rgdData = if (it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")) {
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
val newRgdData = File("src/main/resources/static/mods/$currentVersion/attrib/ebps/races/$racePath/structures").walkTopDown().map {
|
|
val rgdData = if (it.isFile && !it.name.contains("hg_dxp3") && !it.name.contains("npc")) {
|
|
rgdParseService.parseRgdFileStream(DataInputStream(it.inputStream()))
|
|
} else {
|
|
null
|
|
}
|
|
it.name to rgdData
|
|
}.filter { it.second != null }
|
|
.toMap()
|
|
|
|
|
|
newRgdData.forEach { newBuilding ->
|
|
val oldBuilding = classicRgdData[newBuilding.key]
|
|
if (oldBuilding != newBuilding.value) {
|
|
out.println(newBuilding.key.replace(".rgd", "").uppercase())
|
|
rgdService.printRgdDiff(newBuilding.value, oldBuilding, out = out)
|
|
out.println("---")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun saveAllDataToDb() {
|
|
// modParserService.saveModDataToDb()
|
|
}
|
|
|
|
@Test
|
|
fun getAllDiffAndPrintToFiles(){
|
|
val weaponDiffFileName = "$prevVersion-$currentVersion-weapons.txt"
|
|
File(weaponDiffFileName).printWriter().use { out ->
|
|
getAllWeaponsDiff(out)
|
|
}
|
|
val unitsDiffFileName = "$prevVersion-$currentVersion-units.txt"
|
|
File(unitsDiffFileName).printWriter().use { out ->
|
|
getUnitsAndSquadsDiff(out)
|
|
}
|
|
val buildingsFileName = "$prevVersion-$currentVersion-building.txt"
|
|
File(buildingsFileName).printWriter().use { out ->
|
|
getAllBuildingsDiff(out)
|
|
}
|
|
}
|
|
|
|
|
|
private fun findStrategicPointCaptureRate(rgdDataList: List<RgdData>): Double? {
|
|
val capRgdData = rgdDataList.find { it.name == "squad_capture_strategic_point_ext" }?.value as List<RgdData>?
|
|
val canCapture = capRgdData?.find { it.name == "able_to_capture" }?.value == "[1]"
|
|
val captureRate = capRgdData?.find { it.name == "capture_rate" }
|
|
return if(canCapture){
|
|
captureRate?.value as Double?
|
|
} else null
|
|
}
|
|
|
|
private fun findVisionCaptureRate(rgdDataList: List<RgdData>): Double? {
|
|
val visionRgdData = rgdDataList.find { it.name == "sight_ext" }?.value as List<RgdData>?
|
|
return visionRgdData?.find { it.name == "sight_radius" }?.value as Double?
|
|
}
|
|
|
|
private fun String.decodeHex(): ByteArray {
|
|
check(length % 2 == 0) { "Must have an even length" }
|
|
return chunked(2)
|
|
.map { it.toInt(16).toByte() }
|
|
.toByteArray()
|
|
}
|
|
|
|
private fun ByteArray.getFloat(): Float {
|
|
val buffer = ByteBuffer.wrap(this)
|
|
return buffer.float
|
|
}
|
|
|
|
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)
|
|
} |