Skip to content

Adding a check if the app is steam, forcing internal path for steam c…#493

Open
jks211 wants to merge 1 commit intoutkarshdalal:masterfrom
jks211:non-steam-external-storage-fix
Open

Adding a check if the app is steam, forcing internal path for steam c…#493
jks211 wants to merge 1 commit intoutkarshdalal:masterfrom
jks211:non-steam-external-storage-fix

Conversation

@jks211
Copy link

@jks211 jks211 commented Feb 5, 2026

…lient reference for non-steam apps


Summary by cubic

Fixes app directory selection for steamclient DLL by detecting Steam vs non-Steam apps. Non-Steam apps now use the internal path; Steam apps use external storage only when enabled.

  • Bug Fixes
    • Added steamApp flag to getAppDirPath to choose internal for non-Steam and external for Steam.
    • Updated replaceSteamclientDll to pass the Steam source check.
    • Prioritized legacy installs by checking existing internal paths before external.

Written for commit 3691ee8. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor
    • Enhanced application storage path management logic to better handle directory resolution across different storage configurations.

@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Added a new overloaded getAppDirPath() function to SteamService that accepts a steamApp boolean parameter to conditionally select between internal and external storage paths. Updated SteamUtils to import GameSource and invoke the new overload with a source-derived flag.

Changes

Cohort / File(s) Summary
SteamService API Extension
app/src/main/java/app/gamenative/service/SteamService.kt
Added overloaded getAppDirPath(gameId: Int, steamApp: Boolean) function that branches path resolution based on the steamApp flag, preferring external storage when enabled and checking both internal/external paths with legacy name variants.
SteamUtils Integration
app/src/main/java/app/gamenative/utils/SteamUtils.kt
Added GameSource import and updated replaceSteamclientDll to call the new getAppDirPath overload with a boolean derived from app source detection.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 A path once singular, now splits in two,
Steam-aware and bright, the new branch grew,
Internal or external, the flag decides,
Where the game finds home, logic guides,
Storage flexibility hops along! 🎮

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately reflects the main change: adding a check for Steam apps and handling internal path logic for Steam client references in non-Steam apps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jks211
Copy link
Author

jks211 commented Feb 5, 2026

