- Add building database schema
- Add building addon database schema - Add addon modifiers and requires schema - Change weapon-entity many-to-many tables unique keys (same weapon can be in different hardpoint or positions, so unique key is unit+weapon+hardpoint+pozition) - Add building rgd extract service - Add building addons rgd extract service - Add weapon min radius, damage radius, min-max throw force - Fix bug, when same weapon not show in different slots
This commit is contained in:
parent
117186c06b
commit
3666b92626
6
pom.xml
6
pom.xml
@ -106,6 +106,12 @@
|
|||||||
<artifactId>kotlin-test</artifactId>
|
<artifactId>kotlin-test</artifactId>
|
||||||
<version>1.7.22</version>
|
<version>1.7.22</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.mockk</groupId>
|
||||||
|
<artifactId>mockk-jvm</artifactId>
|
||||||
|
<version>1.13.17</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
|
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@ -14,9 +14,11 @@ class AssetsController @Autowired constructor(
|
|||||||
val iconService: IconsService,
|
val iconService: IconsService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@GetMapping("/icon/{raceIconFolder}/{imageName}")
|
@GetMapping("/icon/{modName}/{raceIconFolder}/{imageName}")
|
||||||
fun getUnits(@PathVariable raceIconFolder: String,
|
fun getUnits(
|
||||||
|
@PathVariable modName: String,
|
||||||
|
@PathVariable raceIconFolder: String,
|
||||||
@PathVariable imageName: String,): ByteArray? {
|
@PathVariable imageName: String,): ByteArray? {
|
||||||
return iconService.returnIcon(raceIconFolder, imageName)
|
return iconService.returnIcon(modName, raceIconFolder, imageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.dowstats.controllers
|
||||||
|
|
||||||
|
import com.dowstats.data.dto.controllers.RaceBuildings
|
||||||
|
import com.dowstats.data.dto.controllers.RaceUnits
|
||||||
|
import com.dowstats.data.entities.Building
|
||||||
|
import com.dowstats.data.entities.DowUnit
|
||||||
|
import com.dowstats.data.repositories.BuildingRepository
|
||||||
|
import com.dowstats.data.repositories.UnitRepository
|
||||||
|
import com.dowstats.service.datamaps.DowBuildingMappingService
|
||||||
|
import com.dowstats.service.datamaps.DowUnitMappingService
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("api/v1/buildings")
|
||||||
|
class BuildingsController @Autowired constructor(
|
||||||
|
val dowBuildingMappingService: DowBuildingMappingService,
|
||||||
|
val buildingRepository: BuildingRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
@GetMapping("/{modId}/{raceId}")
|
||||||
|
fun getBuildingsByModAndRace(@PathVariable modId: Long,
|
||||||
|
@PathVariable raceId: String): RaceBuildings {
|
||||||
|
return dowBuildingMappingService.findBuildingsByModAndRace(modId, raceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/mod/{modId}")
|
||||||
|
fun getUnitsByMod(@PathVariable modId: Long,): List<RaceBuildings> {
|
||||||
|
return dowBuildingMappingService.findBuildingsByMod(modId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/{buildingId}")
|
||||||
|
fun getById(@PathVariable buildingId: Long): Building {
|
||||||
|
return buildingRepository.findById(buildingId).get()
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
fun removeAll() {
|
||||||
|
buildingRepository.deleteAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/main/kotlin/com/dowstats/data/dto/BuildingDataToSave.kt
Normal file
11
src/main/kotlin/com/dowstats/data/dto/BuildingDataToSave.kt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package com.dowstats.data.dto
|
||||||
|
|
||||||
|
import com.dowstats.data.entities.Building
|
||||||
|
import com.dowstats.data.entities.DowUnit
|
||||||
|
import com.dowstats.data.entities.Sergeant
|
||||||
|
import com.dowstats.data.entities.Weapon
|
||||||
|
|
||||||
|
data class BuildingDataToSave(
|
||||||
|
val building: Building,
|
||||||
|
val buildingWeapons: Set<Weapon>,
|
||||||
|
)
|
||||||
@ -4,8 +4,14 @@ import com.dowstats.data.entities.DowUnit
|
|||||||
import com.dowstats.data.entities.Sergeant
|
import com.dowstats.data.entities.Sergeant
|
||||||
import com.dowstats.data.entities.Weapon
|
import com.dowstats.data.entities.Weapon
|
||||||
|
|
||||||
|
data class WeaponsData(
|
||||||
|
val hardpoint: Int,
|
||||||
|
val hardpointOrder: Int,
|
||||||
|
val weapon: Weapon,
|
||||||
|
)
|
||||||
|
|
||||||
data class UnitDataToSave(
|
data class UnitDataToSave(
|
||||||
val unit: DowUnit,
|
val unit: DowUnit,
|
||||||
val unitWeapons: Set<Weapon>,
|
val unitWeapons: List<WeaponsData>?,
|
||||||
val sergeants: List<Pair<Sergeant, Set<Weapon>>>?,
|
val sergeants: List<Pair<Sergeant, Set<Weapon>>>?,
|
||||||
)
|
)
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.dowstats.data.dto.controllers
|
||||||
|
|
||||||
|
import com.dowstats.data.entities.Race
|
||||||
|
|
||||||
|
data class RaceBuildings(
|
||||||
|
val race: Race,
|
||||||
|
val buildings: List<BuildingDto>,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class BuildingDto(
|
||||||
|
val name: String,
|
||||||
|
val icon: String,
|
||||||
|
val id: Long,
|
||||||
|
val armourTypeName: String,
|
||||||
|
val canDetect: Boolean,
|
||||||
|
)
|
||||||
23
src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt
Normal file
23
src/main/kotlin/com/dowstats/data/entities/AddonModifiers.kt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.dowstats.data.entities
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||||
|
import jakarta.persistence.*
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "addon_modifiers")
|
||||||
|
class AddonModifiers {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
var id: Long? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "addon_id", nullable = false)
|
||||||
|
@JsonIgnore
|
||||||
|
var addon: BuildingAddon? = null
|
||||||
|
|
||||||
|
var references: String? = null
|
||||||
|
var usageType: String? = null
|
||||||
|
var value: String? = null
|
||||||
|
}
|
||||||
25
src/main/kotlin/com/dowstats/data/entities/AddonRequires.kt
Normal file
25
src/main/kotlin/com/dowstats/data/entities/AddonRequires.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package com.dowstats.data.entities
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||||
|
import jakarta.persistence.*
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "addon_requires")
|
||||||
|
class AddonRequires {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
var id: Long? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "addon_id", nullable = false)
|
||||||
|
@JsonIgnore
|
||||||
|
var addon: BuildingAddon? = null
|
||||||
|
|
||||||
|
var references: String? = null
|
||||||
|
|
||||||
|
var replaceWhenDone: Boolean = false
|
||||||
|
|
||||||
|
var value: String? = null
|
||||||
|
}
|
||||||
50
src/main/kotlin/com/dowstats/data/entities/Building.kt
Normal file
50
src/main/kotlin/com/dowstats/data/entities/Building.kt
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package com.dowstats.data.entities
|
||||||
|
|
||||||
|
import jakarta.persistence.*
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "buildings")
|
||||||
|
class Building {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
var id: Long? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "race_id", nullable = false)
|
||||||
|
var race: Race? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "armour_type_id", nullable = false)
|
||||||
|
var armorType: ArmorType? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "armour_type_2_id")
|
||||||
|
var armorType2: ArmorType? = null
|
||||||
|
|
||||||
|
var name: String? = null
|
||||||
|
var description: String? = null
|
||||||
|
var filename: String? = null
|
||||||
|
var buildCostRequisition: Double? = null
|
||||||
|
var buildCostPower: Double? = null
|
||||||
|
var buildCostPopulation: Double? = null
|
||||||
|
var buildCostFaith: Double? = null
|
||||||
|
var buildCostSouls: Double? = null
|
||||||
|
var buildCostTime: Int? = null
|
||||||
|
var health: Int? = null
|
||||||
|
var healthRegeneration: Double? = null
|
||||||
|
var sightRadius: Int? = null
|
||||||
|
var detectRadius: Int? = null
|
||||||
|
var repairMax: Int? = null
|
||||||
|
var icon: String? = null
|
||||||
|
var modId: Long? = null
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "building", cascade = [CascadeType.ALL])
|
||||||
|
var addons: MutableSet<BuildingAddon>? = null
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "building", cascade = [CascadeType.ALL])
|
||||||
|
var weapons: MutableSet<BuildingWeapon>? = null
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
38
src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt
Normal file
38
src/main/kotlin/com/dowstats/data/entities/BuildingAddon.kt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package com.dowstats.data.entities
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||||
|
import jakarta.persistence.*
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "building_addons")
|
||||||
|
class BuildingAddon {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
var id: Long? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "building_id", nullable = false)
|
||||||
|
@JsonIgnore
|
||||||
|
var building: Building? = null
|
||||||
|
|
||||||
|
var name: String? = null
|
||||||
|
var description: String? = null
|
||||||
|
var filename: String? = null
|
||||||
|
var addonCostRequisition: Double? = null
|
||||||
|
var addonCostPower: Double? = null
|
||||||
|
var addonCostPopulation: Double? = null
|
||||||
|
var addonCostFaith: Double? = null
|
||||||
|
var addonCostSouls: Double? = null
|
||||||
|
var addonCostTime: Int? = null
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
|
||||||
|
var addonModifiers: MutableSet<AddonModifiers>? = null
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
|
||||||
|
var addonRequires: MutableSet<AddonRequires>? = null
|
||||||
|
|
||||||
|
var icon: String? = null
|
||||||
|
|
||||||
|
}
|
||||||
42
src/main/kotlin/com/dowstats/data/entities/BuildingWeapon.kt
Normal file
42
src/main/kotlin/com/dowstats/data/entities/BuildingWeapon.kt
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.dowstats.data.entities
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||||
|
import jakarta.persistence.*
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
class BuildingWeaponKey : Serializable {
|
||||||
|
@Column(name = "building_id")
|
||||||
|
var buildingId: Long? = null
|
||||||
|
|
||||||
|
@Column(name = "weapon_id")
|
||||||
|
var weaponId: Long? = null
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
var hardpoint: Int = 0
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
var hardpointOrder: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "buildings_weapons")
|
||||||
|
class BuildingWeapon {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
@JsonIgnore
|
||||||
|
var buildingWeaponKey: BuildingWeaponKey? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@MapsId("buildingId")
|
||||||
|
@JoinColumn(name = "building_id")
|
||||||
|
@JsonIgnore
|
||||||
|
var building: Building? = null
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@MapsId("weaponId")
|
||||||
|
@JoinColumn(name = "weapon_id")
|
||||||
|
var weapon: Weapon? = null
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,6 +13,11 @@ class SergeantWeaponKey : Serializable {
|
|||||||
@Column(name = "weapon_id")
|
@Column(name = "weapon_id")
|
||||||
var weaponId: Long? = null
|
var weaponId: Long? = null
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
var hardpoint: Int = 0
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
var hardpointOrder: Int = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -33,11 +38,4 @@ class SergeantWeapon {
|
|||||||
@MapsId("weaponId")
|
@MapsId("weaponId")
|
||||||
@JoinColumn(name = "weapon_id")
|
@JoinColumn(name = "weapon_id")
|
||||||
var weapon: Weapon? = null
|
var weapon: Weapon? = null
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
var hardpoint: Int = 0
|
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
var hardpointOrder: Int = 0
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,12 @@ class UnitWeaponKey : Serializable {
|
|||||||
@Column(name = "weapon_id")
|
@Column(name = "weapon_id")
|
||||||
var weaponId: Long? = null
|
var weaponId: Long? = null
|
||||||
|
|
||||||
|
@Column(name = "hardpoint")
|
||||||
|
var hardpoint: Int = 0
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
var hardpointOrder: Int = 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -34,10 +40,4 @@ class UnitWeapon {
|
|||||||
@JoinColumn(name = "weapon_id")
|
@JoinColumn(name = "weapon_id")
|
||||||
var weapon: Weapon? = null
|
var weapon: Weapon? = null
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
var hardpoint: Int = 0
|
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
var hardpointOrder: Int = 0
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@ class Weapon {
|
|||||||
var costTimeSeconds: Int? = null
|
var costTimeSeconds: Int? = null
|
||||||
var accuracy: Double? = null
|
var accuracy: Double? = null
|
||||||
var reloadTime: Double? = null
|
var reloadTime: Double? = null
|
||||||
|
var minRange: Double? = null
|
||||||
var maxRange: Double? = null
|
var maxRange: Double? = null
|
||||||
var setupTime: Double? = null
|
var setupTime: Double? = null
|
||||||
var accuracyReductionMoving: Double? = null
|
var accuracyReductionMoving: Double? = null
|
||||||
@ -25,6 +26,9 @@ class Weapon {
|
|||||||
var maxDamage: Double? = null
|
var maxDamage: Double? = null
|
||||||
var minDamageValue: Double? = null
|
var minDamageValue: Double? = null
|
||||||
var moraleDamage: Double? = null
|
var moraleDamage: Double? = null
|
||||||
|
var damageRadius: Double? = null
|
||||||
|
var throwForceMin: Double? = null
|
||||||
|
var throwForceMax: Double? = null
|
||||||
var isMeleeWeapon: Boolean = true
|
var isMeleeWeapon: Boolean = true
|
||||||
var canAttackAir: Boolean = true
|
var canAttackAir: Boolean = true
|
||||||
var canAttackGround: Boolean = true
|
var canAttackGround: Boolean = true
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.dowstats.data.repositories
|
||||||
|
|
||||||
|
import com.dowstats.data.entities.Building
|
||||||
|
import com.dowstats.data.entities.BuildingAddon
|
||||||
|
import com.dowstats.data.entities.DowUnit
|
||||||
|
import com.dowstats.data.entities.Race
|
||||||
|
import org.springframework.data.jpa.repository.Query
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
|
||||||
|
interface AddonRepository : CrudRepository<BuildingAddon, Long>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.dowstats.data.repositories
|
||||||
|
|
||||||
|
import com.dowstats.data.entities.Building
|
||||||
|
import com.dowstats.data.entities.DowUnit
|
||||||
|
import com.dowstats.data.entities.Race
|
||||||
|
import org.springframework.data.jpa.repository.Query
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
|
||||||
|
interface BuildingRepository : CrudRepository<Building, Long>{
|
||||||
|
@Query("""
|
||||||
|
select b, a1, a2
|
||||||
|
from Building b
|
||||||
|
left join fetch ArmorType a1 on b.armorType.id = a1.id
|
||||||
|
left join fetch ArmorType a2 on b.armorType2.id = a2.id
|
||||||
|
where b.modId = :modId
|
||||||
|
and (:race is null or b.race = :race)
|
||||||
|
""")
|
||||||
|
fun findByModIdAndRace(modId: Long, race: Race?): List<Building>
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package com.dowstats.service.datamaps
|
||||||
|
|
||||||
|
import com.dowstats.data.dto.controllers.BuildingDto
|
||||||
|
import com.dowstats.data.dto.controllers.RaceBuildings
|
||||||
|
import com.dowstats.data.dto.controllers.RaceUnits
|
||||||
|
import com.dowstats.data.dto.controllers.UnitDto
|
||||||
|
import com.dowstats.data.entities.Building
|
||||||
|
import com.dowstats.data.entities.DowUnit
|
||||||
|
import com.dowstats.data.entities.Race
|
||||||
|
import com.dowstats.data.repositories.BuildingRepository
|
||||||
|
import com.dowstats.data.repositories.RaceRepository
|
||||||
|
import com.dowstats.data.repositories.UnitRepository
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class DowBuildingMappingService @Autowired constructor(
|
||||||
|
val buildingRepository: BuildingRepository,
|
||||||
|
val raceRepository: RaceRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun findBuildingsByMod(modId: Long): List<RaceBuildings> {
|
||||||
|
return getAllBuildings(modId).groupBy { it.race }.mapNotNull {raceUnits ->
|
||||||
|
RaceBuildings(raceUnits.key ?: 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") }
|
||||||
|
return RaceBuildings(raceEntity, buildings.toBuildingDto())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun List<Building>.toBuildingDto(): List<BuildingDto> =
|
||||||
|
this.mapNotNull {
|
||||||
|
val name = it.name ?: it.filename
|
||||||
|
val icon = it.icon
|
||||||
|
if (name == null || icon == null) null else BuildingDto(name, icon, it.id!!,
|
||||||
|
it.armorType?.name!!,
|
||||||
|
(it.detectRadius ?: 0) > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getAllBuildings(modId: Long, race: String? = null): List<Building> {
|
||||||
|
val raceEntity = race?.let{ raceRepository.findById(race) ?: throw Exception("Race $race not found") }
|
||||||
|
return filterCompanyUnits(buildingRepository.findByModIdAndRace(modId, raceEntity))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun filterCompanyUnits(buildings: List<Building>): List<Building> =
|
||||||
|
buildings.filter {
|
||||||
|
it.filename?.contains("_sp.") != true
|
||||||
|
&& it.filename?.contains("_sp_") != true
|
||||||
|
&& it.filename?.contains("sp_eldar_") != true
|
||||||
|
&& it.filename?.contains("_dxp3.") != true
|
||||||
|
&& it.filename?.contains("_dxp3_") != true
|
||||||
|
&& it.filename?.contains("_nis.") != true
|
||||||
|
&& it.filename?.contains("_exarch_council.") != true
|
||||||
|
&& it.filename?.contains("_dark_reapers_base.") != true
|
||||||
|
&& it.filename?.contains("tau_squad_slave_murdered") != true
|
||||||
|
&& it.filename?.contains("space_marine_single_player_only_drop_pod_building_2.rgd") != true
|
||||||
|
&& it.filename?.contains("space_marine_single_player_only_drop_pod_building.rgd") != true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -54,6 +54,7 @@ class ModStorageIntegrationService(
|
|||||||
.sortedBy { it.id }
|
.sortedBy { it.id }
|
||||||
|
|
||||||
newVersions.map { toSave ->
|
newVersions.map { toSave ->
|
||||||
|
try{
|
||||||
downloadAndExtractMod(toSave.technicalName, toSave.version)
|
downloadAndExtractMod(toSave.technicalName, toSave.version)
|
||||||
val savedMod = modRepository.save(Mod().also {
|
val savedMod = modRepository.save(Mod().also {
|
||||||
it.version = toSave.version
|
it.version = toSave.version
|
||||||
@ -62,6 +63,10 @@ class ModStorageIntegrationService(
|
|||||||
it.technicalName = toSave.technicalName
|
it.technicalName = toSave.technicalName
|
||||||
})
|
})
|
||||||
modParserService.parceModFilesAndSaveToDb(savedMod)
|
modParserService.parceModFilesAndSaveToDb(savedMod)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error("Error while download and extract mod", e)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,116 @@
|
|||||||
|
package com.dowstats.service.w40k
|
||||||
|
|
||||||
|
import com.dowstats.data.dto.BuildCost
|
||||||
|
import com.dowstats.data.entities.*
|
||||||
|
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 org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
|
import kotlin.io.path.exists
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class BuildingAddonRgdExtractService @Autowired constructor(
|
||||||
|
private val modAttribPathService: ModAttribPathService,
|
||||||
|
private val iconsService: IconsService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
val log = LoggerFactory.getLogger(BuildingAddonRgdExtractService::class.java)
|
||||||
|
|
||||||
|
data class AddonTexts(
|
||||||
|
val name: String?,
|
||||||
|
val description: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun extractToAddonEntity(
|
||||||
|
fileName: String,
|
||||||
|
modDictionary: Map<Int, String>,
|
||||||
|
addonRgdData: List<RgdData>,
|
||||||
|
modFolderData: String,
|
||||||
|
building: Building,
|
||||||
|
mod: Mod,
|
||||||
|
): BuildingAddon {
|
||||||
|
|
||||||
|
val addon = BuildingAddon()
|
||||||
|
|
||||||
|
val nameAndDescription = getAddonNameAndDescription(addonRgdData, modDictionary)
|
||||||
|
addon.name = nameAndDescription.name
|
||||||
|
addon.description = nameAndDescription.description
|
||||||
|
addon.building = building
|
||||||
|
addon.filename = fileName
|
||||||
|
|
||||||
|
val buildCost = getAddonCost(addonRgdData)
|
||||||
|
addon.addonCostRequisition = buildCost.requisition
|
||||||
|
addon.addonCostPower = buildCost.power
|
||||||
|
addon.addonCostPopulation = buildCost.population
|
||||||
|
addon.addonCostFaith = buildCost.faith
|
||||||
|
addon.addonCostSouls = buildCost.souls
|
||||||
|
addon.addonCostTime = buildCost.time
|
||||||
|
|
||||||
|
val addonIcon = convertIconAndReturnPath(addonRgdData, modFolderData, mod.name)
|
||||||
|
addon.icon = addonIcon
|
||||||
|
|
||||||
|
|
||||||
|
return addon
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getAddonCost(addonData: List<RgdData>): BuildCost {
|
||||||
|
|
||||||
|
val cost = addonData.getRgdTableByName("time_cost")
|
||||||
|
|
||||||
|
val costResources = cost?.getRgdTableByName("cost")
|
||||||
|
|
||||||
|
return BuildCost(
|
||||||
|
costResources?.getDoubleByName("requisition"),
|
||||||
|
costResources?.getDoubleByName("power"),
|
||||||
|
costResources?.getDoubleByName("population"),
|
||||||
|
costResources?.getDoubleByName("faith"),
|
||||||
|
costResources?.getDoubleByName("souls"),
|
||||||
|
cost?.getDoubleByName("time_seconds")?.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAddonNameAndDescription(addonData: List<RgdData>, modDictionary: Map<Int, String>): AddonTexts {
|
||||||
|
val uiInfo = addonData.getRgdTableByName("ui_info")
|
||||||
|
|
||||||
|
val nameRef = uiInfo?.getStringByName("screen_name_id")?.replace("$", "")
|
||||||
|
val name = nameRef?.let { try{modDictionary[it.toInt()]} catch (e: Exception) { null } }
|
||||||
|
|
||||||
|
val descriptionRefs = uiInfo?.getRgdTableByName("help_text_list")
|
||||||
|
?.map{(it.value as String).replace("$", "")}
|
||||||
|
?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""}
|
||||||
|
?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } }
|
||||||
|
|
||||||
|
val description = try {
|
||||||
|
descriptionRefs?.map { modDictionary[it.toInt()] }?.joinToString ( "\n" )
|
||||||
|
} catch(e:Exception) {
|
||||||
|
log.warn("Error parsing ui description", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddonTexts(name, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun convertIconAndReturnPath(buildingData: List<RgdData>, modFolderData: String, modName: String?): String? {
|
||||||
|
val iconPathInMod = buildingData
|
||||||
|
.getRgdTableByName("ui_info")
|
||||||
|
?.getStringByName("icon_name")
|
||||||
|
?.replace("/", File.separator)
|
||||||
|
|
||||||
|
|
||||||
|
val tgaIconPath = iconPathInMod?.let {
|
||||||
|
val modIcon = modAttribPathService.getIconPath(modFolderData, it)
|
||||||
|
if(Path.of(modIcon).exists()) modIcon else
|
||||||
|
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,239 @@
|
|||||||
|
package com.dowstats.service.w40k
|
||||||
|
|
||||||
|
import com.dowstats.data.dto.BuildCost
|
||||||
|
import com.dowstats.data.dto.BuildingDataToSave
|
||||||
|
import com.dowstats.data.entities.*
|
||||||
|
import com.dowstats.data.rgd.RgdData
|
||||||
|
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
|
||||||
|
import com.dowstats.data.rgd.RgdDataUtil.getIntByName
|
||||||
|
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
|
||||||
|
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
|
import kotlin.io.path.exists
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class BuildingRgdExtractService @Autowired constructor(
|
||||||
|
private val modAttribPathService: ModAttribPathService,
|
||||||
|
private val iconsService: IconsService,
|
||||||
|
private val addonRgdExtractService: BuildingAddonRgdExtractService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
val log = LoggerFactory.getLogger(BuildingRgdExtractService::class.java)
|
||||||
|
|
||||||
|
data class HealthData(
|
||||||
|
val hitpoints: Double?,
|
||||||
|
val regeneration: Double?,
|
||||||
|
val maxRepaires: Int?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class WeaponsData(
|
||||||
|
val hardpoint: Int,
|
||||||
|
val hardpointOrder: Int,
|
||||||
|
val weaponFilename: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class BuildingTexts(
|
||||||
|
val name: String?,
|
||||||
|
val description: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun extractToBuildingEntity(
|
||||||
|
fileName: String,
|
||||||
|
modDictionary: Map<Int, String>,
|
||||||
|
buildingData: List<RgdData>,
|
||||||
|
weapons: Set<Weapon>,
|
||||||
|
race: String,
|
||||||
|
modFolderData: String,
|
||||||
|
mod: Mod,
|
||||||
|
races: List<Race>,
|
||||||
|
armorTypes: List<ArmorType>,
|
||||||
|
addonsRgdData: Map<String, List<RgdData>>,
|
||||||
|
): BuildingDataToSave {
|
||||||
|
|
||||||
|
val building = Building()
|
||||||
|
val race = races.find { it.id == race } ?: throw Exception("Cant get race $race")
|
||||||
|
|
||||||
|
building.race = race
|
||||||
|
building.armorType = getBuildingArmourType(buildingData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type")
|
||||||
|
building.armorType2 = getBuildingArmourType(buildingData, armorTypes, "type_armour_2")
|
||||||
|
|
||||||
|
val nameAndDescription = getBuildingNameAndDescription(buildingData, modDictionary)
|
||||||
|
building.name = nameAndDescription.name
|
||||||
|
building.description = nameAndDescription.description
|
||||||
|
building.filename = fileName
|
||||||
|
|
||||||
|
val buildCost = getBuildCost(buildingData)
|
||||||
|
building.buildCostRequisition = buildCost.requisition
|
||||||
|
building.buildCostPower = buildCost.power
|
||||||
|
building.buildCostPopulation = buildCost.population
|
||||||
|
building.buildCostFaith = buildCost.faith
|
||||||
|
building.buildCostSouls = buildCost.souls
|
||||||
|
building.buildCostTime = buildCost.time
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val healthData = getHealthData(buildingData)
|
||||||
|
building.health = healthData.hitpoints?.toInt()
|
||||||
|
building.healthRegeneration = healthData.regeneration
|
||||||
|
|
||||||
|
building.sightRadius = getSightRadius(buildingData)?.toInt()
|
||||||
|
building.detectRadius = getDetectRadius(buildingData)?.toInt()
|
||||||
|
|
||||||
|
building.repairMax = healthData.maxRepaires
|
||||||
|
|
||||||
|
val addons = getAddons(buildingData)
|
||||||
|
building.addons = addons?.mapNotNull {addonFileName ->
|
||||||
|
val addonRgdData = addonsRgdData[addonFileName]
|
||||||
|
if(addonRgdData != null){
|
||||||
|
addonRgdExtractService.extractToAddonEntity(addonFileName, modDictionary, addonRgdData, modFolderData, building, mod)
|
||||||
|
} else {
|
||||||
|
log.warn("Can't find addon $addonFileName")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}?.toMutableSet()
|
||||||
|
|
||||||
|
val buildingIcon = convertIconAndReturnPath(buildingData, modFolderData, mod.name)
|
||||||
|
building.icon = buildingIcon
|
||||||
|
|
||||||
|
val buildingWeapons = getBuildingWeapon(buildingData)?.mapNotNull { weaponData ->
|
||||||
|
weapons.find {
|
||||||
|
it.filename == weaponData.weaponFilename + ".rgd"
|
||||||
|
}.also {
|
||||||
|
it?.hardpoint = weaponData.hardpoint
|
||||||
|
it?.hardpointOrder = weaponData.hardpointOrder
|
||||||
|
}
|
||||||
|
}.orEmpty().toSet()
|
||||||
|
|
||||||
|
building.modId = mod.id
|
||||||
|
|
||||||
|
return BuildingDataToSave(building, buildingWeapons)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getBuildingArmourType(
|
||||||
|
unitData: List<RgdData>,
|
||||||
|
armorTypes: Iterable<ArmorType>,
|
||||||
|
armorTypeTableName: String
|
||||||
|
): ArmorType? {
|
||||||
|
val armorType = unitData.getRgdTableByName("type_ext")
|
||||||
|
?.getRgdTableByName(armorTypeTableName)
|
||||||
|
?.getStringByName("\$REF")
|
||||||
|
|
||||||
|
return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBuildCost(buildingData: List<RgdData>): BuildCost {
|
||||||
|
|
||||||
|
val cost = buildingData.getRgdTableByName("cost_ext")
|
||||||
|
?.getRgdTableByName("time_cost")
|
||||||
|
|
||||||
|
val costResources = cost?.getRgdTableByName("cost")
|
||||||
|
|
||||||
|
return BuildCost(
|
||||||
|
costResources?.getDoubleByName("requisition"),
|
||||||
|
costResources?.getDoubleByName("power"),
|
||||||
|
costResources?.getDoubleByName("population"),
|
||||||
|
costResources?.getDoubleByName("faith"),
|
||||||
|
costResources?.getDoubleByName("souls"),
|
||||||
|
cost?.getDoubleByName("time_seconds")?.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBuildingNameAndDescription(buildingData: List<RgdData>, modDictionary: Map<Int, String>): BuildingTexts {
|
||||||
|
val uiInfo = buildingData.getRgdTableByName("ui_ext")
|
||||||
|
?.getRgdTableByName("ui_info")
|
||||||
|
|
||||||
|
val nameRef = uiInfo?.getStringByName("screen_name_id")?.replace("$", "")
|
||||||
|
val name = nameRef?.let { try{modDictionary[it.toInt()]} catch (e: Exception) { null } }
|
||||||
|
|
||||||
|
val descriptionRefs = uiInfo?.getRgdTableByName("help_text_list")
|
||||||
|
?.map{(it.value as String).replace("$", "")}
|
||||||
|
?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""}
|
||||||
|
?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } }
|
||||||
|
|
||||||
|
val description = try {
|
||||||
|
descriptionRefs?.map { modDictionary[it.toInt()] }?.joinToString ( "\n" )
|
||||||
|
} catch(e:Exception) {
|
||||||
|
log.warn("Error parsing ui description", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
return BuildingTexts(name, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHealthData(buildingData: List<RgdData>): HealthData {
|
||||||
|
val healthExt = buildingData.getRgdTableByName("health_ext")
|
||||||
|
return HealthData(
|
||||||
|
healthExt?.getDoubleByName("hitpoints"),
|
||||||
|
healthExt?.getDoubleByName("regeneration_rate"),
|
||||||
|
healthExt?.getIntByName("max_repairers")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getSightRadius(unitData: List<RgdData>): Double? = unitData
|
||||||
|
.getRgdTableByName("sight_ext")
|
||||||
|
?.getDoubleByName("sight_radius")
|
||||||
|
|
||||||
|
private fun getDetectRadius(unitData: List<RgdData>): Double? = unitData
|
||||||
|
.getRgdTableByName("sight_ext")
|
||||||
|
?.getDoubleByName("keen_sight_radius")
|
||||||
|
|
||||||
|
|
||||||
|
private fun getBuildingWeapon(buildingData: List<RgdData>?): List<WeaponsData>? = buildingData
|
||||||
|
?.getRgdTableByName("combat_ext")
|
||||||
|
?.getRgdTableByName("hardpoints")
|
||||||
|
?.mapNotNull { hardpoint ->
|
||||||
|
if (hardpoint.name.contains("hardpoint_")) {
|
||||||
|
val hardpointValue = hardpoint.name.replace("hardpoint_", "").toInt()
|
||||||
|
val hardpointTable = hardpoint.value as List<RgdData>
|
||||||
|
hardpointTable.getRgdTableByName("weapon_table")?.let {
|
||||||
|
it.mapNotNull { weapon ->
|
||||||
|
(weapon.value as? List<RgdData>)?.getStringByName("weapon")?.let {
|
||||||
|
if (it != "") {
|
||||||
|
WeaponsData(hardpointValue,
|
||||||
|
weapon.name.replace("weapon_", "").toInt(),
|
||||||
|
it.replace("weapon\\", "").replace(".lua", ""))
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
}?.flatten()
|
||||||
|
|
||||||
|
|
||||||
|
private fun convertIconAndReturnPath(buildingData: List<RgdData>, modFolderData: String, modName: String?): String? {
|
||||||
|
val iconPathInMod = buildingData
|
||||||
|
.getRgdTableByName("ui_ext")
|
||||||
|
?.getRgdTableByName("ui_info")
|
||||||
|
?.getStringByName("icon_name")
|
||||||
|
?.replace("/", File.separator)
|
||||||
|
|
||||||
|
|
||||||
|
val tgaIconPath = iconPathInMod?.let {
|
||||||
|
val modIcon = modAttribPathService.getIconPath(modFolderData, it)
|
||||||
|
if(Path.of(modIcon).exists()) modIcon else
|
||||||
|
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getAddons(buildingData: List<RgdData>): List<String>? = buildingData
|
||||||
|
.getRgdTableByName("addon_ext")
|
||||||
|
?.getRgdTableByName("addons")
|
||||||
|
?.mapNotNull { addon ->
|
||||||
|
if (addon.value != "") {
|
||||||
|
addon.value.toString()
|
||||||
|
.replace("addons\\", "")
|
||||||
|
.replace(".lua", "")
|
||||||
|
.plus(".rgd")
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class IconsService @Autowired constructor(
|
|||||||
* @param pathToTgaIcon - путь до иконки
|
* @param pathToTgaIcon - путь до иконки
|
||||||
* @return путь до сконвертированной иконки
|
* @return путь до сконвертированной иконки
|
||||||
*/
|
*/
|
||||||
fun convertTgaToJpegImage(iconPathInMod: String, pathToTgaIcon: String): String? {
|
fun convertTgaToJpegImage(iconPathInMod: String, pathToTgaIcon: String, modName: String? = null): String? {
|
||||||
try{
|
try{
|
||||||
val image: BufferedImage = try {
|
val image: BufferedImage = try {
|
||||||
ImageIO.read(File(pathToTgaIcon))
|
ImageIO.read(File(pathToTgaIcon))
|
||||||
@ -28,7 +28,10 @@ class IconsService @Autowired constructor(
|
|||||||
ImageIO.read(File(pathToTgaIcon.lowercase()))
|
ImageIO.read(File(pathToTgaIcon.lowercase()))
|
||||||
}
|
}
|
||||||
|
|
||||||
val pathToSave = "${storageConfig.iconsStorage.replace("/", File.separator)}${File.separator}${iconPathInMod.replace("\\", File.separator)}.png"
|
val modFolder = modName?.let { "${File.separator}$modName" } ?: ""
|
||||||
|
|
||||||
|
val pathToSave = "${storageConfig.iconsStorage.replace("/", File.separator)}$modFolder" +
|
||||||
|
"${File.separator}${iconPathInMod.replace("\\", File.separator)}.png"
|
||||||
|
|
||||||
val directoryToSave = File(pathToSave.split(File.separator).dropLast(1).joinToString (File.separator))
|
val directoryToSave = File(pathToSave.split(File.separator).dropLast(1).joinToString (File.separator))
|
||||||
if(!directoryToSave.exists()) directoryToSave.mkdirs()
|
if(!directoryToSave.exists()) directoryToSave.mkdirs()
|
||||||
@ -45,8 +48,8 @@ class IconsService @Autowired constructor(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun returnIcon(raceIconFolder: String, iconName: String): ByteArray? {
|
fun returnIcon(modName: String, raceIconFolder: String, iconName: String): ByteArray? {
|
||||||
val pathToIcon = "${storageConfig.iconsStorage.replace("/", File.separator)}${File.separator}$raceIconFolder${File.separator}$iconName"
|
val pathToIcon = "${storageConfig.iconsStorage.replace("/", File.separator)}${File.separator}$modName${File.separator}$raceIconFolder${File.separator}$iconName"
|
||||||
return File(pathToIcon).readBytes()
|
return File(pathToIcon).readBytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,9 @@ class ModAttribPathService @Autowired constructor(
|
|||||||
fun getWeaponAttribsPath(modFolderData: String): String =
|
fun getWeaponAttribsPath(modFolderData: String): String =
|
||||||
"$modFolderData${File.separator}attrib${File.separator}weapon"
|
"$modFolderData${File.separator}attrib${File.separator}weapon"
|
||||||
|
|
||||||
|
fun getAddonAttribsPath(modFolderData: String): String =
|
||||||
|
"$modFolderData${File.separator}attrib${File.separator}addons"
|
||||||
|
|
||||||
fun getSbpsAttribsFolderPath(modFolderData: String): String =
|
fun getSbpsAttribsFolderPath(modFolderData: String): String =
|
||||||
"$modFolderData${File.separator}attrib${File.separator}sbps${File.separator}races${File.separator}"
|
"$modFolderData${File.separator}attrib${File.separator}sbps${File.separator}races${File.separator}"
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,8 @@ class ModParserService @Autowired constructor(
|
|||||||
val weaponRgdExtractService: WeaponRgdExtractService,
|
val weaponRgdExtractService: WeaponRgdExtractService,
|
||||||
val weaponRepository: WeaponRepository,
|
val weaponRepository: WeaponRepository,
|
||||||
val modAttribPathService: ModAttribPathService,
|
val modAttribPathService: ModAttribPathService,
|
||||||
|
val buildingRepository: BuildingRepository,
|
||||||
|
val buildingExtractService: BuildingRgdExtractService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val defaultDictionary: MutableMap<Int, String> = mutableMapOf()
|
val defaultDictionary: MutableMap<Int, String> = mutableMapOf()
|
||||||
@ -53,8 +55,6 @@ class ModParserService @Autowired constructor(
|
|||||||
|
|
||||||
log.info("Start parse mod files ${mod.technicalName}:${mod.version}")
|
log.info("Start parse mod files ${mod.technicalName}:${mod.version}")
|
||||||
|
|
||||||
val modId = mod.id!!
|
|
||||||
|
|
||||||
val modFolderData = modAttribPathService.getModFolderData(mod.technicalName!!, mod.version!!)
|
val modFolderData = modAttribPathService.getModFolderData(mod.technicalName!!, mod.version!!)
|
||||||
val racesList = Files.walk(Path(modAttribPathService.getSbpsAttribsFolderPath(modFolderData)), 1)
|
val racesList = Files.walk(Path(modAttribPathService.getSbpsAttribsFolderPath(modFolderData)), 1)
|
||||||
.toList()
|
.toList()
|
||||||
@ -62,10 +62,9 @@ class ModParserService @Autowired constructor(
|
|||||||
.filter { Files.isDirectory(it) }.map { it.name }.toList()
|
.filter { Files.isDirectory(it) }.map { it.name }.toList()
|
||||||
|
|
||||||
racesList.forEach{
|
racesList.forEach{
|
||||||
unitRepository.deleteAllByModIdAndRaceId(modId, it)
|
unitRepository.deleteAllByModIdAndRaceId(mod.id!!, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val modDictionary: MutableMap<Int, String> = mutableMapOf()
|
val modDictionary: MutableMap<Int, String> = mutableMapOf()
|
||||||
|
|
||||||
log.info("Extract dictionaries from $modFolderData")
|
log.info("Extract dictionaries from $modFolderData")
|
||||||
@ -73,7 +72,10 @@ class ModParserService @Autowired constructor(
|
|||||||
it.bufferedReader(Charsets.UTF_8).lines().forEach {
|
it.bufferedReader(Charsets.UTF_8).lines().forEach {
|
||||||
val kv = it.split("\\s+".toRegex())
|
val kv = it.split("\\s+".toRegex())
|
||||||
if (kv.size < 2) return@forEach
|
if (kv.size < 2) return@forEach
|
||||||
val key = kv.first().filter { it.isDigit() }.toInt()
|
val key = try {kv.first().filter { it.isDigit() }.toInt()} catch(e: Exception) {
|
||||||
|
log.warn("Cant' get key ${kv.first()} for dict")
|
||||||
|
0
|
||||||
|
}
|
||||||
val value = kv.drop(1).joinToString(" ").replace("\u0000","")
|
val value = kv.drop(1).joinToString(" ").replace("\u0000","")
|
||||||
modDictionary[key] = value
|
modDictionary[key] = value
|
||||||
}
|
}
|
||||||
@ -81,25 +83,20 @@ class ModParserService @Autowired constructor(
|
|||||||
|
|
||||||
val enrichedModDictionary = modDictionary + defaultDictionary
|
val enrichedModDictionary = modDictionary + defaultDictionary
|
||||||
|
|
||||||
val weapons = saveWeapons(modFolderData, modId, enrichedModDictionary)
|
val weapons = saveWeapons(modFolderData, mod, enrichedModDictionary)
|
||||||
saveUnits(modFolderData, weapons, racesList, modId, enrichedModDictionary)
|
saveUnits(modFolderData, weapons, racesList, mod, enrichedModDictionary)
|
||||||
|
|
||||||
|
saveBuildings(modFolderData, weapons, racesList, mod, enrichedModDictionary)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveUnits(modFolderData: String, weapons: Set<Weapon>, racesList: List<String>, modId: Long, modDictionary: Map<Int, String>) {
|
fun saveUnits(modFolderData: String, weapons: Set<Weapon>, racesList: List<String>, mod: Mod, modDictionary: Map<Int, String>) {
|
||||||
|
|
||||||
val races = raceRepository.findAll().toList()
|
val races = raceRepository.findAll().toList()
|
||||||
val armorTypes = armorTypeRepository.findAll().toList()
|
val armorTypes = armorTypeRepository.findAll().toList()
|
||||||
|
|
||||||
racesList.forEach { raceFolder ->
|
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 =
|
val classicRgdDataSquads =
|
||||||
rgdParserService.parseFolderToRgdFiles(modAttribPathService.getSbpsAttribsPath(modAttribPathService.pathToWanilaData, raceFolder))
|
rgdParserService.parseFolderToRgdFiles(modAttribPathService.getSbpsAttribsPath(modAttribPathService.pathToWanilaData, raceFolder))
|
||||||
val modRgdDataSquads =
|
val modRgdDataSquads =
|
||||||
@ -136,7 +133,7 @@ class ModParserService @Autowired constructor(
|
|||||||
weapons,
|
weapons,
|
||||||
raceFolder,
|
raceFolder,
|
||||||
modFolderData,
|
modFolderData,
|
||||||
modId,
|
mod,
|
||||||
races,
|
races,
|
||||||
armorTypes,
|
armorTypes,
|
||||||
modUnitsFull
|
modUnitsFull
|
||||||
@ -148,18 +145,18 @@ class ModParserService @Autowired constructor(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val unit = unitRepository.save(unitDataToSave.unit)
|
val unit = unitRepository.save(unitDataToSave.unit)
|
||||||
unit.weapons = unitDataToSave.unitWeapons.map {weapon ->
|
unit.weapons = unitDataToSave.unitWeapons?.map {weapon ->
|
||||||
UnitWeapon().also {
|
UnitWeapon().also {
|
||||||
it.unit = unit
|
it.unit = unit
|
||||||
it.weapon = weapon
|
it.weapon = weapon.weapon
|
||||||
it.hardpoint = weapon.hardpoint
|
|
||||||
it.hardpointOrder = weapon.hardpointOrder
|
|
||||||
it.unitWeaponKey = UnitWeaponKey().also {
|
it.unitWeaponKey = UnitWeaponKey().also {
|
||||||
it.unitId = unit.id
|
it.unitId = unit.id
|
||||||
it.weaponId = weapon.id
|
it.weaponId = weapon.weapon?.id
|
||||||
|
it.hardpoint = weapon.hardpoint
|
||||||
|
it.hardpointOrder = weapon.hardpointOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.toMutableSet()
|
}?.toMutableSet()
|
||||||
unitRepository.save(unit)
|
unitRepository.save(unit)
|
||||||
|
|
||||||
|
|
||||||
@ -171,11 +168,12 @@ class ModParserService @Autowired constructor(
|
|||||||
SergeantWeapon().also {
|
SergeantWeapon().also {
|
||||||
it.sergeant = sergeant
|
it.sergeant = sergeant
|
||||||
it.weapon = weapon
|
it.weapon = weapon
|
||||||
it.hardpoint = weapon.hardpoint
|
|
||||||
it.hardpointOrder = weapon.hardpointOrder
|
|
||||||
it.sergeantWeaponKey = SergeantWeaponKey().also { swk ->
|
it.sergeantWeaponKey = SergeantWeaponKey().also { swk ->
|
||||||
swk.sergeantId = sergeant.id
|
swk.sergeantId = sergeant.id
|
||||||
swk.weaponId = weapon.id
|
swk.weaponId = weapon.id
|
||||||
|
swk.hardpoint = weapon.hardpoint
|
||||||
|
swk.hardpointOrder = weapon.hardpointOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.toMutableSet()
|
}.toMutableSet()
|
||||||
@ -188,7 +186,80 @@ class ModParserService @Autowired constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveWeapons(modFolderData: String, modId: Long, modDictionary: Map<Int, String>): Set<Weapon> {
|
fun saveBuildings(modFolderData: String,
|
||||||
|
weapons: Set<Weapon>,
|
||||||
|
racesList: List<String>,
|
||||||
|
mod: Mod, modDictionary: Map<Int, String>) {
|
||||||
|
|
||||||
|
val races = raceRepository.findAll().toList()
|
||||||
|
val armorTypes = armorTypeRepository.findAll().toList()
|
||||||
|
|
||||||
|
val addonsRgdData = getAddonsRgdData(modFolderData)
|
||||||
|
|
||||||
|
racesList.forEach { raceFolder ->
|
||||||
|
val classicRgdDataStructures =
|
||||||
|
rgdParserService.parseFolderToRgdFiles(modAttribPathService.geBuildingAttribsPath(modAttribPathService.pathToWanilaData, raceFolder))
|
||||||
|
val modRgdDataStructures =
|
||||||
|
rgdParserService.parseFolderToRgdFiles(modAttribPathService.geBuildingAttribsPath(modFolderData, raceFolder))
|
||||||
|
|
||||||
|
val modStructuresFull = classicRgdDataStructures + modRgdDataStructures
|
||||||
|
|
||||||
|
modStructuresFull.forEach { structure ->
|
||||||
|
val structureDataToSave =
|
||||||
|
try {
|
||||||
|
buildingExtractService.extractToBuildingEntity(
|
||||||
|
structure.key,
|
||||||
|
modDictionary,
|
||||||
|
structure.value,
|
||||||
|
weapons,
|
||||||
|
raceFolder,
|
||||||
|
modFolderData,
|
||||||
|
mod,
|
||||||
|
races,
|
||||||
|
armorTypes,
|
||||||
|
addonsRgdData,
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error("Can't extract ${structure.key}", e)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val building = buildingRepository.save(structureDataToSave.building)
|
||||||
|
building.weapons = structureDataToSave.buildingWeapons.map {weapon ->
|
||||||
|
BuildingWeapon().also {
|
||||||
|
it.building = building
|
||||||
|
it.weapon = weapon
|
||||||
|
it.buildingWeaponKey = BuildingWeaponKey().also {
|
||||||
|
it.buildingId = building.id
|
||||||
|
it.weaponId = weapon.id
|
||||||
|
it.hardpoint = weapon.hardpoint
|
||||||
|
it.hardpointOrder = weapon.hardpointOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toMutableSet()
|
||||||
|
buildingRepository.save(building)
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAddonsRgdData(modFolderData: String): Map<String, List<RgdData>> {
|
||||||
|
|
||||||
|
val classicAddons = rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/addons")
|
||||||
|
|
||||||
|
val modAddons =
|
||||||
|
rgdParserService.parseFolderToRgdFiles(modAttribPathService.getAddonAttribsPath(modFolderData))
|
||||||
|
|
||||||
|
return classicAddons + modAddons
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveWeapons(modFolderData: String, mod: Mod, modDictionary: Map<Int, String>): Set<Weapon> {
|
||||||
|
|
||||||
val classicWeapons = rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/weapon")
|
val classicWeapons = rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/weapon")
|
||||||
|
|
||||||
@ -198,7 +269,7 @@ class ModParserService @Autowired constructor(
|
|||||||
val allWeapons = classicWeapons + modWeapons
|
val allWeapons = classicWeapons + modWeapons
|
||||||
|
|
||||||
val weaponsToSave = allWeapons.mapNotNull {
|
val weaponsToSave = allWeapons.mapNotNull {
|
||||||
weaponRgdExtractService.extractToWeaponEntity(it.key, it.value, modId, modFolderData, modDictionary)
|
weaponRgdExtractService.extractToWeaponEntity(it.key, it.value, mod, modFolderData, modDictionary)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
|
|||||||
@ -48,6 +48,7 @@ class SergeantRgdExtractService @Autowired constructor(
|
|||||||
fun extractToSergeantEntity(
|
fun extractToSergeantEntity(
|
||||||
fileName: String,
|
fileName: String,
|
||||||
modDictionary: Map<Int, String>,
|
modDictionary: Map<Int, String>,
|
||||||
|
mod: Mod,
|
||||||
sergeantData: List<RgdData>,
|
sergeantData: List<RgdData>,
|
||||||
weapons: Set<Weapon>,
|
weapons: Set<Weapon>,
|
||||||
modFolderData: String,
|
modFolderData: String,
|
||||||
@ -84,7 +85,7 @@ class SergeantRgdExtractService @Autowired constructor(
|
|||||||
sergeant.mass = massData.mass
|
sergeant.mass = massData.mass
|
||||||
sergeant.upTime = massData.upTime
|
sergeant.upTime = massData.upTime
|
||||||
|
|
||||||
val unitIcon = convertSergeantIconAndReturnPath(sergeantData, modFolderData)
|
val unitIcon = convertSergeantIconAndReturnPath(sergeantData, modFolderData, mod.name)
|
||||||
sergeant.icon = unitIcon
|
sergeant.icon = unitIcon
|
||||||
|
|
||||||
val sergeantWeapons = getSergeantWeapons(sergeantData)?.mapNotNull { weaponData ->
|
val sergeantWeapons = getSergeantWeapons(sergeantData)?.mapNotNull { weaponData ->
|
||||||
@ -183,7 +184,7 @@ class SergeantRgdExtractService @Autowired constructor(
|
|||||||
} else null
|
} else null
|
||||||
}?.flatten()
|
}?.flatten()
|
||||||
|
|
||||||
private fun convertSergeantIconAndReturnPath(sergeantData: List<RgdData>, modFolderData: String): String? {
|
private fun convertSergeantIconAndReturnPath(sergeantData: List<RgdData>, modFolderData: String, modName: String?): String? {
|
||||||
val iconPathInMod = sergeantData
|
val iconPathInMod = sergeantData
|
||||||
.getRgdTableByName("ui_ext")
|
.getRgdTableByName("ui_ext")
|
||||||
?.getRgdTableByName("ui_info")
|
?.getRgdTableByName("ui_info")
|
||||||
@ -197,7 +198,7 @@ class SergeantRgdExtractService @Autowired constructor(
|
|||||||
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it) }
|
return tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.dowstats.service.w40k
|
|||||||
|
|
||||||
import com.dowstats.data.dto.BuildCost
|
import com.dowstats.data.dto.BuildCost
|
||||||
import com.dowstats.data.dto.UnitDataToSave
|
import com.dowstats.data.dto.UnitDataToSave
|
||||||
|
import com.dowstats.data.dto.WeaponsData
|
||||||
import com.dowstats.data.entities.*
|
import com.dowstats.data.entities.*
|
||||||
import com.dowstats.data.rgd.RgdData
|
import com.dowstats.data.rgd.RgdData
|
||||||
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
|
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
|
||||||
@ -36,12 +37,6 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
val regeneration: Double?,
|
val regeneration: Double?,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class WeaponsData(
|
|
||||||
val hardpoint: Int,
|
|
||||||
val hardpointOrder: Int,
|
|
||||||
val weaponFilename: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class SergeantData(
|
data class SergeantData(
|
||||||
val filePath: String,
|
val filePath: String,
|
||||||
val cost: BuildCost,
|
val cost: BuildCost,
|
||||||
@ -65,7 +60,7 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
weapons: Set<Weapon>,
|
weapons: Set<Weapon>,
|
||||||
race: String,
|
race: String,
|
||||||
modFolderData: String,
|
modFolderData: String,
|
||||||
modId: Long,
|
mod: Mod,
|
||||||
races: List<Race>,
|
races: List<Race>,
|
||||||
armorTypes: List<ArmorType>,
|
armorTypes: List<ArmorType>,
|
||||||
modUnitsFull: Map<String, List<RgdData>>,
|
modUnitsFull: Map<String, List<RgdData>>,
|
||||||
@ -131,10 +126,11 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
val sergeantsEntities: List<Pair<Sergeant, Set<Weapon>>>? = sergeantsData.first?.mapNotNull { sergeantData ->
|
val sergeantsEntities: List<Pair<Sergeant, Set<Weapon>>>? = sergeantsData.first?.mapNotNull { sergeantData ->
|
||||||
val sergeantFile = sergeantData.filePath.split("\\").last().replace(".lua", ".rgd")
|
val sergeantFile = sergeantData.filePath.split("\\").last().replace(".lua", ".rgd")
|
||||||
val sergeantRgdData = modUnitsFull[sergeantFile]
|
val sergeantRgdData = modUnitsFull[sergeantFile]
|
||||||
if(sergeantRgdData != null){
|
if (sergeantRgdData != null) {
|
||||||
sergeantRgdExtractService.extractToSergeantEntity(
|
sergeantRgdExtractService.extractToSergeantEntity(
|
||||||
sergeantFile,
|
sergeantFile,
|
||||||
modDictionary,
|
modDictionary,
|
||||||
|
mod,
|
||||||
sergeantRgdData,
|
sergeantRgdData,
|
||||||
weapons,
|
weapons,
|
||||||
modFolderData,
|
modFolderData,
|
||||||
@ -146,19 +142,12 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
|
|
||||||
unit.maxSergeants = sergeantsData.second
|
unit.maxSergeants = sergeantsData.second
|
||||||
|
|
||||||
val unitIcon = convertIconAndReturnPath(squadData, modFolderData)
|
val unitIcon = convertIconAndReturnPath(mod.name, squadData, modFolderData)
|
||||||
unit.icon = unitIcon
|
unit.icon = unitIcon
|
||||||
|
|
||||||
val unitWeapons = getUnitWeapons(unitData)?.mapNotNull { weaponData ->
|
val unitWeapons = getUnitWeapons(unitData, weapons)
|
||||||
weapons.find {
|
|
||||||
it.filename == weaponData.weaponFilename + ".rgd"
|
|
||||||
}.also {
|
|
||||||
it?.hardpoint = weaponData.hardpoint
|
|
||||||
it?.hardpointOrder = weaponData.hardpointOrder
|
|
||||||
}
|
|
||||||
}.orEmpty().toSet()
|
|
||||||
|
|
||||||
unit.modId = modId
|
unit.modId = mod.id
|
||||||
|
|
||||||
return UnitDataToSave(unit, unitWeapons, sergeantsEntities)
|
return UnitDataToSave(unit, unitWeapons, sergeantsEntities)
|
||||||
}
|
}
|
||||||
@ -212,16 +201,28 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
|
|
||||||
|
|
||||||
val nameRef = uiInfo?.getStringByName("screen_name_id")?.replace("$", "")
|
val nameRef = uiInfo?.getStringByName("screen_name_id")?.replace("$", "")
|
||||||
val name = nameRef?.let { try{modDictionary[it.toInt()]} catch (e: Exception) { null } }
|
val name = nameRef?.let {
|
||||||
|
try {
|
||||||
|
modDictionary[it.toInt()]
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val descriptionRefs = uiInfo?.getRgdTableByName("help_text_list")
|
val descriptionRefs = uiInfo?.getRgdTableByName("help_text_list")
|
||||||
?.map{(it.value as String).replace("$", "")}
|
?.map { (it.value as String).replace("$", "") }
|
||||||
?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""}
|
?.filter { it != "0" && it != "tables\\text_table.lua" && it != "" }
|
||||||
?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } }
|
?.sortedBy {
|
||||||
|
try {
|
||||||
|
it.toInt()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val description = try {
|
val description = try {
|
||||||
descriptionRefs?.map { modDictionary[it.toInt()] }?.joinToString ( "\n" )
|
descriptionRefs?.map { modDictionary[it.toInt()] }?.joinToString("\n")
|
||||||
} catch(e:Exception) {
|
} catch (e: Exception) {
|
||||||
log.warn("Error parsing ui description", e)
|
log.warn("Error parsing ui description", e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@ -321,20 +322,34 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
private fun getReinforceTime(reinforceData: List<RgdData>?): Int? = reinforceData
|
private fun getReinforceTime(reinforceData: List<RgdData>?): Int? = reinforceData
|
||||||
?.getIntByName("time_seconds")
|
?.getIntByName("time_seconds")
|
||||||
|
|
||||||
private fun getUnitWeapons(reinforceData: List<RgdData>?): List<WeaponsData>? = reinforceData
|
private fun getUnitWeapons(reinforceData: List<RgdData>?, weapons: Set<Weapon>): List<WeaponsData>? = reinforceData
|
||||||
?.getRgdTableByName("combat_ext")
|
?.getRgdTableByName("combat_ext")
|
||||||
?.getRgdTableByName("hardpoints")
|
?.getRgdTableByName("hardpoints")
|
||||||
?.mapNotNull { hardpoint ->
|
?.mapNotNull { hardpoint ->
|
||||||
if (hardpoint.name.contains("hardpoint_")) {
|
if (hardpoint.name.contains("hardpoint_")) {
|
||||||
val hardpointValue = hardpoint.name.replace("hardpoint_", "").toInt()
|
val hardpointValue = hardpoint.name.replace("hardpoint_", "").toInt()
|
||||||
val hardpointTable = hardpoint.value as List<RgdData>
|
val hardpointTable = hardpoint.value as List<RgdData>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hardpointTable.getRgdTableByName("weapon_table")?.let {
|
hardpointTable.getRgdTableByName("weapon_table")?.let {
|
||||||
it.mapNotNull { weapon ->
|
it.mapNotNull { weapon ->
|
||||||
(weapon.value as? List<RgdData>)?.getStringByName("weapon")?.let {
|
(weapon.value as? List<RgdData>)?.getStringByName("weapon")?.let {
|
||||||
if (it != "") {
|
if (it != "") {
|
||||||
WeaponsData(hardpointValue,
|
val weaponFileName = it.replace("weapon\\", "").replace(".lua", ".rgd")
|
||||||
|
val weaponEntity = weapons.find {
|
||||||
|
it.filename == weaponFileName
|
||||||
|
}
|
||||||
|
if(weaponEntity == null){
|
||||||
|
log.warn("Can't find weapon $weaponFileName")
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
WeaponsData(
|
||||||
|
hardpointValue,
|
||||||
weapon.name.replace("weapon_", "").toInt(),
|
weapon.name.replace("weapon_", "").toInt(),
|
||||||
it.replace("weapon\\", "").replace(".lua", ""))
|
weaponEntity
|
||||||
|
)
|
||||||
|
}
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,12 +370,13 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
|
|
||||||
val sergeantLeaderFilePath = sergeantRgdTable.getRgdTableByName("leader")?.getStringByName("type")
|
val sergeantLeaderFilePath = sergeantRgdTable.getRgdTableByName("leader")?.getStringByName("type")
|
||||||
|
|
||||||
if(sergeantLeaderFilePath == null || sergeantLeaderFilePath == "") null else {
|
if (sergeantLeaderFilePath == null || sergeantLeaderFilePath == "") null else {
|
||||||
|
|
||||||
val cost = sergeantRgdTable.getRgdTableByName("cost_time")
|
val cost = sergeantRgdTable.getRgdTableByName("cost_time")
|
||||||
val costResources = cost?.getRgdTableByName("cost")
|
val costResources = cost?.getRgdTableByName("cost")
|
||||||
|
|
||||||
SergeantData(sergeantLeaderFilePath,
|
SergeantData(
|
||||||
|
sergeantLeaderFilePath,
|
||||||
BuildCost(
|
BuildCost(
|
||||||
costResources?.getDoubleByName("requisition"),
|
costResources?.getDoubleByName("requisition"),
|
||||||
costResources?.getDoubleByName("power"),
|
costResources?.getDoubleByName("power"),
|
||||||
@ -377,7 +393,7 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
return Pair(sergeantsData, maxSergeants)
|
return Pair(sergeantsData, maxSergeants)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertIconAndReturnPath(squadData: List<RgdData>, modFolderData: String): String? {
|
private fun convertIconAndReturnPath(modName: String?, squadData: List<RgdData>, modFolderData: String): String? {
|
||||||
val iconPathInMod = squadData
|
val iconPathInMod = squadData
|
||||||
.getRgdTableByName("squad_ui_ext")
|
.getRgdTableByName("squad_ui_ext")
|
||||||
?.getRgdTableByName("ui_info")
|
?.getRgdTableByName("ui_info")
|
||||||
@ -387,11 +403,11 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
|
|
||||||
val tgaIconPath = iconPathInMod?.let {
|
val tgaIconPath = iconPathInMod?.let {
|
||||||
val modIcon = modAttribPathService.getIconPath(modFolderData, it)
|
val modIcon = modAttribPathService.getIconPath(modFolderData, it)
|
||||||
if(Path.of(modIcon).exists()) modIcon else
|
if (Path.of(modIcon).exists()) modIcon else
|
||||||
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it) }
|
return tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPathInMod, it, modName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.dowstats.service.w40k
|
package com.dowstats.service.w40k
|
||||||
|
|
||||||
import com.dowstats.data.entities.ArmorType
|
import com.dowstats.data.entities.ArmorType
|
||||||
|
import com.dowstats.data.entities.Mod
|
||||||
import com.dowstats.data.entities.Weapon
|
import com.dowstats.data.entities.Weapon
|
||||||
import com.dowstats.data.entities.WeaponArmorPiercing
|
import com.dowstats.data.entities.WeaponArmorPiercing
|
||||||
import com.dowstats.data.repositories.ArmorTypeRepository
|
import com.dowstats.data.repositories.ArmorTypeRepository
|
||||||
@ -32,9 +33,12 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
val seconds: Int?
|
val seconds: Int?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ArmourDamage(
|
data class AreaEffectData(
|
||||||
val minDamage: Double,
|
val minDamage: Double,
|
||||||
val maxDamage: Double,
|
val maxDamage: Double,
|
||||||
|
val damageRadius: Double,
|
||||||
|
val throwForceMin: Double,
|
||||||
|
val throwForceMax: Double,
|
||||||
val minDamageValue: Double,
|
val minDamageValue: Double,
|
||||||
val moraleDamage: Double,
|
val moraleDamage: Double,
|
||||||
val armourPiercing: List<WeaponArmorPiercing>,
|
val armourPiercing: List<WeaponArmorPiercing>,
|
||||||
@ -47,14 +51,14 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
val haveEquipButton: Boolean
|
val haveEquipButton: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
fun extractToWeaponEntity(weaponFileName: String, weaponData: List<RgdData>, modId: Long, modFolderData: String, modDictionary: Map<Int, String>): Weapon? {
|
fun extractToWeaponEntity(weaponFileName: String, weaponData: List<RgdData>, mod: Mod, modFolderData: String, modDictionary: Map<Int, String>): Weapon? {
|
||||||
|
|
||||||
val armorTypes = armorTypeRepository.findAll().toSet()
|
val armorTypes = armorTypeRepository.findAll().toSet()
|
||||||
|
|
||||||
val weapon = Weapon()
|
val weapon = Weapon()
|
||||||
|
|
||||||
weapon.filename = weaponFileName
|
weapon.filename = weaponFileName
|
||||||
val weaponUiData = getWeaponNameAndDescription(weaponData, modDictionary, modFolderData)
|
val weaponUiData = getWeaponNameAndDescription(weaponData, modDictionary, modFolderData, mod)
|
||||||
weapon.name = weaponUiData.name
|
weapon.name = weaponUiData.name
|
||||||
weapon.icon = weaponUiData.iconPath
|
weapon.icon = weaponUiData.iconPath
|
||||||
weapon.description = weaponUiData.description
|
weapon.description = weaponUiData.description
|
||||||
@ -67,21 +71,26 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
weapon.costTimeSeconds = cost.seconds ?: 0
|
weapon.costTimeSeconds = cost.seconds ?: 0
|
||||||
weapon.accuracy = weaponData.getDoubleByName("accuracy")
|
weapon.accuracy = weaponData.getDoubleByName("accuracy")
|
||||||
weapon.accuracyReductionMoving = weaponData.getDoubleByName("accuracy_reduction_when_moving")
|
weapon.accuracyReductionMoving = weaponData.getDoubleByName("accuracy_reduction_when_moving")
|
||||||
|
weapon.minRange = weaponData.getDoubleByName("min_range")
|
||||||
weapon.maxRange = weaponData.getDoubleByName("max_range")
|
weapon.maxRange = weaponData.getDoubleByName("max_range")
|
||||||
|
|
||||||
weapon.reloadTime = weaponData.getDoubleByName("reload_time")
|
weapon.reloadTime = weaponData.getDoubleByName("reload_time")
|
||||||
weapon.setupTime = weaponData.getDoubleByName("setup_time")
|
weapon.setupTime = weaponData.getDoubleByName("setup_time")
|
||||||
weapon.isMeleeWeapon = weaponData.getBooleanByName("melee_weapon") ?: false
|
weapon.isMeleeWeapon = weaponData.getBooleanByName("melee_weapon") ?: false
|
||||||
weapon.canAttackAir = weaponData.getBooleanByName("can_attack_air_units") ?: false
|
weapon.canAttackAir = weaponData.getBooleanByName("can_attack_air_units") ?: true
|
||||||
weapon.canAttackGround = weaponData.getBooleanByName("can_attack_ground_units") ?: false
|
weapon.canAttackGround = weaponData.getBooleanByName("can_attack_ground_units") ?: true
|
||||||
|
|
||||||
|
|
||||||
val armourDamage = getArmourDamage(weaponData, armorTypes, weapon)
|
val areaEffectData = getAreaEffectData(weaponData, armorTypes, weapon)
|
||||||
weapon.minDamageValue = armourDamage.minDamageValue
|
weapon.minDamageValue = areaEffectData.minDamageValue
|
||||||
weapon.minDamage = armourDamage.minDamage
|
weapon.minDamage = areaEffectData.minDamage
|
||||||
weapon.maxDamage = armourDamage.maxDamage
|
weapon.maxDamage = areaEffectData.maxDamage
|
||||||
weapon.moraleDamage = armourDamage.moraleDamage
|
weapon.throwForceMin = areaEffectData.throwForceMin
|
||||||
weapon.weaponPiercings = armourDamage.armourPiercing
|
weapon.throwForceMax = areaEffectData.throwForceMax
|
||||||
weapon.modId = modId
|
weapon.moraleDamage = areaEffectData.moraleDamage
|
||||||
|
weapon.weaponPiercings = areaEffectData.armourPiercing
|
||||||
|
weapon.damageRadius = areaEffectData.damageRadius
|
||||||
|
weapon.modId = mod.id
|
||||||
|
|
||||||
return if(weapon.minDamage == 0.0 && weapon.maxDamage == 0.0 && weapon.moraleDamage == 0.0){
|
return if(weapon.minDamage == 0.0 && weapon.maxDamage == 0.0 && weapon.moraleDamage == 0.0){
|
||||||
null
|
null
|
||||||
@ -97,8 +106,15 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
return BuildCost(requisition, power, costTime)
|
return BuildCost(requisition, power, costTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getArmourDamage(weaponData: List<RgdData>, armorTypes: Set<ArmorType>, thisWeapon: Weapon): ArmourDamage {
|
private fun getAreaEffectData(weaponData: List<RgdData>, armorTypes: Set<ArmorType>, thisWeapon: Weapon): AreaEffectData {
|
||||||
val armourDamage = weaponData.getRgdTableByName("area_effect")
|
val areaEffect = weaponData.getRgdTableByName("area_effect")
|
||||||
|
val damageRadius = areaEffect?.getRgdTableByName("area_effect_information")?.getDoubleByName("radius") ?: 0.0
|
||||||
|
|
||||||
|
val throwData = areaEffect?.getRgdTableByName("throw_data")
|
||||||
|
val forceMin = throwData?.getDoubleByName("force_min") ?: 0.0
|
||||||
|
val forceMax = throwData?.getDoubleByName("force_max") ?: 0.0
|
||||||
|
|
||||||
|
val armourDamage = areaEffect
|
||||||
?.getRgdTableByName("weapon_damage")
|
?.getRgdTableByName("weapon_damage")
|
||||||
?.getRgdTableByName("armour_damage")!!
|
?.getRgdTableByName("armour_damage")!!
|
||||||
val minDamage = armourDamage.getDoubleByName("min_damage")!!
|
val minDamage = armourDamage.getDoubleByName("min_damage")!!
|
||||||
@ -106,6 +122,7 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
val minDamageValue = armourDamage.getDoubleByName("min_damage_value")!!
|
val minDamageValue = armourDamage.getDoubleByName("min_damage_value")!!
|
||||||
val moraleDamage = armourDamage.getDoubleByName("morale_damage")!!
|
val moraleDamage = armourDamage.getDoubleByName("morale_damage")!!
|
||||||
|
|
||||||
|
|
||||||
val defaultArmourPiercing = armourDamage.getDoubleByName("armour_piercing")
|
val defaultArmourPiercing = armourDamage.getDoubleByName("armour_piercing")
|
||||||
val weaponDmgMap: Map<String, Double> =
|
val weaponDmgMap: Map<String, Double> =
|
||||||
armourDamage.getRgdTableByName("armour_piercing_types")!!.mapNotNull { armour_piercing ->
|
armourDamage.getRgdTableByName("armour_piercing_types")!!.mapNotNull { armour_piercing ->
|
||||||
@ -125,11 +142,11 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
weaponArmourPiercing
|
weaponArmourPiercing
|
||||||
}
|
}
|
||||||
|
|
||||||
return ArmourDamage(minDamage, maxDamage, minDamageValue, moraleDamage, armoursPiercing)
|
return AreaEffectData(minDamage, maxDamage, damageRadius, forceMin, forceMax, minDamageValue, moraleDamage, armoursPiercing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getWeaponNameAndDescription(weaponData: List<RgdData>, modDictionary: Map<Int, String>, modFolderData: String): WeaponUiInfo {
|
private fun getWeaponNameAndDescription(weaponData: List<RgdData>, modDictionary: Map<Int, String>, modFolderData: String, mod: Mod): WeaponUiInfo {
|
||||||
val weaponUiInfo = weaponData.getRgdTableByName("ui_info")
|
val weaponUiInfo = weaponData.getRgdTableByName("ui_info")
|
||||||
|
|
||||||
val nameRef = weaponUiInfo?.getStringByName("screen_name_id")?.replace("$", "")
|
val nameRef = weaponUiInfo?.getStringByName("screen_name_id")?.replace("$", "")
|
||||||
@ -156,7 +173,7 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
if(Path.of(modIcon).exists()) modIcon else
|
if(Path.of(modIcon).exists()) modIcon else
|
||||||
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
|
||||||
}
|
}
|
||||||
tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPath, it) }
|
tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPath, it, mod.name) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Error parsing ui icon path", e)
|
log.error("Error parsing ui icon path", e)
|
||||||
null
|
null
|
||||||
|
|||||||
63
src/main/resources/db/0.0.1/schema/addon_modifiers.json
Normal file
63
src/main/resources/db/0.0.1/schema/addon_modifiers.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"databaseChangeLog": [
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Add buildings table",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"createTable": {
|
||||||
|
"tableName": "addon_modifiers",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "int",
|
||||||
|
"autoIncrement": true,
|
||||||
|
"constraints": {
|
||||||
|
"primaryKey": true,
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "references",
|
||||||
|
"type": "varchar(255)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "usage_type",
|
||||||
|
"type": "varchar(255)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_id",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "addon_id",
|
||||||
|
"baseTableName": "addon_modifiers",
|
||||||
|
"constraintName": "fk_building_addons_addon_modifiers",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "building_addons"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
63
src/main/resources/db/0.0.1/schema/addon_requires.json
Normal file
63
src/main/resources/db/0.0.1/schema/addon_requires.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"databaseChangeLog": [
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Add buildings table",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"createTable": {
|
||||||
|
"tableName": "addon_requires",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "int",
|
||||||
|
"autoIncrement": true,
|
||||||
|
"constraints": {
|
||||||
|
"primaryKey": true,
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "references",
|
||||||
|
"type": "varchar(255)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "varchar(255)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "replace_when_done",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_id",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "addon_id",
|
||||||
|
"baseTableName": "addon_requires",
|
||||||
|
"constraintName": "fk_building_addons_addon_requires",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "building_addons"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
104
src/main/resources/db/0.0.1/schema/building_addons.json
Normal file
104
src/main/resources/db/0.0.1/schema/building_addons.json
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"databaseChangeLog": [
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Add buildings table",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"createTable": {
|
||||||
|
"tableName": "building_addons",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "int",
|
||||||
|
"autoIncrement": true,
|
||||||
|
"constraints": {
|
||||||
|
"primaryKey": true,
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "filename",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "varchar(5000)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_cost_requisition",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_cost_power",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_cost_population",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_cost_faith",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_cost_souls",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "addon_cost_time",
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "varchar(128)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "building_id",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "building_id",
|
||||||
|
"baseTableName": "building_addons",
|
||||||
|
"constraintName": "fk_building_addons_buildings",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "buildings"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
170
src/main/resources/db/0.0.1/schema/buildings.json
Normal file
170
src/main/resources/db/0.0.1/schema/buildings.json
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
{
|
||||||
|
"databaseChangeLog": [
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Add buildings table",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"createTable": {
|
||||||
|
"tableName": "buildings",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "int",
|
||||||
|
"autoIncrement": true,
|
||||||
|
"constraints": {
|
||||||
|
"primaryKey": true,
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "filename",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(4096)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "varchar(5000)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "build_cost_requisition",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "build_cost_power",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "build_cost_population",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "build_cost_faith",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "build_cost_souls",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "build_cost_time",
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "health",
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "health_regeneration",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "race_id",
|
||||||
|
"type": "varchar(50)",
|
||||||
|
"constraints": {
|
||||||
|
"nullable":false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "armour_type_id",
|
||||||
|
"type": "varchar(50)",
|
||||||
|
"constraints": {
|
||||||
|
"nullable":false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "armour_type_2_id",
|
||||||
|
"type": "varchar(50)"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "sight_radius",
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "detect_radius",
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "repair_max",
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "mod_id",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "varchar(128)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "race_id",
|
||||||
|
"baseTableName": "buildings",
|
||||||
|
"constraintName": "fk_buildings_races",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "races"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "armour_type_id",
|
||||||
|
"baseTableName": "buildings",
|
||||||
|
"constraintName": "fk_buildings_armor_types",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "armor_types"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "mod_id",
|
||||||
|
"baseTableName": "buildings",
|
||||||
|
"constraintName": "fk_buildings_mods",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "mods"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
82
src/main/resources/db/0.0.1/schema/buildings_weapons.json
Normal file
82
src/main/resources/db/0.0.1/schema/buildings_weapons.json
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"databaseChangeLog": [
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Add buildings_weapons table",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"createTable": {
|
||||||
|
"tableName": "buildings_weapons",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "building_id",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "weapon_id",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "hardpoint",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "hardpoint_order",
|
||||||
|
"type": "int",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addUniqueConstraint": {
|
||||||
|
"columnNames": "building_id, weapon_id, hardpoint, hardpoint_order",
|
||||||
|
"constraintName": "uc_building_weapon_hardpoint_hardpoint_order",
|
||||||
|
"tableName": "buildings_weapons"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "building_id",
|
||||||
|
"baseTableName": "buildings_weapons",
|
||||||
|
"constraintName": "fk_buildings_buildings_weapons",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "buildings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addForeignKeyConstraint":
|
||||||
|
{
|
||||||
|
"baseColumnNames": "weapon_id",
|
||||||
|
"baseTableName": "buildings_weapons",
|
||||||
|
"constraintName": "fk_weapons_buildings_weapons",
|
||||||
|
"referencedColumnNames": "id",
|
||||||
|
"referencedTableName": "weapons"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -50,8 +50,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"addUniqueConstraint": {
|
"addUniqueConstraint": {
|
||||||
"columnNames": "sergeant_id, weapon_id",
|
"columnNames": "sergeant_id, weapon_id, hardpoint, hardpoint_order",
|
||||||
"constraintName": "uc_sergeant_weapon",
|
"constraintName": "uc_sergeant_weapon_hardpoint_hardpoint_order",
|
||||||
"tableName": "sergeants_weapons"
|
"tableName": "sergeants_weapons"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
},{
|
},{
|
||||||
"column": {
|
"column": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"type": "varchar(255)"
|
"type": "varchar(4096)"
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"column": {
|
"column": {
|
||||||
@ -215,12 +215,6 @@
|
|||||||
"name": "icon",
|
"name": "icon",
|
||||||
"type": "varchar(128)"
|
"type": "varchar(128)"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"column": {
|
|
||||||
"name": "hotkey_name",
|
|
||||||
"type": "varchar(64)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,8 +50,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"addUniqueConstraint": {
|
"addUniqueConstraint": {
|
||||||
"columnNames": "unit_id, weapon_id",
|
"columnNames": "unit_id, weapon_id, hardpoint, hardpoint_order",
|
||||||
"constraintName": "uc_unit_weapon",
|
"constraintName": "uc_unit_weapon_hardpoint_hardpoint_order",
|
||||||
"tableName": "units_weapons"
|
"tableName": "units_weapons"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
},{
|
},{
|
||||||
"column": {
|
"column": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"type": "varchar(255)"
|
"type": "varchar(4096)"
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"column": {
|
"column": {
|
||||||
@ -94,6 +94,11 @@
|
|||||||
"nullable": false
|
"nullable": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "min_range",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
},{
|
},{
|
||||||
"column": {
|
"column": {
|
||||||
"name": "max_range",
|
"name": "max_range",
|
||||||
@ -131,6 +136,30 @@
|
|||||||
"nullable": false
|
"nullable": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "damage_radius",
|
||||||
|
"type": "number",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "throw_force_min",
|
||||||
|
"type": "number",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"column": {
|
||||||
|
"name": "throw_force_max",
|
||||||
|
"type": "number",
|
||||||
|
"constraints": {
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"column": {
|
"column": {
|
||||||
|
|||||||
@ -21,10 +21,30 @@
|
|||||||
"include": {
|
"include": {
|
||||||
"file": "db/0.0.1/schema/sergants.json"
|
"file": "db/0.0.1/schema/sergants.json"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"include": {
|
||||||
|
"file": "db/0.0.1/schema/buildings.json"
|
||||||
|
}
|
||||||
},{
|
},{
|
||||||
"include": {
|
"include": {
|
||||||
"file": "db/0.0.1/schema/weapons.json"
|
"file": "db/0.0.1/schema/weapons.json"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"include": {
|
||||||
|
"file": "db/0.0.1/schema/buildings_weapons.json"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"include": {
|
||||||
|
"file": "db/0.0.1/schema/building_addons.json"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"include": {
|
||||||
|
"file": "db/0.0.1/schema/addon_modifiers.json"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"include": {
|
||||||
|
"file": "db/0.0.1/schema/addon_requires.json"
|
||||||
|
}
|
||||||
},{
|
},{
|
||||||
"include": {
|
"include": {
|
||||||
"file": "db/0.0.1/schema/units_weapons.json"
|
"file": "db/0.0.1/schema/units_weapons.json"
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
import com.dowstats.configuration.StorageConfig
|
||||||
|
import com.dowstats.data.entities.ArmorType
|
||||||
|
import com.dowstats.data.entities.Mod
|
||||||
|
import com.dowstats.data.entities.Race
|
||||||
|
import com.dowstats.service.w40k.*
|
||||||
|
import io.mockk.junit5.MockKExtension
|
||||||
|
import io.mockk.mockk
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
|
import java.io.DataInputStream
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ExtendWith(MockKExtension::class)
|
||||||
|
class BuildingRgdExtractServiceTest {
|
||||||
|
|
||||||
|
val modAttribPathService = ModAttribPathService(StorageConfig())
|
||||||
|
val iconService = mockk<IconsService>()
|
||||||
|
val addonRgdExtractService = mockk<BuildingAddonRgdExtractService>()
|
||||||
|
|
||||||
|
val buildingRgdExtractService = BuildingRgdExtractService(modAttribPathService, iconService, addonRgdExtractService)
|
||||||
|
|
||||||
|
val rgdService = RgdParserService()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Should correct parse building`() {
|
||||||
|
|
||||||
|
val buildingRgdFile = File("src/test/resources/rgd/waagh_banner/ork_waagh_banner.rgd")
|
||||||
|
|
||||||
|
val rgdData = rgdService.parseRgdFileStream(DataInputStream(buildingRgdFile.inputStream()))
|
||||||
|
|
||||||
|
val res = buildingRgdExtractService.extractToBuildingEntity("Waagh banner", emptyMap(), rgdData, emptySet(), "orks", "/modFolder", Mod(), listOf(
|
||||||
|
Race().also {
|
||||||
|
it.id = "orks"
|
||||||
|
it.name = "Орки"
|
||||||
|
}
|
||||||
|
), listOf(
|
||||||
|
ArmorType().also {
|
||||||
|
it.id = "building_low"
|
||||||
|
it.name = "Лёгкие здания"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
emptyMap())
|
||||||
|
|
||||||
|
assertEquals(170.toDouble(), res.building.buildCostRequisition)
|
||||||
|
assertEquals(emptySet(), res.buildingWeapons)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
src/test/resources/application.properties
Normal file
27
src/test/resources/application.properties
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
spring.datasource.url=jdbc:postgresql://localhost:5433/wiki-db
|
||||||
|
spring.datasource.username=wiki-application
|
||||||
|
spring.datasource.password=hQXmQLJkKXdbIgBx
|
||||||
|
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||||
|
spring.liquibase.change-log=classpath:db/changelog-master.json
|
||||||
|
|
||||||
|
spring.servlet.multipart.enabled=true
|
||||||
|
spring.servlet.multipart.max-file-size=500MB
|
||||||
|
spring.servlet.multipart.max-request-size=500MB
|
||||||
|
|
||||||
|
spring.jpa.database=postgresql
|
||||||
|
spring.jpa.show-sql=true
|
||||||
|
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation= true
|
||||||
|
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
|
||||||
|
|
||||||
|
|
||||||
|
hibernate.jdbc.batch_size = 1000
|
||||||
|
|
||||||
|
server.port=8082
|
||||||
|
|
||||||
|
steam.api.key=1DDFA1A35D907D5F5C20418A8D1885C1
|
||||||
|
|
||||||
|
storage.key=3F82D04CC274897B2552E8798F82F7A1
|
||||||
|
storage.take-last=2
|
||||||
|
storage.mod-storage=/home/cnb/mods
|
||||||
|
storage.wanila-storage=/home/cnb/wanila
|
||||||
|
storage.icons-storage=/home/cnb/icons
|
||||||
BIN
src/test/resources/rgd/waagh_banner/ork_waagh_banner.rgd
Normal file
BIN
src/test/resources/rgd/waagh_banner/ork_waagh_banner.rgd
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user