Skip to content

Commit

Permalink
Support extra data in modrinth packs swap default jvm to openjdk, fix…
Browse files Browse the repository at this point in the history
… bug when leaving coroutine scope while downloading, minor ui fixes
  • Loading branch information
0ffz committed Mar 7, 2024
1 parent fb89c8f commit 27fa279
Show file tree
Hide file tree
Showing 41 changed files with 313 additions and 180 deletions.
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ dependencies {

implementation("com.darkrockstudios:mpfilepicker:3.1.0")
implementation("org.rauschig:jarchivelib:1.2.0")
implementation("edu.stanford.ejalbert:BrowserLauncher2:1.3")

implementation("net.raphimc:MinecraftAuth:4.0.0")
implementation("dev.3-3:jmccc-mcdownloader:3.1.4")
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
group=com.mineinabyss
version=2.0.0-alpha.3
version=2.0.0-alpha.4
idofrontVersion=0.22.3
9 changes: 6 additions & 3 deletions src/main/kotlin/com/mineinabyss/launchy/data/Dirs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ object Dirs {
OS.LINUX -> home / ".config"
} / "mineinabyss"

val cacheDir = config / "cache"
val imageCache = cacheDir / "images"

val jdks = mineinabyss / ".jdks"
val jdkGraal = mineinabyss / ".jdks" / "graalvm-jdk-17.zip"

val tmp = config / ".tmp"

val accounts = config / "accounts"
val avatars = config / "avatars"

fun avatar(uuid: UUID) = avatars / "$uuid.png"
fun avatar(uuid: UUID) = imageCache / "avatar-$uuid"

val configFile = config / "mia-launcher.yml"
val versionsFile = config / "mia-versions.yml"
Expand All @@ -48,6 +49,8 @@ object Dirs {
tmp.createDirectories()
modpackConfigsDir.createDirectories()
jdks.createDirectories()
cacheDir.createDirectories()
imageCache.createDirectories()
}

fun createConfigFiles() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ data class Config(
val jvmArguments: String? = null,
val memoryAllocation: Int? = null,
val useRecommendedJvmArguments: Boolean = true,
val preferHue: Float? = null,
) {
fun save() {
Dirs.configFile.writeText(Formats.yaml.encodeToString(this))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package com.mineinabyss.launchy.data.config

import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.res.loadImageBitmap
import com.charleskorn.kaml.decodeFromStream
import com.charleskorn.kaml.encodeToStream
import com.mineinabyss.launchy.data.Dirs
import com.mineinabyss.launchy.data.Formats
import com.mineinabyss.launchy.logic.Downloader
import com.mineinabyss.launchy.state.LaunchyState
import com.mineinabyss.launchy.state.modpack.ModpackState
import com.mineinabyss.launchy.ui.screens.Dialog
Expand All @@ -18,6 +14,8 @@ import kotlin.io.path.*
class GameInstance(
val configDir: Path,
) {
val overridesDir = configDir / "overrides"

init {
require(configDir.isDirectory()) { "Game instance at $configDir must be a directory" }
}
Expand All @@ -27,37 +25,18 @@ class GameInstance(
val minecraftDir = config.overrideMinecraftDir?.let { Path(it) } ?: Dirs.modpackDir(configDir.name)

val userConfigFile = (configDir / "config.yml")
private val backgroundImagePath = configDir / "background.png"
private val logoPath = configDir / "logo.png"
private var cachedBackground: BitmapPainter? = null
private var cachedLogo: BitmapPainter? = null

suspend fun getOrDownloadBackground(): BitmapPainter {
cachedBackground?.let { return it }
if (!backgroundImagePath.exists()) Downloader.download(config.backgroundURL, backgroundImagePath)
val painter =
BitmapPainter(loadImageBitmap(backgroundImagePath.inputStream()), filterQuality = FilterQuality.High)
cachedBackground = painter
return painter
}

suspend fun getOrDownloadLogo(): BitmapPainter {
cachedLogo?.let { return it }
if (!logoPath.exists()) Downloader.download(config.logoURL, logoPath)
val painter = BitmapPainter(loadImageBitmap(logoPath.inputStream()), filterQuality = FilterQuality.High)
cachedLogo = painter
return painter
}

suspend fun createModpackState(): ModpackState? {
val userConfig =
if (userConfigFile.exists()) Formats.yaml.decodeFromStream<ModpackUserConfig>(userConfigFile.inputStream())
else ModpackUserConfig()
val modpack = config.source.loadInstance(this)
.getOrElse {
dialog = Dialog.Error("Failed read instance", it
.stackTraceToString()
.split("\n").take(5).joinToString("\n"))
dialog = Dialog.Error(
"Failed read instance", it
.stackTraceToString()
.split("\n").take(5).joinToString("\n")
)
it.printStackTrace()
return null
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package com.mineinabyss.launchy.data.config

import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.runtime.Composable
import androidx.compose.runtime.produceState
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.res.loadImageBitmap
import com.mineinabyss.launchy.data.Dirs
import com.mineinabyss.launchy.data.Formats
import com.mineinabyss.launchy.data.modpacks.source.PackSource
import com.mineinabyss.launchy.logic.Downloader
import com.mineinabyss.launchy.state.LaunchyState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import java.nio.file.Path
import kotlin.io.path.div
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.time.Duration.Companion.seconds

@Serializable
@OptIn(ExperimentalStdlibApi::class)
Expand All @@ -27,34 +31,47 @@ data class GameInstanceConfig(
val overrideMinecraftDir: String? = null,
) {
@Transient
private val backgroundImagePath = Dirs.tmp / "background-${backgroundURL.hashCode().toHexString()}.png"
val backgroundPath = Dirs.imageCache / "background-${backgroundURL.hashCode().toHexString()}"

@Transient
private val logoPath = Dirs.tmp / "icon-${backgroundURL.hashCode().toHexString()}.png"
val logoPath = Dirs.imageCache / "icon-${logoURL.hashCode().toHexString()}"

@Transient
private var cachedBackground: BitmapPainter? = null

@Transient
private var cachedLogo: BitmapPainter? = null

suspend fun loadBackgroundFromTmpFile(): BitmapPainter {
suspend fun loadBackgroundImage(): BitmapPainter {
cachedBackground?.let { return it }
if (!backgroundImagePath.exists()) Downloader.download(backgroundURL, backgroundImagePath)
val painter =
BitmapPainter(loadImageBitmap(backgroundImagePath.inputStream()), filterQuality = FilterQuality.High)
Downloader.download(backgroundURL, backgroundPath, override = false)
val painter = BitmapPainter(loadImageBitmap(backgroundPath.inputStream()))
cachedBackground = painter
return painter
}

suspend fun loadIconFromTmpFile(): BitmapPainter {
suspend fun loadLogo(): BitmapPainter {
cachedLogo?.let { return it }
if (!logoPath.exists()) Downloader.download(logoURL, logoPath)
val painter = BitmapPainter(loadImageBitmap(logoPath.inputStream()), filterQuality = FilterQuality.High)
Downloader.download(logoURL, logoPath, override = false)
val painter = BitmapPainter(loadImageBitmap(logoPath.inputStream()))
cachedLogo = painter
return painter
}

@Composable
fun produceBackgroundState(state: LaunchyState) = produceState(cachedBackground) {
state.downloadContext.launch {
value = loadBackgroundImage()
}
}

@Composable
fun produceLogoState(state: LaunchyState) = produceState(cachedLogo) {
state.downloadContext.launch {
value = loadLogo()
}
}

companion object {
fun read(path: Path) =
Formats.yaml.decodeFromStream(serializer(), path.inputStream())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
package com.mineinabyss.launchy.data.config

import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.res.loadImageBitmap
import com.mineinabyss.launchy.data.Dirs
import com.mineinabyss.launchy.data.serializers.UUIDSerializer
import com.mineinabyss.launchy.logic.Downloader
import com.mineinabyss.launchy.state.LaunchyState
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import java.util.*
import kotlin.io.path.exists
import kotlin.io.path.inputStream

@Serializable
data class PlayerProfile(
val name: String,
val uuid: @Serializable(with = UUIDSerializer::class) UUID,
) {
suspend fun getAvatar(): ImageBitmap {
suspend fun getAvatar(state: LaunchyState): BitmapPainter {
val avatarPath = Dirs.avatar(uuid)

if (!avatarPath.exists()) Downloader.downloadAvatar(uuid)

return loadImageBitmap(avatarPath.inputStream())
state.downloadContext.launch {
Downloader.downloadAvatar(uuid)
}.join()
return BitmapPainter(loadImageBitmap(avatarPath.inputStream()), filterQuality = FilterQuality.None)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mineinabyss.launchy.data.modpacks

import kotlinx.serialization.Serializable

@Serializable
class ModReference(
val urlContains: String,
val info: ModInfo? = null,
)
@Serializable
class ExtraPackInfo(
val groups: List<Group> = listOf(),
val modGroups: Map<String, Set<ModReference>> = mapOf(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.nio.file.Path
import kotlin.io.path.div
import kotlin.io.path.exists

class Mod(
data class Mod(
val packDir: Path,
val info: ModInfo
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ data class ModInfo(
val name: String,
val license: String = "Unknown",
val homepage: String = "",
val desc: String,
val desc: String = "",
val url: String,
val configUrl: String = "",
val configDesc: String = "",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.mineinabyss.launchy.data.modpacks

import com.mineinabyss.launchy.data.config.GameInstance
import java.nio.file.Path

class Modpack(
val dependencies: PackDependencies,
val mods: Mods,
val overridesPath: Path? = null,
val overridesPaths: List<Path> = listOf(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.mineinabyss.launchy.data.modpacks
import com.mineinabyss.launchy.data.GroupName
import com.mineinabyss.launchy.data.ModName

class Mods(
data class Mods(
val modGroups: Map<Group, Set<Mod>>,
) {
val groups = modGroups.keys
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.mineinabyss.launchy.data.modpacks.formats

import com.mineinabyss.launchy.data.modpacks.ExtraPackInfo
import com.mineinabyss.launchy.data.modpacks.Group
import com.mineinabyss.launchy.data.modpacks.Mod
import com.mineinabyss.launchy.data.modpacks.Mods
import java.nio.file.Path


data class ExtraInfoFormat(
val format: PackFormat,
val extraInfoPack: ExtraPackInfo,
) : PackFormat by format {
override fun toGenericMods(minecraftDir: Path): Mods {
val originalMods = format.toGenericMods(minecraftDir)
val foundMods = mutableSetOf<Mod>()
val mods: Map<Group, Set<Mod>> = extraInfoPack.modGroups
.mapKeys { (name, _) -> extraInfoPack.groups.single { it.name == name } }
.mapValues { (_, mods) ->
mods.mapNotNull { ref ->
val found = originalMods.mods.find { mod -> ref.urlContains in mod.info.url }
if (found != null) foundMods.add(found)
if (found != null && ref.info != null)
found.copy(info = ref.info.copy(url = found.info.url))
else found
}.toSet()
}

val originalGroups = originalMods.modGroups.mapValues {
it.value.filterTo(mutableSetOf()) { mod -> mod !in foundMods }
}
return Mods(originalGroups + mods)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ data class LaunchyPackFormat(
return PackDependencies(minecraft = minecraftVersion, fabricLoader = fabricVersion)
}

override fun getOverridesPath(configDir: Path): Path? = null
override fun getOverridesPaths(configDir: Path): List<Path> = emptyList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ data class ModrinthPackFormat(
override fun toGenericMods(minecraftDir: Path) =
Mods.withSingleGroup(files.map { it.toMod(minecraftDir) })

override fun getOverridesPath(configDir: Path): Path = configDir / "mrpack" / "overrides"
override fun getOverridesPaths(configDir: Path): List<Path> = listOf(configDir / "mrpack" / "overrides")
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ sealed interface PackFormat {

fun getDependencies(minecraftDir: Path): PackDependencies

fun getOverridesPath(configDir: Path): Path?
fun getOverridesPaths(configDir: Path): List<Path>
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ import com.mineinabyss.launchy.data.modpacks.Modpack
import com.mineinabyss.launchy.logic.Downloader
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.io.path.createFile
import kotlin.io.path.createParentDirectories
import kotlin.io.path.exists

@Serializable
sealed class PackSource {
Expand All @@ -18,7 +15,7 @@ sealed class PackSource {
val format = type.getFormat(instance.configDir).getOrThrow()
val mods = format.toGenericMods(instance.minecraftDir)
val dependencies = format.getDependencies(instance.minecraftDir)
Modpack(dependencies, mods, format.getOverridesPath(instance.configDir))
Modpack(dependencies, mods, format.getOverridesPaths(instance.configDir))
}
}

Expand Down
Loading

0 comments on commit 27fa279

Please sign in to comment.