From 0ccdacff9a43d1e16b62c9edc541bc1ad3cdc69b Mon Sep 17 00:00:00 2001 From: ProRapSuperstarOriginalMaster <154511084+ProRapSuperstarOriginalMaster@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:59:20 +0100 Subject: [PATCH 1/3] Separated downloadPath from InstallPath in order to allow for staging operations that benefit SD cards --- .../depotdownloader/DepotDownloader.kt | 30 ++++++++++++------- .../depotdownloader/data/DownloadItems.kt | 2 ++ .../_023_downloadapp/SampleDownloadApp.java | 1 + 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt b/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt index 3a8498f5..6fce9eaf 100644 --- a/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt +++ b/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt @@ -156,6 +156,8 @@ class DepotDownloader @JvmOverloads constructor( private val progressUpdateInterval = 500L // ms + private var lastProgressUpdate = 0L + private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob(parentJob)) private var cdnClientPool: CDNClientPool? = null @@ -211,6 +213,7 @@ class DepotDownloader @JvmOverloads constructor( val androidEmulation: Boolean = false, val downloadManifestOnly: Boolean = false, val installToGameNameDirectory: Boolean = false, + val downloadPath: Path? = null, // Not used yet in code val usingFileList: Boolean = false, @@ -1571,7 +1574,8 @@ class DepotDownloader @JvmOverloads constructor( ensureActive() // Create temporary file path for this chunk - val chunkTempDir = depot.installDir / STAGING_DIR / "chunks" / fileId + // Try to set it to the Download path, use installdir as fallback, probably unessecary + val chunkTempDir = (config.downloadPath ?: depot.installDir) / STAGING_DIR / "chunks" / fileId filesystem.createDirectories(chunkTempDir) val chunkTempPath = chunkTempDir / "${chunk.offset}_$chunkID.chunk" @@ -1727,6 +1731,7 @@ class DepotDownloader @JvmOverloads constructor( downloadManifestOnly = item.downloadManifestOnly, installPath = item.installDirectory?.toPath(), installToGameNameDirectory = item.installToGameNameDirectory, + downloadPath = (item as? AppItem)?.downloadDirectory?.toPath(), ) processingItemsMap[item.appId] = item @@ -1835,7 +1840,7 @@ class DepotDownloader @JvmOverloads constructor( val file = item.file val fileFinalPath = depot.installDir / file.fileName val chunk = item.chunk - val chunkTempDir = depot.installDir / STAGING_DIR / "chunks" / item.fileId + val chunkTempDir = (config.downloadPath ?: depot.installDir) / STAGING_DIR / "chunks" / item.fileId val writeOffset = file.chunks.filter { it.offset < chunk.offset }.sumOf { it.uncompressedLength.toLong() } @@ -1888,14 +1893,19 @@ class DepotDownloader @JvmOverloads constructor( } val depotPercentage = (sizeDownloaded.toFloat() / depotDownloadCounter.completeDownloadSize) - - notifyListeners { listener -> - listener.onChunkCompleted( - depotId = depot.depotId, - depotPercentComplete = depotPercentage, - compressedBytes = downloadCounter.totalBytesCompressed, - uncompressedBytes = downloadCounter.totalBytesUncompressed - ) + // Limiting the listener calls to once every 0.5s significantly improves performance on SD cards + val now = System.currentTimeMillis() + if (now - lastProgressUpdate >= progressUpdateInterval) { + lastProgressUpdate = now + logger?.debug("Chunk progress update") + notifyListeners { listener -> + listener.onChunkCompleted( + depotId = depot.depotId, + depotPercentComplete = depotPercentage, + compressedBytes = downloadCounter.totalBytesCompressed, + uncompressedBytes = downloadCounter.totalBytesUncompressed + ) + } } val remainingDownloads = item.fileStreamData.chunksDownloaded.decrementAndGet() diff --git a/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/data/DownloadItems.kt b/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/data/DownloadItems.kt index 813e0b52..d3cceda7 100644 --- a/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/data/DownloadItems.kt +++ b/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/data/DownloadItems.kt @@ -70,6 +70,7 @@ class PubFileItem @JvmOverloads constructor( * @property lowViolence If true, downloads low-violence versions where available * @property depot List of specific depot IDs to download * @property manifest List of specific manifest IDs corresponding to depot IDs + * @property downloadDirectory Separate directory for downloading and staging an app/game * * @author Lossy * @since Oct 1, 2025 @@ -89,6 +90,7 @@ class AppItem @JvmOverloads constructor( val lowViolence: Boolean = false, val depot: List = emptyList(), val manifest: List = emptyList(), + val downloadDirectory: String? = null, verify: Boolean = false, downloadManifestOnly: Boolean = false, ) : DownloadItem(appId, installDirectory, installToGameNameDirectory, verify, downloadManifestOnly) diff --git a/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java b/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java index 1305d187..4d8b9988 100644 --- a/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java +++ b/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java @@ -290,6 +290,7 @@ private void downloadApp() { /* (Optional) lowViolence */ false, /* (Optional) depot */ List.of(), /* (Optional) manifest */ List.of(), + /* (Optional) downloadManifestOnly */ null, /* (Optional) verify */ false, /* (Optional) downloadManifestOnly */ false ); From 9300c03c0cf83082a1b1c0abe35a86b723f67415 Mon Sep 17 00:00:00 2001 From: ProRapSuperstarOriginalMaster <154511084+ProRapSuperstarOriginalMaster@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:44:09 +0100 Subject: [PATCH 2/3] Made downloadPath fit better into style of previous code --- .../dragonbra/javasteam/depotdownloader/DepotDownloader.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt b/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt index 6fce9eaf..134a30c1 100644 --- a/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt +++ b/javasteam-depotdownloader/src/main/kotlin/in/dragonbra/javasteam/depotdownloader/DepotDownloader.kt @@ -1574,7 +1574,7 @@ class DepotDownloader @JvmOverloads constructor( ensureActive() // Create temporary file path for this chunk - // Try to set it to the Download path, use installdir as fallback, probably unessecary + // Try to set it to the Download path, use installdir as fallback val chunkTempDir = (config.downloadPath ?: depot.installDir) / STAGING_DIR / "chunks" / fileId filesystem.createDirectories(chunkTempDir) val chunkTempPath = chunkTempDir / "${chunk.offset}_$chunkID.chunk" @@ -1731,7 +1731,6 @@ class DepotDownloader @JvmOverloads constructor( downloadManifestOnly = item.downloadManifestOnly, installPath = item.installDirectory?.toPath(), installToGameNameDirectory = item.installToGameNameDirectory, - downloadPath = (item as? AppItem)?.downloadDirectory?.toPath(), ) processingItemsMap[item.appId] = item @@ -1750,6 +1749,8 @@ class DepotDownloader @JvmOverloads constructor( } is AppItem -> { + config = config.copy(downloadPath = item.downloadDirectory?.toPath()) + val branch = item.branch ?: DEFAULT_BRANCH config = config.copy(betaPassword = item.branchPassword) From 74374f11dca8664ff6cfdbdb259e686d5aea2ca0 Mon Sep 17 00:00:00 2001 From: ProRapSuperstarOriginalMaster <154511084+ProRapSuperstarOriginalMaster@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:03:23 +0100 Subject: [PATCH 3/3] Corrected val name in test --- .../javasteamsamples/_023_downloadapp/SampleDownloadApp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java b/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java index 4d8b9988..0b62b5fb 100644 --- a/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java +++ b/javasteam-samples/src/main/java/in/dragonbra/javasteamsamples/_023_downloadapp/SampleDownloadApp.java @@ -290,7 +290,7 @@ private void downloadApp() { /* (Optional) lowViolence */ false, /* (Optional) depot */ List.of(), /* (Optional) manifest */ List.of(), - /* (Optional) downloadManifestOnly */ null, + /* (Optional) downloadDirectory */ null, /* (Optional) verify */ false, /* (Optional) downloadManifestOnly */ false );