mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 21:16:30 +02:00
Compare commits
No commits in common. "main" and "v0.5.10" have entirely different histories.
@ -21,7 +21,6 @@ import java.nio.file.StandardCopyOption
|
||||
|
||||
internal class DownloadTask private constructor(val metadata: IndexFile.File, val index: IndexFile, private val downloadSide: Side) : IOptionDetails {
|
||||
var cachedFile: ManifestFile.File? = null
|
||||
private set
|
||||
|
||||
private var err: Exception? = null
|
||||
val exceptionDetails get() = err?.let { e -> ExceptionDetails(name, e) }
|
||||
@ -29,24 +28,10 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
|
||||
fun failed() = err != null
|
||||
|
||||
var alreadyUpToDate = false
|
||||
private set
|
||||
private var metadataRequired = true
|
||||
private var invalidated = false
|
||||
// If file is new or isOptional changed to true, the option needs to be presented again
|
||||
private var newOptional = true
|
||||
var completionStatus = CompletionStatus.INCOMPLETE
|
||||
private set
|
||||
|
||||
enum class CompletionStatus {
|
||||
INCOMPLETE,
|
||||
DOWNLOADED,
|
||||
ALREADY_EXISTS_CACHED,
|
||||
ALREADY_EXISTS_VALIDATED,
|
||||
SKIPPED_DISABLED,
|
||||
SKIPPED_WRONG_SIDE,
|
||||
DELETED_DISABLED,
|
||||
DELETED_WRONG_SIDE;
|
||||
}
|
||||
|
||||
val isOptional get() = metadata.linkedFile?.option?.optional ?: false
|
||||
|
||||
@ -91,7 +76,6 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
|
||||
if (currHash == cachedFile.hash) { // Already up to date
|
||||
alreadyUpToDate = true
|
||||
metadataRequired = false
|
||||
completionStatus = CompletionStatus.ALREADY_EXISTS_CACHED
|
||||
}
|
||||
}
|
||||
if (cachedFile.isOptional) {
|
||||
@ -159,7 +143,6 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
|
||||
fileSource.buffer().readAll(blackholeSink())
|
||||
if (hash == fileSource.hash) {
|
||||
alreadyUpToDate = true
|
||||
completionStatus = CompletionStatus.ALREADY_EXISTS_VALIDATED
|
||||
|
||||
// Update the manifest file
|
||||
cachedFile = (cachedFile ?: ManifestFile.File()).also {
|
||||
@ -198,18 +181,10 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
|
||||
if (it.cachedLocation != null) {
|
||||
// Ensure wrong-side or optional false files are removed
|
||||
try {
|
||||
completionStatus = if (Files.deleteIfExists(it.cachedLocation!!.nioPath)) {
|
||||
if (correctSide()) { CompletionStatus.DELETED_DISABLED } else { CompletionStatus.DELETED_WRONG_SIDE }
|
||||
} else {
|
||||
if (correctSide()) { CompletionStatus.SKIPPED_DISABLED } else { CompletionStatus.SKIPPED_WRONG_SIDE }
|
||||
}
|
||||
Files.deleteIfExists(it.cachedLocation!!.nioPath)
|
||||
} catch (e: IOException) {
|
||||
Log.warn("Failed to delete file", e)
|
||||
}
|
||||
} else {
|
||||
completionStatus =
|
||||
if (correctSide()) { CompletionStatus.SKIPPED_DISABLED }
|
||||
else { CompletionStatus.SKIPPED_WRONG_SIDE }
|
||||
}
|
||||
it.cachedLocation = null
|
||||
return
|
||||
@ -309,8 +284,6 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
completionStatus = CompletionStatus.DOWNLOADED
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -48,7 +48,6 @@ class LauncherUtils internal constructor(private val opts: UpdateManager.Options
|
||||
val modLoaders = hashMapOf(
|
||||
"net.minecraft" to "minecraft",
|
||||
"net.minecraftforge" to "forge",
|
||||
"net.neoforged" to "neoforge",
|
||||
"net.fabricmc.fabric-loader" to "fabric",
|
||||
"org.quiltmc.quilt-loader" to "quilt",
|
||||
"com.mumfrey.liteloader" to "liteloader"
|
||||
@ -60,7 +59,6 @@ class LauncherUtils internal constructor(private val opts: UpdateManager.Options
|
||||
"org.lwjgl" to -1,
|
||||
"org.lwjgl3" to -1,
|
||||
"net.minecraftforge" to 5,
|
||||
"net.neoforged" to 5,
|
||||
"net.fabricmc.fabric-loader" to 10,
|
||||
"org.quiltmc.quilt-loader" to 10,
|
||||
"com.mumfrey.liteloader" to 10,
|
||||
|
@ -127,45 +127,41 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
|
||||
ui.submitProgress(InstallProgress("Checking local files..."))
|
||||
|
||||
// If the side changes, invalidate EVERYTHING (even when the index hasn't changed)
|
||||
val invalidateAll = opts.side != manifest.cachedSide
|
||||
// Invalidation checking must be done here, as it must happen before pack/index hashes are checked
|
||||
val invalidatedUris: MutableList<PackwizFilePath> = ArrayList()
|
||||
if (!invalidateAll) {
|
||||
// Invalidation checking must be done here, as it must happen before pack/index hashes are checked
|
||||
for ((fileUri, file) in manifest.cachedFiles) {
|
||||
// ignore onlyOtherSide files
|
||||
if (file.onlyOtherSide) {
|
||||
continue
|
||||
}
|
||||
|
||||
var invalid = false
|
||||
// if isn't optional, or is optional but optionValue == true
|
||||
if (!file.isOptional || file.optionValue) {
|
||||
if (file.cachedLocation != null) {
|
||||
if (!file.cachedLocation!!.nioPath.toFile().exists()) {
|
||||
invalid = true
|
||||
}
|
||||
} else {
|
||||
// if cachedLocation == null, should probably be installed!!
|
||||
invalid = true
|
||||
}
|
||||
}
|
||||
if (invalid) {
|
||||
Log.info("File ${fileUri.filename} invalidated, marked for redownloading")
|
||||
invalidatedUris.add(fileUri)
|
||||
}
|
||||
for ((fileUri, file) in manifest.cachedFiles) {
|
||||
// ignore onlyOtherSide files
|
||||
if (file.onlyOtherSide) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (manifest.packFileHash?.let { it == packFileSource.hash } == true && invalidatedUris.isEmpty()) {
|
||||
// todo: --force?
|
||||
ui.submitProgress(InstallProgress("Modpack is already up to date!", 1, 1))
|
||||
if (manifest.cachedFiles.any { it.value.isOptional }) {
|
||||
ui.awaitOptionalButton(false, opts.timeout)
|
||||
}
|
||||
if (!ui.optionsButtonPressed) {
|
||||
return
|
||||
var invalid = false
|
||||
// if isn't optional, or is optional but optionValue == true
|
||||
if (!file.isOptional || file.optionValue) {
|
||||
if (file.cachedLocation != null) {
|
||||
if (!file.cachedLocation!!.nioPath.toFile().exists()) {
|
||||
invalid = true
|
||||
}
|
||||
} else {
|
||||
// if cachedLocation == null, should probably be installed!!
|
||||
invalid = true
|
||||
}
|
||||
}
|
||||
if (invalid) {
|
||||
Log.info("File ${fileUri.filename} invalidated, marked for redownloading")
|
||||
invalidatedUris.add(fileUri)
|
||||
}
|
||||
}
|
||||
|
||||
if (manifest.packFileHash?.let { it == packFileSource.hash } == true && invalidatedUris.isEmpty()) {
|
||||
// todo: --force?
|
||||
ui.submitProgress(InstallProgress("Modpack is already up to date!", 1, 1))
|
||||
if (manifest.cachedFiles.any { it.value.isOptional }) {
|
||||
ui.awaitOptionalButton(false, opts.timeout)
|
||||
}
|
||||
if (!ui.optionsButtonPressed) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("Modpack name: ${pf.name}")
|
||||
@ -181,7 +177,6 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
pf.index.hashFormat,
|
||||
manifest,
|
||||
invalidatedUris,
|
||||
invalidateAll,
|
||||
clientHolder
|
||||
)
|
||||
} catch (e1: Exception) {
|
||||
@ -207,20 +202,18 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
}
|
||||
}
|
||||
|
||||
private fun processIndex(indexUri: PackwizPath<*>, indexHash: Hash<*>, hashFormat: HashFormat<*>, manifest: ManifestFile, invalidatedFiles: List<PackwizFilePath>, invalidateAll: Boolean, clientHolder: ClientHolder) {
|
||||
if (!invalidateAll) {
|
||||
if (manifest.indexFileHash == indexHash && invalidatedFiles.isEmpty()) {
|
||||
ui.submitProgress(InstallProgress("Modpack files are already up to date!", 1, 1))
|
||||
if (manifest.cachedFiles.any { it.value.isOptional }) {
|
||||
ui.awaitOptionalButton(false, opts.timeout)
|
||||
}
|
||||
if (!ui.optionsButtonPressed) {
|
||||
return
|
||||
}
|
||||
if (ui.cancelButtonPressed) {
|
||||
showCancellationDialog()
|
||||
return
|
||||
}
|
||||
private fun processIndex(indexUri: PackwizPath<*>, indexHash: Hash<*>, hashFormat: HashFormat<*>, manifest: ManifestFile, invalidatedFiles: List<PackwizFilePath>, clientHolder: ClientHolder) {
|
||||
if (manifest.indexFileHash == indexHash && invalidatedFiles.isEmpty()) {
|
||||
ui.submitProgress(InstallProgress("Modpack files are already up to date!", 1, 1))
|
||||
if (manifest.cachedFiles.any { it.value.isOptional }) {
|
||||
ui.awaitOptionalButton(false, opts.timeout)
|
||||
}
|
||||
if (!ui.optionsButtonPressed) {
|
||||
return
|
||||
}
|
||||
if (ui.cancelButtonPressed) {
|
||||
showCancellationDialog()
|
||||
return
|
||||
}
|
||||
}
|
||||
manifest.indexFileHash = indexHash
|
||||
@ -247,17 +240,31 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
}
|
||||
|
||||
ui.submitProgress(InstallProgress("Checking local files..."))
|
||||
// TODO: use kotlin filtering/FP rather than an iterator?
|
||||
val it: MutableIterator<Map.Entry<PackwizFilePath, ManifestFile.File>> = manifest.cachedFiles.entries.iterator()
|
||||
while (it.hasNext()) {
|
||||
val (uri, file) = it.next()
|
||||
if (file.cachedLocation != null) {
|
||||
if (indexFile.files.none { it.file.rebase(opts.packFolder) == uri }) { // File has been removed from the index
|
||||
var alreadyDeleted = false
|
||||
// Delete if option value has been set to false
|
||||
if (file.isOptional && !file.optionValue) {
|
||||
try {
|
||||
Files.deleteIfExists(file.cachedLocation!!.nioPath)
|
||||
} catch (e: IOException) {
|
||||
Log.warn("Failed to delete file removed from index", e)
|
||||
Log.warn("Failed to delete optional disabled file", e)
|
||||
}
|
||||
// Set to null, as it doesn't exist anymore
|
||||
file.cachedLocation = null
|
||||
alreadyDeleted = true
|
||||
}
|
||||
if (indexFile.files.none { it.file.rebase(opts.packFolder) == uri }) { // File has been removed from the index
|
||||
if (!alreadyDeleted) {
|
||||
try {
|
||||
Files.deleteIfExists(file.cachedLocation!!.nioPath)
|
||||
} catch (e: IOException) {
|
||||
Log.warn("Failed to delete file removed from index", e)
|
||||
}
|
||||
}
|
||||
Log.info("Deleted ${file.cachedLocation!!.filename} (removed from pack)")
|
||||
it.remove()
|
||||
}
|
||||
}
|
||||
@ -274,6 +281,9 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
Log.warn("Index is empty!")
|
||||
}
|
||||
val tasks = createTasksFromIndex(indexFile, opts.side)
|
||||
// If the side changes, invalidate EVERYTHING just in case
|
||||
// Might not be needed, but done just to be safe
|
||||
val invalidateAll = opts.side != manifest.cachedSide
|
||||
if (invalidateAll) {
|
||||
Log.info("Side changed, invalidating all mods")
|
||||
}
|
||||
@ -387,16 +397,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
val progress = if (exDetails != null) {
|
||||
"Failed to download ${exDetails.name}: ${exDetails.exception.message}"
|
||||
} else {
|
||||
when (task.completionStatus) {
|
||||
DownloadTask.CompletionStatus.INCOMPLETE -> "${task.name} pending (you should never see this...)"
|
||||
DownloadTask.CompletionStatus.DOWNLOADED -> "Downloaded ${task.name}"
|
||||
DownloadTask.CompletionStatus.ALREADY_EXISTS_CACHED -> "${task.name} already exists (cached)"
|
||||
DownloadTask.CompletionStatus.ALREADY_EXISTS_VALIDATED -> "${task.name} already exists (validated)"
|
||||
DownloadTask.CompletionStatus.SKIPPED_DISABLED -> "Skipped ${task.name} (disabled)"
|
||||
DownloadTask.CompletionStatus.SKIPPED_WRONG_SIDE -> "Skipped ${task.name} (wrong side)"
|
||||
DownloadTask.CompletionStatus.DELETED_DISABLED -> "Deleted ${task.name} (disabled)"
|
||||
DownloadTask.CompletionStatus.DELETED_WRONG_SIDE -> "Deleted ${task.name} (wrong side)"
|
||||
}
|
||||
"Downloaded ${task.name}"
|
||||
}
|
||||
ui.submitProgress(InstallProgress(progress, i + 1, tasks.size))
|
||||
|
||||
|
@ -147,9 +147,8 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
|
||||
}
|
||||
|
||||
for (indexFile in fileIdMap[fileId]!!) {
|
||||
var modUrl = "${mod.links?.websiteUrl}/files/${fileId}"
|
||||
failures.add(ExceptionDetails(indexFile.name, Exception("This mod is excluded from the CurseForge API and must be downloaded manually.\n" +
|
||||
"Please go to ${modUrl} and save this file to ${indexFile.destURI.rebase(packFolder).nioPath.absolute()}"), modUrl))
|
||||
"Please go to ${mod.links?.websiteUrl}/files/${fileId} and save this file to ${indexFile.destURI.rebase(packFolder).nioPath.absolute()}")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,7 @@ interface IUserInterface {
|
||||
|
||||
fun showCancellationDialog(): CancellationResult = CancellationResult.QUIT
|
||||
|
||||
fun showUpdateConfirmationDialog(oldVersions: List<Pair<String, String?>>, newVersions: List<Pair<String, String?>>): UpdateConfirmationResult {
|
||||
// Always update metadata when using the CLI
|
||||
return UpdateConfirmationResult.UPDATE
|
||||
}
|
||||
fun showUpdateConfirmationDialog(oldVersions: List<Pair<String, String?>>, newVersions: List<Pair<String, String?>>): UpdateConfirmationResult = UpdateConfirmationResult.CANCELLED
|
||||
|
||||
fun awaitOptionalButton(showCancel: Boolean, timeout: Long)
|
||||
|
||||
|
@ -2,6 +2,5 @@ package link.infra.packwiz.installer.ui.data
|
||||
|
||||
data class ExceptionDetails(
|
||||
val name: String,
|
||||
val exception: Exception,
|
||||
val modUrl: String? = null
|
||||
val exception: Exception
|
||||
)
|
@ -1,6 +1,5 @@
|
||||
package link.infra.packwiz.installer.ui.gui
|
||||
|
||||
import link.infra.packwiz.installer.util.Log
|
||||
import link.infra.packwiz.installer.ui.IUserInterface
|
||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||
import java.awt.BorderLayout
|
||||
@ -25,24 +24,6 @@ class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFutu
|
||||
fun getExceptionAt(index: Int) = details[index].exception
|
||||
}
|
||||
|
||||
private fun openUrl(url: String) {
|
||||
try {
|
||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||
Desktop.getDesktop().browse(URI(url))
|
||||
} else {
|
||||
val process = Runtime.getRuntime().exec(arrayOf("xdg-open", url));
|
||||
val exitValue = process.waitFor()
|
||||
if (exitValue > 0) {
|
||||
Log.warn("Failed to open $url: xdg-open exited with code $exitValue")
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.warn("Failed to open $url", e)
|
||||
} catch (e: URISyntaxException) {
|
||||
Log.warn("Failed to open $url", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the dialog.
|
||||
*/
|
||||
@ -131,19 +112,6 @@ class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFutu
|
||||
this@ExceptionListWindow.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
val missingMods = eList.filter { it.modUrl != null }.map { it.modUrl!! }.toSet()
|
||||
|
||||
if (!missingMods.isEmpty()) {
|
||||
add(JButton("Open missing mods").apply {
|
||||
toolTipText = "Open missing mods in your browser"
|
||||
addActionListener {
|
||||
missingMods.forEach {
|
||||
openUrl(it)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}, BorderLayout.EAST)
|
||||
|
||||
// Errored label
|
||||
@ -154,8 +122,16 @@ class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFutu
|
||||
// Left buttons
|
||||
add(JPanel().apply {
|
||||
add(JButton("Report issue").apply {
|
||||
addActionListener {
|
||||
openUrl("https://github.com/packwiz/packwiz-installer/issues/new")
|
||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||
addActionListener {
|
||||
try {
|
||||
Desktop.getDesktop().browse(URI("https://github.com/packwiz/packwiz-installer/issues/new"))
|
||||
} catch (e: IOException) {
|
||||
// lol the button just won't work i guess
|
||||
} catch (e: URISyntaxException) {}
|
||||
}
|
||||
} else {
|
||||
isEnabled = false
|
||||
}
|
||||
})
|
||||
}, BorderLayout.WEST)
|
||||
|
Loading…
x
Reference in New Issue
Block a user