Screenshot 2026-02-04 221922 Screenshot 2026-02-04 222937 Screenshot 2026-02-04 222545

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/main/java/app/gamenative/utils/SteamUtils.kt`:
- Around line 230-233: The contains-based source check is fragile; use
ContainerUtils.extractGameSourceFromContainerId(appId) instead of
appId.contains("${GameSource.STEAM.name}") in replaceSteamclientDll so the
source is derived via prefix matching. Keep steamAppId as
ContainerUtils.extractGameIdFromContainerId(appId), call
ContainerUtils.extractGameSourceFromContainerId(appId) to get the source value,
and pass that result into SteamService.getAppDirPath(steamAppId, <source>)
rather than the boolean contains expression.

Comment on lines 230 to 233
suspend fun replaceSteamclientDll(context: Context, appId: String) {
val steamAppId = ContainerUtils.extractGameIdFromContainerId(appId)
val appDirPath = SteamService.getAppDirPath(steamAppId)
val appDirPath = SteamService.getAppDirPath(steamAppId, (appId.contains("${GameSource.STEAM.name}")))
val container = ContainerUtils.getContainer(context, appId)
Copy link

@coderabbitai coderabbitai bot Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for GameSource enum definition
rg -n "enum class GameSource" --type kotlin -A 10

Repository: utkarshdalal/GameNative

Length of output: 855


🏁 Script executed:

# Look at ContainerUtils helpers for source detection or ID parsing
rg -n "object ContainerUtils|class ContainerUtils" --type kotlin -A 5

Repository: utkarshdalal/GameNative

Length of output: 560


🏁 Script executed:

# Search for container ID construction and format patterns
rg -n "containerId|container.*id" --type kotlin app/src/main/java | head -30

Repository: utkarshdalal/GameNative

Length of output: 4541


🏁 Script executed:

# Check how source detection is done elsewhere in the codebase
rg -n "GameSource\." --type kotlin | head -40

Repository: utkarshdalal/GameNative

Length of output: 4805


🏁 Script executed:

# Look at the actual function context in SteamUtils.kt around line 230-233
cat -n app/src/main/java/app/gamenative/utils/SteamUtils.kt | sed -n '220,250p'

Repository: utkarshdalal/GameNative

Length of output: 1718


🏁 Script executed:

rg -n "fun extractGameSourceFromContainerId" -A 10 --type kotlin

Repository: utkarshdalal/GameNative

Length of output: 1228


Use the existing extractGameSourceFromContainerId() helper for source detection.

The .contains() check is weaker than necessary. The ContainerUtils class already provides extractGameSourceFromContainerId() which properly uses prefix matching (startsWith()). Use that instead to extract the source explicitly and pass the result.

Suggested fix
    suspend fun replaceSteamclientDll(context: Context, appId: String) {
        val steamAppId = ContainerUtils.extractGameIdFromContainerId(appId)
-       val appDirPath = SteamService.getAppDirPath(steamAppId, (appId.contains("${GameSource.STEAM.name}")))
+       val gameSource = ContainerUtils.extractGameSourceFromContainerId(appId)
+       val appDirPath = SteamService.getAppDirPath(steamAppId, (gameSource == GameSource.STEAM))
        val container = ContainerUtils.getContainer(context, appId)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
suspend fun replaceSteamclientDll(context: Context, appId: String) {
val steamAppId = ContainerUtils.extractGameIdFromContainerId(appId)
val appDirPath = SteamService.getAppDirPath(steamAppId)
val appDirPath = SteamService.getAppDirPath(steamAppId, (appId.contains("${GameSource.STEAM.name}")))
val container = ContainerUtils.getContainer(context, appId)
suspend fun replaceSteamclientDll(context: Context, appId: String) {
val steamAppId = ContainerUtils.extractGameIdFromContainerId(appId)
val gameSource = ContainerUtils.extractGameSourceFromContainerId(appId)
val appDirPath = SteamService.getAppDirPath(steamAppId, (gameSource == GameSource.STEAM))
val container = ContainerUtils.getContainer(context, appId)
🤖 Prompt for AI Agents
In `@app/src/main/java/app/gamenative/utils/SteamUtils.kt` around lines 230 - 233,
The contains-based source check is fragile; use
ContainerUtils.extractGameSourceFromContainerId(appId) instead of
appId.contains("${GameSource.STEAM.name}") in replaceSteamclientDll so the
source is derived via prefix matching. Keep steamAppId as
ContainerUtils.extractGameIdFromContainerId(appId), call
ContainerUtils.extractGameSourceFromContainerId(appId) to get the source value,
and pass that result into SteamService.getAppDirPath(steamAppId, <source>)
rather than the boolean contains expression.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose I should take this recommendation, can see potential bugs with epic and gog games that the name "Steam"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jks211, great catch! Yes, using extractGameSourceFromContainerId() will properly handle edge cases where game names or IDs might contain the string "STEAM" for non-Steam sources like Epic or GOG. The prefix-matching approach in that helper is more robust and prevents false positives.


🧠 Learnings used
Learnt from: utkarshdalal
Repo: utkarshdalal/GameNative PR: 344
File: app/src/main/java/app/gamenative/service/SteamAutoCloud.kt:415-419
Timestamp: 2025-12-17T05:14:05.133Z
Learning: In SteamAutoCloud.kt, when uploading files to Steam Cloud API (beginFileUpload and commitFileUpload), the filename parameter intentionally uses different formats: `file.path + file.filename` (relative path without placeholder) when `appInfo.ufs.saveFilePatterns.isEmpty()` is true (fallback case), and `file.prefixPath` (includes placeholder like %SteamUserData%) when patterns are configured. This difference is by design.

Learnt from: utkarshdalal
Repo: utkarshdalal/GameNative PR: 176
File: app/src/main/java/app/gamenative/utils/SteamUtils.kt:651-655
Timestamp: 2025-09-28T13:54:16.048Z
Learning: In the GameNative project, when creating depots.txt files in SteamUtils.ensureSteamSettings, only create the file when SteamService.getInstalledDepotsOf() returns actual data (non-null). Don't create empty files or write empty strings when no data is available.

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.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a ContainerUtil that has "ExtractGameSourceFromAppId" for this

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@jks211
Copy link
Author

jks211 commented Feb 5, 2026

I realize that probably overloading this utils function isn't good architectural hygiene, I was going for a quicker fix to avoid refactoring but if there is a less invasive way of doing it properly let me know.

Comment on lines +739 to +763
fun getAppDirPath(gameId: Int, steamApp: Boolean): String {

val info = getAppInfoOf(gameId)
val appName = getAppDirName(info)
val oldName = info?.name.orEmpty()

// Internal first (legacy installs), external second
val internalPath = Paths.get(internalAppInstallPath, appName)
if (Files.exists(internalPath)) return internalPath.pathString
val internalOld = Paths.get(internalAppInstallPath, oldName)
if (oldName.isNotEmpty() && Files.exists(internalOld)) return internalOld.pathString

val externalPath = Paths.get(externalAppInstallPath, appName)
val externalOld = Paths.get(externalAppInstallPath, oldName)
if (steamApp) {
if (Files.exists(externalPath)) return externalPath.pathString
if (oldName.isNotEmpty() && Files.exists(externalOld)) return externalOld.pathString
}

// Nothing on disk yet – default to whatever location you want new installs to use
if (PrefManager.useExternalStorage && steamApp) {
return externalPath.pathString
}
return internalPath.pathString
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a copy of the getAppDirPath method, with an extra param?

            if (steamApp) {
                if (Files.exists(externalPath)) return externalPath.pathString
                if (oldName.isNotEmpty() && Files.exists(externalOld)) return externalOld.pathString
            }

I see only that changed. Why only if it's a steam app?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants