First day release changes
- add addon requirements - add addon modifiers - fix bug with incorrect dps, when armourPiercing more than 100 - fix bug, when dmg radius show on point weapon
This commit is contained in:
parent
fb94b26c83
commit
8f14dd9e62
@ -17,7 +17,7 @@ class AddonModifiers {
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
var addon: BuildingAddon? = null
|
var addon: BuildingAddon? = null
|
||||||
|
|
||||||
var references: String? = null
|
var reference: String? = null
|
||||||
var usageType: String? = null
|
var usageType: String? = null
|
||||||
var value: String? = null
|
var value: Double? = null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import jakarta.persistence.*
|
|||||||
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "addon_requires")
|
@Table(name = "addon_requirements")
|
||||||
class AddonRequires {
|
class AddonRequirements {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@ -16,10 +16,7 @@ class AddonRequires {
|
|||||||
@JoinColumn(name = "addon_id", nullable = false)
|
@JoinColumn(name = "addon_id", nullable = false)
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
var addon: BuildingAddon? = null
|
var addon: BuildingAddon? = null
|
||||||
|
var reference: String? = null
|
||||||
var references: String? = null
|
|
||||||
|
|
||||||
var replaceWhenDone: Boolean = false
|
var replaceWhenDone: Boolean = false
|
||||||
|
var value: Double? = null
|
||||||
var value: String? = null
|
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ class BuildingAddon {
|
|||||||
var addonModifiers: MutableSet<AddonModifiers>? = null
|
var addonModifiers: MutableSet<AddonModifiers>? = null
|
||||||
|
|
||||||
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
|
@OneToMany(mappedBy = "addon", cascade = [CascadeType.ALL])
|
||||||
var addonRequires: MutableSet<AddonRequires>? = null
|
var addonRequirements: MutableSet<AddonRequirements>? = null
|
||||||
|
|
||||||
var icon: String? = null
|
var icon: String? = null
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,11 @@ class DowUnit {
|
|||||||
@JoinColumn(name = "race_id", nullable = false)
|
@JoinColumn(name = "race_id", nullable = false)
|
||||||
var race: Race? = null
|
var race: Race? = null
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "armour_type_id", nullable = false)
|
@JoinColumn(name = "armour_type_id", nullable = false)
|
||||||
var armorType: ArmorType? = null
|
var armorType: ArmorType? = null
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "armour_type_2_id")
|
@JoinColumn(name = "armour_type_2_id")
|
||||||
var armorType2: ArmorType? = null
|
var armorType2: ArmorType? = null
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.dowstats.configuration.StorageConfig
|
|||||||
import com.dowstats.data.dto.integration.AvailableMods
|
import com.dowstats.data.dto.integration.AvailableMods
|
||||||
import com.dowstats.data.entities.Mod
|
import com.dowstats.data.entities.Mod
|
||||||
import com.dowstats.data.repositories.ModRepository
|
import com.dowstats.data.repositories.ModRepository
|
||||||
|
import com.dowstats.service.w40k.ModAttribPathService
|
||||||
import com.dowstats.service.w40k.ModParserService
|
import com.dowstats.service.w40k.ModParserService
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
@ -17,7 +18,10 @@ import java.io.FileOutputStream
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
import java.util.zip.*
|
import java.util.zip.*
|
||||||
|
|
||||||
|
|
||||||
@ -26,6 +30,7 @@ class ModStorageIntegrationService(
|
|||||||
val modStorageConfig: StorageConfig,
|
val modStorageConfig: StorageConfig,
|
||||||
val modRepository: ModRepository,
|
val modRepository: ModRepository,
|
||||||
val modParserService: ModParserService,
|
val modParserService: ModParserService,
|
||||||
|
val storageConfig: StorageConfig,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val objectMapper = jacksonObjectMapper()
|
val objectMapper = jacksonObjectMapper()
|
||||||
@ -64,7 +69,7 @@ class ModStorageIntegrationService(
|
|||||||
it.name = "Dowstats balance mod"
|
it.name = "Dowstats balance mod"
|
||||||
it.technicalName = toSave.technicalName
|
it.technicalName = toSave.technicalName
|
||||||
})
|
})
|
||||||
modParserService.parceModFilesAndSaveToDb(savedMod)
|
modParserService.parseModFilesAndSaveToDb(savedMod)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Error while download and extract mod", e)
|
log.error("Error while download and extract mod", e)
|
||||||
}
|
}
|
||||||
@ -76,7 +81,8 @@ class ModStorageIntegrationService(
|
|||||||
fun reloadMod(modId: Long) {
|
fun reloadMod(modId: Long) {
|
||||||
val mod = modRepository.findById(modId).orElseThrow { IllegalArgumentException("Mod not found") }
|
val mod = modRepository.findById(modId).orElseThrow { IllegalArgumentException("Mod not found") }
|
||||||
modRepository.clearModData(modId)
|
modRepository.clearModData(modId)
|
||||||
modParserService.parceModFilesAndSaveToDb(mod)
|
checkSgaAndExtract(mod)
|
||||||
|
modParserService.parseModFilesAndSaveToDb(mod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -94,11 +100,35 @@ class ModStorageIntegrationService(
|
|||||||
val modDirectoryTo = "$name$version"
|
val modDirectoryTo = "$name$version"
|
||||||
val fileStream = file.bytes.inputStream()
|
val fileStream = file.bytes.inputStream()
|
||||||
unzip(fileStream, modDirectoryTo)
|
unzip(fileStream, modDirectoryTo)
|
||||||
modParserService.parceModFilesAndSaveToDb(savedMod)
|
modParserService.parseModFilesAndSaveToDb(savedMod)
|
||||||
log.info("${file.originalFilename} successfull uploaded. Name: $name, version: $version")
|
log.info("${file.originalFilename} successfull uploaded. Name: $name, version: $version")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkSgaAndExtract(mod: Mod){
|
||||||
|
val modDirectory = "${storageConfig.modStorage.replace("/", File.separator)}${File.separator}${mod.technicalName}${mod.version}"
|
||||||
|
File(modDirectory).listFiles()?.forEach { sgaFolder ->
|
||||||
|
if(sgaFolder.isDirectory && sgaFolder.name.endsWith(".sga")){
|
||||||
|
// Перемещаем иконки
|
||||||
|
val iconFolder = sgaFolder.path + "${File.separator}Data${File.separator}art${File.separator}ui${File.separator}ingame"
|
||||||
|
if(File(iconFolder).exists()){
|
||||||
|
val iconFolderDestination = iconFolder.replace(sgaFolder.name + File.separator, "")
|
||||||
|
Files.createDirectories(Paths.get(iconFolderDestination))
|
||||||
|
FileSystemUtils.copyRecursively(Paths.get(iconFolder),Paths.get(iconFolderDestination))
|
||||||
|
}
|
||||||
|
// Перемещаем атрибуты
|
||||||
|
val attribFolder = sgaFolder.path + "${File.separator}Data${File.separator}attrib"
|
||||||
|
if(File(attribFolder).exists()) {
|
||||||
|
val attribFolderDestination = attribFolder.replace(sgaFolder.name + File.separator, "")
|
||||||
|
Files.createDirectories(Paths.get(attribFolder))
|
||||||
|
FileSystemUtils.copyRecursively(Paths.get(attribFolder),Paths.get(attribFolderDestination))
|
||||||
|
}
|
||||||
|
// Удаляем остальное
|
||||||
|
FileSystemUtils.deleteRecursively(sgaFolder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun downloadAndExtractMod(modTechName: String, version: String) {
|
private fun downloadAndExtractMod(modTechName: String, version: String) {
|
||||||
log.info("Downloading mod $modTechName")
|
log.info("Downloading mod $modTechName")
|
||||||
val urlString = "http://crosspick.ru/dow_stats_client/dow_stats_balance_mod/$modTechName.zip"
|
val urlString = "http://crosspick.ru/dow_stats_client/dow_stats_balance_mod/$modTechName.zip"
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.dowstats.service.w40k
|
|||||||
import com.dowstats.data.dto.BuildCost
|
import com.dowstats.data.dto.BuildCost
|
||||||
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.getBooleanByName
|
||||||
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
|
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
|
||||||
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
|
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
|
||||||
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
|
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
|
||||||
@ -50,14 +51,50 @@ class BuildingAddonRgdExtractService @Autowired constructor(
|
|||||||
addon.addonCostFaith = buildCost.faith
|
addon.addonCostFaith = buildCost.faith
|
||||||
addon.addonCostSouls = buildCost.souls
|
addon.addonCostSouls = buildCost.souls
|
||||||
addon.addonCostTime = buildCost.time
|
addon.addonCostTime = buildCost.time
|
||||||
|
addon.addonModifiers = getAddonModifiers(addon, addonRgdData).toMutableSet()
|
||||||
|
addon.addonRequirements = getAddonRequirements(addon, addonRgdData).toMutableSet()
|
||||||
|
|
||||||
val addonIcon = convertIconAndReturnPath(addonRgdData, modFolderData, mod.name)
|
val addonIcon = convertIconAndReturnPath(addonRgdData, modFolderData, mod.name)
|
||||||
addon.icon = addonIcon
|
addon.icon = addonIcon
|
||||||
|
|
||||||
|
|
||||||
return addon
|
return addon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getAddonModifiers(addon: BuildingAddon, addonData: List<RgdData>): List<AddonModifiers> {
|
||||||
|
val modifiers = addonData.getRgdTableByName("modifiers")
|
||||||
|
return modifiers?.mapNotNull { m ->
|
||||||
|
if (m.name.contains("modifier_")) {
|
||||||
|
val mTable = m.value as List<RgdData>
|
||||||
|
if (mTable.getStringByName("\$REF") == "modifiers\\no_modifier.lua") null else {
|
||||||
|
AddonModifiers().also {
|
||||||
|
it.addon = addon
|
||||||
|
it.reference = mTable.getStringByName("\$REF")
|
||||||
|
it.usageType = mTable.getRgdTableByName("usage_type")?.getStringByName("\$REF")
|
||||||
|
it.value = mTable.getDoubleByName("value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
} ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAddonRequirements(addon: BuildingAddon, addonData: List<RgdData>): List<AddonRequirements> {
|
||||||
|
val requirements = addonData.getRgdTableByName("requirements")
|
||||||
|
return requirements?.mapNotNull { r ->
|
||||||
|
if (r.name.contains("required_")) {
|
||||||
|
val rTable = r.value as List<RgdData>
|
||||||
|
if (rTable.getStringByName("\$REF") == "requirements\\required_none.lua") null else {
|
||||||
|
AddonRequirements().also {
|
||||||
|
it.addon = addon
|
||||||
|
it.reference = rTable.getStringByName("\$REF")
|
||||||
|
it.replaceWhenDone = rTable.getBooleanByName("replace_when_done") == true
|
||||||
|
it.value =
|
||||||
|
if (it.reference == "requirements\\required_total_pop.lua") rTable.getDoubleByName("population_required") else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
} ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getAddonCost(addonData: List<RgdData>): BuildCost {
|
private fun getAddonCost(addonData: List<RgdData>): BuildCost {
|
||||||
|
|
||||||
@ -79,12 +116,24 @@ class BuildingAddonRgdExtractService @Autowired constructor(
|
|||||||
val uiInfo = addonData.getRgdTableByName("ui_info")
|
val uiInfo = addonData.getRgdTableByName("ui_info")
|
||||||
|
|
||||||
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")
|
||||||
@ -97,7 +146,11 @@ class BuildingAddonRgdExtractService @Autowired constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun convertIconAndReturnPath(buildingData: List<RgdData>, modFolderData: String, modName: String?): String? {
|
private fun convertIconAndReturnPath(
|
||||||
|
buildingData: List<RgdData>,
|
||||||
|
modFolderData: String,
|
||||||
|
modName: String?
|
||||||
|
): String? {
|
||||||
val iconPathInMod = buildingData
|
val iconPathInMod = buildingData
|
||||||
.getRgdTableByName("ui_info")
|
.getRgdTableByName("ui_info")
|
||||||
?.getStringByName("icon_name")
|
?.getStringByName("icon_name")
|
||||||
|
|||||||
@ -51,7 +51,7 @@ class ModParserService @Autowired constructor(
|
|||||||
val log = LoggerFactory.getLogger(ModParserService::class.java)
|
val log = LoggerFactory.getLogger(ModParserService::class.java)
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
fun parceModFilesAndSaveToDb(mod: Mod) {
|
fun parseModFilesAndSaveToDb(mod: Mod) {
|
||||||
|
|
||||||
log.info("Start parse mod files ${mod.technicalName}:${mod.version}")
|
log.info("Start parse mod files ${mod.technicalName}:${mod.version}")
|
||||||
|
|
||||||
|
|||||||
@ -169,7 +169,10 @@ class UnitRgdExtractService @Autowired constructor(
|
|||||||
?.getRgdTableByName(armorTypeTableName)
|
?.getRgdTableByName(armorTypeTableName)
|
||||||
?.getStringByName("\$REF")
|
?.getStringByName("\$REF")
|
||||||
|
|
||||||
return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") }
|
return armorTypes.find { it.id == armorType
|
||||||
|
?.replace("TYPE_Armour\\tp_", "")
|
||||||
|
?.replace("type_armour\\tp_", "")
|
||||||
|
?.replace(".lua", "") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBuildCost(unitData: List<RgdData>, squadData: List<RgdData>): BuildCost {
|
private fun getBuildCost(unitData: List<RgdData>, squadData: List<RgdData>): BuildCost {
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory
|
|||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.exists
|
import kotlin.io.path.exists
|
||||||
|
|
||||||
@ -107,7 +108,10 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
|
|
||||||
private fun getAreaEffectData(weaponData: List<RgdData>, armorTypes: Set<ArmorType>, thisWeapon: Weapon): AreaEffectData {
|
private fun getAreaEffectData(weaponData: List<RgdData>, armorTypes: Set<ArmorType>, thisWeapon: Weapon): AreaEffectData {
|
||||||
val areaEffect = weaponData.getRgdTableByName("area_effect")
|
val areaEffect = weaponData.getRgdTableByName("area_effect")
|
||||||
val damageRadius = areaEffect?.getRgdTableByName("area_effect_information")?.getDoubleByName("radius") ?: 0.0
|
|
||||||
|
val areaEffectInformation = areaEffect?.getRgdTableByName("area_effect_information")
|
||||||
|
val cantHaveRadius = areaEffectInformation?.getRgdTableByName("area_type")?.getStringByName("\$REF")?.contains("tp_area_effect_point") == true
|
||||||
|
val damageRadius = if(cantHaveRadius) 0.0 else areaEffectInformation?.getDoubleByName("radius") ?: 0.0
|
||||||
|
|
||||||
val throwData = areaEffect?.getRgdTableByName("throw_data")
|
val throwData = areaEffect?.getRgdTableByName("throw_data")
|
||||||
val forceMin = throwData?.getDoubleByName("force_min") ?: 0.0
|
val forceMin = throwData?.getDoubleByName("force_min") ?: 0.0
|
||||||
@ -137,7 +141,8 @@ class WeaponRgdExtractService @Autowired constructor(
|
|||||||
val weaponArmourPiercing = WeaponArmorPiercing()
|
val weaponArmourPiercing = WeaponArmorPiercing()
|
||||||
weaponArmourPiercing.weapon = thisWeapon
|
weaponArmourPiercing.weapon = thisWeapon
|
||||||
weaponArmourPiercing.armorType = it
|
weaponArmourPiercing.armorType = it
|
||||||
weaponArmourPiercing.piercingValue = (weaponDmgMap[it.id] ?: defaultArmourPiercing)?.toBigDecimal()
|
val piercingValue = (weaponDmgMap[it.id] ?: defaultArmourPiercing)?.toBigDecimal()
|
||||||
|
weaponArmourPiercing.piercingValue = piercingValue?.let {pv -> if(pv <= BigDecimal(100)) pv else BigDecimal(100) }
|
||||||
weaponArmourPiercing
|
weaponArmourPiercing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
72
src/main/resources/db/0.0.2/schema/addon.json
Normal file
72
src/main/resources/db/0.0.2/schema/addon.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"databaseChangeLog": [
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Rename addon columns",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"renameColumn": {
|
||||||
|
"newColumnName": "reference",
|
||||||
|
"oldColumnName": "references",
|
||||||
|
"tableName": "addon_modifiers"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"renameColumn": {
|
||||||
|
"newColumnName": "reference",
|
||||||
|
"oldColumnName": "references",
|
||||||
|
"tableName": "addon_requires"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Rename addon_requires table",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"renameTable": {
|
||||||
|
"oldTableName": "addon_requires",
|
||||||
|
"newTableName": "addon_requirements"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changeSet": {
|
||||||
|
"id": "Change addon_requirements value type",
|
||||||
|
"author": "anibus",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"dropColumn": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tableName": "addon_requirements"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addColumn": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"column": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tableName": "addon_requirements"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -73,6 +73,10 @@
|
|||||||
"include": {
|
"include": {
|
||||||
"file": "db/0.0.1/schema/procedure_delete_mod_data.json"
|
"file": "db/0.0.1/schema/procedure_delete_mod_data.json"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"include": {
|
||||||
|
"file": "db/0.0.2/schema/addon.json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user