Added language support for Epic (also shrinks game sizes)#754
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds container-language-aware install-tag mapping and selection for Epic downloads, updates download APIs to accept a containerLanguage, and extends ManifestUtils to compute files/chunks/sizes based on selected install tags with fallback to English. Changes
Sequence DiagramsequenceDiagram
actor User
participant EpicAppScreen
participant EpicService
participant EpicDownloadManager
participant EpicConstants
participant ManifestUtils
User->>EpicAppScreen: initiate download
EpicAppScreen->>EpicAppScreen: loadContainerData()
EpicAppScreen->>EpicService: downloadGame(..., containerLanguage)
EpicService->>EpicDownloadManager: downloadGame(..., containerLanguage)
EpicDownloadManager->>EpicConstants: containerLanguageToEpicInstallTags(containerLanguage)
EpicConstants-->>EpicDownloadManager: selectedTags
EpicDownloadManager->>ManifestUtils: getFilesForSelectedInstallTags(manifest, selectedTags)
ManifestUtils-->>EpicDownloadManager: files
EpicDownloadManager->>ManifestUtils: getRequiredChunksForFileList(manifest, files)
ManifestUtils-->>EpicDownloadManager: chunks
rect rgba(200,100,100,0.5)
alt chunks exist AND files non-empty
EpicDownloadManager->>ManifestUtils: getSizesForSelectedInstallTags(manifest, selectedTags)
ManifestUtils-->>EpicDownloadManager: (downloadSize, installSize)
EpicDownloadManager->>EpicDownloadManager: proceed with download using sizes
else missing chunks OR no matching files
EpicDownloadManager-->>EpicDownloadManager: fail with descriptive error
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
3 issues found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="app/src/main/java/app/gamenative/service/epic/EpicService.kt">
<violation number="1" location="app/src/main/java/app/gamenative/service/epic/EpicService.kt:349">
P2: Download became language-dependent, but manifest size calculation/precheck still ignores language tags, causing potentially incorrect install/download size estimates and disk-space gating.</violation>
</file>
<file name="app/src/main/java/app/gamenative/service/epic/EpicManager.kt">
<violation number="1" location="app/src/main/java/app/gamenative/service/epic/EpicManager.kt:955">
P2: `fetchManifestSizes` now returns required-only sizes via `emptyList()` tags, which can underestimate install/download requirements in callers that use it for install space checks.</violation>
</file>
<file name="app/src/main/java/app/gamenative/service/epic/EpicDownloadManager.kt">
<violation number="1" location="app/src/main/java/app/gamenative/service/epic/EpicDownloadManager.kt:136">
P2: DLC download path bypasses new install-tag language filtering and still downloads unfiltered manifest content.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| } | ||
|
|
||
| fun downloadGame(context: Context, appId: Int, dlcGameIds: List<Int>, installPath: String): Result<DownloadInfo> { | ||
| fun downloadGame(context: Context, appId: Int, dlcGameIds: List<Int>, installPath: String, containerLanguage: String): Result<DownloadInfo> { |
There was a problem hiding this comment.
P2: Download became language-dependent, but manifest size calculation/precheck still ignores language tags, causing potentially incorrect install/download size estimates and disk-space gating.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/service/epic/EpicService.kt, line 349:
<comment>Download became language-dependent, but manifest size calculation/precheck still ignores language tags, causing potentially incorrect install/download size estimates and disk-space gating.</comment>
<file context>
@@ -346,7 +346,7 @@ class EpicService : Service() {
}
- fun downloadGame(context: Context, appId: Int, dlcGameIds: List<Int>, installPath: String): Result<DownloadInfo> {
+ fun downloadGame(context: Context, appId: Int, dlcGameIds: List<Int>, installPath: String, containerLanguage: String): Result<DownloadInfo> {
val instance = getInstance() ?: return Result.failure(Exception("Service not available"))
</file context>
| val installSize = manifest.fileManifestList?.elements?.sumOf { it.fileSize } ?: 0L | ||
| val downloadSize = app.gamenative.service.epic.manifest.ManifestUtils.getTotalDownloadSize(manifest) | ||
| // Required-only sizes for detail page display (download uses container language via getSizesForSelectedInstallTags elsewhere). | ||
| val (downloadSize, installSize) = app.gamenative.service.epic.manifest.ManifestUtils.getSizesForSelectedInstallTags(manifest, emptyList()) |
There was a problem hiding this comment.
P2: fetchManifestSizes now returns required-only sizes via emptyList() tags, which can underestimate install/download requirements in callers that use it for install space checks.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/service/epic/EpicManager.kt, line 955:
<comment>`fetchManifestSizes` now returns required-only sizes via `emptyList()` tags, which can underestimate install/download requirements in callers that use it for install space checks.</comment>
<file context>
@@ -951,9 +951,8 @@ class EpicManager @Inject constructor(
- val installSize = manifest.fileManifestList?.elements?.sumOf { it.fileSize } ?: 0L
- val downloadSize = app.gamenative.service.epic.manifest.ManifestUtils.getTotalDownloadSize(manifest)
+ // Required-only sizes for detail page display (download uses container language via getSizesForSelectedInstallTags elsewhere).
+ val (downloadSize, installSize) = app.gamenative.service.epic.manifest.ManifestUtils.getSizesForSelectedInstallTags(manifest, emptyList())
Timber.tag("Epic").d(
"Manifest stats for $appName: version=${manifest.version}, featureLevel=${manifest.meta?.featureLevel}, " +
</file context>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/main/java/app/gamenative/service/epic/EpicDownloadManager.kt`:
- Around line 134-137: The current code computes totalInstalledSize from unique
chunk windowSize (via chunks) which measures payload, not the actual selected
files; replace that calculation by using
ManifestUtils.getSizesForSelectedInstallTags(selectedTags, manifest) (or the
provided getSizesForSelectedInstallTags function that accepts the manifest and
selected tags) to compute installSize based on file.fileSize for the files
variable, then assign that value to updatedGame.installSize before calling
epicManager.updateGame(updatedGame); update references to
totalInstalledSize/installSize in the block that follows the
selectedTags/files/chunks creation so the stored install size reflects selected
files rather than chunk window sizes.
- Around line 75-76: The DLC download flow currently only applies install tags
(including containerLanguage) to the base manifest; update the logic so that for
each dlcId you fetch its manifest, call the same tag application routine
(preserving containerLanguage) before the size prepass and before invoking
downloadGameWithManifest(), and ensure the size prepass uses these per-DLC
tagged manifests rather than the full untagged manifests; modify the loop
handling dlcIds and the calls to downloadGameWithManifest() and the size-prepass
helper so they accept/consume the tagged DLC manifest objects.
In `@app/src/main/java/app/gamenative/service/epic/EpicManager.kt`:
- Around line 954-955: fetchManifestSizes() currently calls
ManifestUtils.getSizesForSelectedInstallTags(manifest, emptyList()) which
hardcodes required-only sizes; update the call to pass the same install-tag
language used at download time so displayed sizes match actual download sizes
(e.g., pass the container/install tags derived from containerData.language or
the selected install tags stored on the manifest/epic app state). Locate the
call to getSizesForSelectedInstallTags in EpicManager.fetchManifestSizes() and
replace emptyList() with the appropriate install-tag list (the same source used
by EpicAppScreen.performDownload()), ensuring the function receives the
language/tag selection used when performing downloads.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 83bb8fc1-7e95-4e01-9ca9-c278981286bb
📒 Files selected for processing (6)
app/src/main/java/app/gamenative/service/epic/EpicConstants.ktapp/src/main/java/app/gamenative/service/epic/EpicDownloadManager.ktapp/src/main/java/app/gamenative/service/epic/EpicManager.ktapp/src/main/java/app/gamenative/service/epic/EpicService.ktapp/src/main/java/app/gamenative/service/epic/manifest/ManifestUtils.ktapp/src/main/java/app/gamenative/ui/screen/library/appscreen/EpicAppScreen.kt
| containerLanguage: String = EpicConstants.EPIC_FALLBACK_CONTAINER_LANGUAGE, | ||
| dlcIds: List<Int>, |
There was a problem hiding this comment.
DLC downloads still ignore containerLanguage.
Lines 135-137 apply install tags to the base manifest only. The DLC size prepass and the later downloadGameWithManifest() path still use full manifests, so selecting DLCs falls back to downloading every tagged language package for those manifests.
Suggested direction
- private suspend fun downloadGameWithManifest(
+ private suspend fun downloadGameWithManifest(
context: Context,
game: EpicGame,
manifestData: EpicManager.ManifestResult,
installPath: String,
downloadInfo: DownloadInfo,
+ selectedTags: List<String>,
): Result<Unit> = withContext(Dispatchers.IO) {
@@
- val chunks = chunkDataList.elements
- val files = fileManifestList.elements
+ val files = ManifestUtils.getFilesForSelectedInstallTags(manifest, selectedTags)
+ val chunks = ManifestUtils.getRequiredChunksForFileList(manifest, files)Also applies to: 134-137
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src/main/java/app/gamenative/service/epic/EpicDownloadManager.kt` around
lines 75 - 76, The DLC download flow currently only applies install tags
(including containerLanguage) to the base manifest; update the logic so that for
each dlcId you fetch its manifest, call the same tag application routine
(preserving containerLanguage) before the size prepass and before invoking
downloadGameWithManifest(), and ensure the size prepass uses these per-DLC
tagged manifests rather than the full untagged manifests; modify the loop
handling dlcIds and the calls to downloadGameWithManifest() and the size-prepass
helper so they accept/consume the tagged DLC manifest objects.
There was a problem hiding this comment.
@phobos665 Yes, the issue is still present in the current code. Here's a quick summary of what's unfixed:
-
DLC size prepass — the loop that fetches DLC manifests and sums sizes uses
dlcParsed.chunkDataList?.elementsdirectly (the full, unfiltered chunk list), ignoring theselectedTagsderived fromcontainerLanguage. -
downloadGameWithManifest()— the private helper used for each DLC still reads the rawchunkDataList.elementsandfileManifestList.elementswithout any tag filtering:val chunks = chunkDataList.elements val files = fileManifestList.elements
-
Call site —
downloadGameWithManifestis called without forwardingselectedTags.
The fix direction from the original review is still valid — downloadGameWithManifest needs a selectedTags: List<String> parameter, and both the size prepass and the assembly path need to use ManifestUtils.getFilesForSelectedInstallTags / ManifestUtils.getRequiredChunksForFileList for DLC manifests, just as the base game already does.
🧠 Learnings used
Learnt from: phobos665
Repo: utkarshdalal/GameNative PR: 418
File: app/src/main/java/app/gamenative/service/gog/GOGManager.kt:270-282
Timestamp: 2026-01-16T17:32:12.974Z
Learning: In the GOG implementation for GameNative, DLC items should be excluded from the library view using the `isDlc` flag in the exclude condition. The library should only display base games. DLC download decisions are handled separately via the `withDlcs` parameter in GOGDownloadManager and related filtering logic, not through library visibility.
Learnt from: utkarshdalal
Repo: utkarshdalal/GameNative PR: 159
File: app/src/main/java/app/gamenative/service/DownloadService.kt:6-6
Timestamp: 2025-09-19T17:07:27.941Z
Learning: In app/src/main/java/app/gamenative/service/DownloadService.kt, the getSizeFromStoreDisplay() function uses runBlocking to call SteamService.getDownloadableDepots() because the latter was converted from synchronous to suspend in this PR. The user confirmed the previous synchronous implementation worked fine, and if performance is acceptable, keeping runBlocking is a valid approach.
Learnt from: jeremybernstein
Repo: utkarshdalal/GameNative PR: 581
File: app/src/main/java/app/gamenative/ui/PluviaMain.kt:1154-1176
Timestamp: 2026-02-21T22:26:41.871Z
Learning: In Kotlin coroutines, suspend functions automatically suspend and resume within a coroutine scope. Only Deferred objects produced by async { ... } require .await() to obtain the result. Do not call .await() on direct suspend function calls or on non-Deferred results; use await() only when you have a Deferred that represents a value you need.
| // Use container language (same as GOG) to select install tags: required + optional language files. | ||
| val selectedTags = EpicConstants.containerLanguageToEpicInstallTags(containerLanguage) | ||
| val files = ManifestUtils.getFilesForSelectedInstallTags(manifest, selectedTags) | ||
| val chunks = ManifestUtils.getRequiredChunksForFileList(manifest, files) |
There was a problem hiding this comment.
Use selected file sizes for installSize.
Line 159 still derives totalInstalledSize from unique chunk windowSizes. That measures chunk payload, not the selected files that land on disk, so the value later written via epicManager.updateGame(updatedGame) can drift from the real install size. ManifestUtils.getSizesForSelectedInstallTags() already calculates this from file.fileSize; reuse it here.
Suggested fix
val selectedTags = EpicConstants.containerLanguageToEpicInstallTags(containerLanguage)
val files = ManifestUtils.getFilesForSelectedInstallTags(manifest, selectedTags)
val chunks = ManifestUtils.getRequiredChunksForFileList(manifest, files)
@@
- var totalDownloadSize = chunks.sumOf { it.fileSize }
- var totalInstalledSize = chunks.sumOf { it.windowSize.toLong() }
+ val (baseDownloadSize, baseInstalledSize) =
+ ManifestUtils.getSizesForSelectedInstallTags(manifest, selectedTags)
+ var totalDownloadSize = baseDownloadSize
+ var totalInstalledSize = baseInstalledSizeAlso applies to: 157-160
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src/main/java/app/gamenative/service/epic/EpicDownloadManager.kt` around
lines 134 - 137, The current code computes totalInstalledSize from unique chunk
windowSize (via chunks) which measures payload, not the actual selected files;
replace that calculation by using
ManifestUtils.getSizesForSelectedInstallTags(selectedTags, manifest) (or the
provided getSizesForSelectedInstallTags function that accepts the manifest and
selected tags) to compute installSize based on file.fileSize for the files
variable, then assign that value to updatedGame.installSize before calling
epicManager.updateGame(updatedGame); update references to
totalInstalledSize/installSize in the block that follows the
selectedTags/files/chunks creation so the stored install size reflects selected
files rather than chunk window sizes.
| // Required-only sizes for detail page display (download uses container language via getSizesForSelectedInstallTags elsewhere). | ||
| val (downloadSize, installSize) = app.gamenative.service.epic.manifest.ManifestUtils.getSizesForSelectedInstallTags(manifest, emptyList()) |
There was a problem hiding this comment.
fetchManifestSizes() is now hardcoded to required-only.
Line 955 passes emptyList() into getSizesForSelectedInstallTags(), so the library page only stores untagged-file sizes. EpicAppScreen.performDownload() later passes containerData.language into the real download path, which means non-English installs can be larger than the size we show before install.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src/main/java/app/gamenative/service/epic/EpicManager.kt` around lines
954 - 955, fetchManifestSizes() currently calls
ManifestUtils.getSizesForSelectedInstallTags(manifest, emptyList()) which
hardcodes required-only sizes; update the call to pass the same install-tag
language used at download time so displayed sizes match actual download sizes
(e.g., pass the container/install tags derived from containerData.language or
the selected install tags stored on the manifest/epic app state). Locate the
call to getSizesForSelectedInstallTags in EpicManager.fetchManifestSizes() and
replace emptyList() with the appropriate install-tag list (the same source used
by EpicAppScreen.performDownload()), ensuring the function receives the
language/tag selection used when performing downloads.
1384194 to
9805f4c
Compare
Currently it downloads all files with all tags.. Only files with "no tags" are required. And language specific files would be located under a "language" tag. So implemented that.
Summary by cubic
Adds language-aware downloads for Epic. We now install required files plus the selected container language to cut download/install sizes and match the GOG/Steam language setting.
Written for commit 9805f4c. Summary will update on new commits.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes