diff --git a/modsman-cli/src/main/kotlin/modsman/cli/main.kt b/modsman-cli/src/main/kotlin/modsman/cli/main.kt index f8124fb..9a1341f 100644 --- a/modsman-cli/src/main/kotlin/modsman/cli/main.kt +++ b/modsman-cli/src/main/kotlin/modsman/cli/main.kt @@ -4,13 +4,13 @@ import com.beust.jcommander.JCommander import com.beust.jcommander.Parameter import com.beust.jcommander.ParameterException import com.beust.jcommander.Parameters -import modsman.BuildConfig -import modsman.ModlistManager -import modsman.Modsman import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.runBlocking +import modsman.BuildConfig +import modsman.ModlistManager +import modsman.Modsman import java.nio.file.NoSuchFileException import java.nio.file.Path import kotlin.system.exitProcess @@ -70,11 +70,11 @@ internal object RootCommand : CommandBase() { @Parameters(commandNames = ["init"], commandDescription = "initialize a new mod list") internal object InitCommand : CommandBase() { - @Parameter(names = ["--mc-version", "-M"], required = true, description = "the MC version this mods folder is for") - lateinit var gameVersion: String + @Parameter(names = ["--mc-version", "-M"], required = true, description = "the target MC version (repeatable)") + lateinit var gameVersions: List override suspend fun run(jc: JCommander): Int { - ModlistManager.init(Path.of(RootCommand.modsFolder), gameVersion).close() + ModlistManager.init(Path.of(RootCommand.modsFolder), gameVersions).close() return 0 } } @@ -218,7 +218,7 @@ fun main(args: Array) { } if (RootCommand.help) { - jc.parsedCommand?.let {jc.usage(it)} ?: jc.usage() + jc.parsedCommand?.let { jc.usage(it) } ?: jc.usage() exitProcess(0) } diff --git a/modsman-core/src/main/kotlin/modsman/exceptions.kt b/modsman-core/src/main/kotlin/modsman/exceptions.kt index 813aae8..4f101a1 100644 --- a/modsman-core/src/main/kotlin/modsman/exceptions.kt +++ b/modsman-core/src/main/kotlin/modsman/exceptions.kt @@ -5,8 +5,8 @@ sealed class ModsmanException : RuntimeException { constructor(message: String, cause: Throwable) : super(message, cause) } -class ChooseFileException(version: String) : - ModsmanException("Failed to find a valid version matching '$version'") +class ChooseFileException(versions: List) : + ModsmanException("Failed to find a valid version matching $versions") class UpgradeException(mod: ModEntry, cause: ChooseFileException) : ModsmanException("Failed to upgrade '${mod.projectName}', caused by: ${cause.message}", cause) diff --git a/modsman-core/src/main/kotlin/modsman/modlist.kt b/modsman-core/src/main/kotlin/modsman/modlist.kt index 1497b4c..f49e7bd 100644 --- a/modsman-core/src/main/kotlin/modsman/modlist.kt +++ b/modsman-core/src/main/kotlin/modsman/modlist.kt @@ -1,8 +1,8 @@ package modsman -import com.google.gson.FieldNamingPolicy -import com.google.gson.GsonBuilder +import com.google.gson.* import java.io.Closeable +import java.lang.reflect.Type import java.nio.file.Files import java.nio.file.Path @@ -18,7 +18,7 @@ data class Modlist( val mods: List ) { data class Config( - val gameVersion: String + val requiredGameVersions: List ) companion object { @@ -26,6 +26,23 @@ data class Modlist( const val fileName = ".modlist.json" internal val gson = GsonBuilder() + .registerTypeAdapter( + Config::class.java, + JsonDeserializer { element: JsonElement, + _: Type, + _: JsonDeserializationContext -> + val obj = element.asJsonObject + Config( + when { + obj.has("required_game_versions") -> + obj.get("required_game_versions").asJsonArray.map { it.asString } + obj.has("game_version") -> + listOf(obj.get("game_version").asString) + else -> emptyList() + } + ) + } + ) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .setPrettyPrinting() .create()!! @@ -70,14 +87,14 @@ class ModlistManager(val modsPath: Path, modlist: Modlist) : Closeable { override fun close() = save() companion object { - fun init(modsPath: Path, gameVersion: String): ModlistManager { + fun init(modsPath: Path, gameVersions: List): ModlistManager { modsPath.resolve(Modlist.fileName).let { if (Files.exists(it)) throw FileAlreadyExistsException(it.toFile()) else return ModlistManager( modsPath = modsPath, - modlist = Modlist(config = Modlist.Config(gameVersion), mods = arrayListOf()) + modlist = Modlist(config = Modlist.Config(gameVersions), mods = arrayListOf()) ) } } diff --git a/modsman-core/src/main/kotlin/modsman/modsman.kt b/modsman-core/src/main/kotlin/modsman/modsman.kt index 589cccf..a209a7f 100644 --- a/modsman-core/src/main/kotlin/modsman/modsman.kt +++ b/modsman-core/src/main/kotlin/modsman/modsman.kt @@ -29,13 +29,14 @@ class Modsman( .filter { file -> file.isAvailable && !file.isAlternate && - file.gameVersion.any { version -> - modlist.config.gameVersion in version + modlist.config.requiredGameVersions.all { configVersion -> + file.gameVersion.any { fileVersion -> + configVersion in fileVersion + } } } .maxBy { file -> file.fileDate } - ?.let { it } - return ret ?: throw ChooseFileException(modlist.config.gameVersion) + return ret ?: throw ChooseFileException(modlist.config.requiredGameVersions) } private fun deleteFile(mod: ModEntry): Boolean { diff --git a/modsman-gui/src/main/kotlin/modsman/gui/MainApp.kt b/modsman-gui/src/main/kotlin/modsman/gui/MainApp.kt index 28c6dd9..29ca4bc 100644 --- a/modsman-gui/src/main/kotlin/modsman/gui/MainApp.kt +++ b/modsman-gui/src/main/kotlin/modsman/gui/MainApp.kt @@ -25,20 +25,23 @@ class MainApp : Application() { return chooser.showDialog(stage)?.toPath() ?: exitProcess(0) } - private fun chooseGameVersion(): String { + private fun chooseGameVersions(): List { val dialog = TextInputDialog("1.14") dialog.headerText = "Mod list not found." + "\nEnter a game version to initialize a new mod list." + "\nModsman will match to any versions that contain this version as a substring." + "\nFor example, the input \"1.14\" matches mods for \"1.14\", \"1.14.1\", and \"1.14-Snapshot\"." dialog.title = title - return dialog.showAndWait().orElse(null) ?: exitProcess(0) + return dialog + .showAndWait() + .map { it.split("\\s+,\\s+") } + .orElseGet { exitProcess(0) } } private fun createModsman(stage: Stage): Modsman { val path = chooseDirectory(stage) if (!Files.exists(path.resolve(Modlist.fileName))) { - ModlistManager.init(path, chooseGameVersion()).close() + ModlistManager.init(path, chooseGameVersions()).close() } return Modsman(path, 10) } diff --git a/modsman-gui/src/main/kotlin/modsman/gui/MainController.kt b/modsman-gui/src/main/kotlin/modsman/gui/MainController.kt index bedfeca..b6bd086 100644 --- a/modsman-gui/src/main/kotlin/modsman/gui/MainController.kt +++ b/modsman-gui/src/main/kotlin/modsman/gui/MainController.kt @@ -159,7 +159,7 @@ class MainController : Initializable { modsman?.let { path.text = "${it.modlist.modsPath.toAbsolutePath()}" - version.text = "MC ${it.modlist.config.gameVersion}" + version.text = it.modlist.config.requiredGameVersions.joinToString(", ") tableView.items.addAll(it.modlist.mods) } }