Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom wine prefixes #50

Closed
kourm opened this issue Sep 24, 2020 · 11 comments
Closed

Add support for custom wine prefixes #50

kourm opened this issue Sep 24, 2020 · 11 comments
Labels
enhancement New feature or request
Milestone

Comments

@kourm
Copy link

kourm commented Sep 24, 2020

Currently, ludusavi only supports creating backups of wine/proton saves for steam games. Since there are many games that aren't available through steam/available for free somewhere else, adding support for different/custom wine prefixes is very desirable for integration in third party launchers & normal usage.

I'm looking into adding backup support to steam-buddy for gamer-os, which will add support for EGS games in the next release, while using steams shortcut system for the proton integration with predictably generated game ids.

For this purpose, calling ludusavi separately for each game is alright, so a CLI option would suffice, with the mapping (wine prefix <-> game) handled by steam-buddy

@mtkennerly
Copy link
Owner

Integration with Steam Buddy sounds like a great idea!

Could you tell me a little bit more about the functionality you would need for your use case? I assume you're mainly interested in these Windows -> Proton mappings, but without the associated Steam assumptions:

ludusavi/src/prelude.rs

Lines 275 to 305 in 23ab816

if get_os() == Os::Linux && root.store == Store::Steam && steam_id.is_some() {
let prefix = format!(
"{}/steamapps/compatdata/{}/pfx/drive_c",
root.path.interpret(),
steam_id.unwrap()
);
paths.insert(
path.replace("<root>", &root.path.interpret())
.replace("<game>", &install_dir)
.replace(
"<base>",
&format!("{}/steamapps/common/{}", root.path.interpret(), install_dir),
)
.replace("<home>", &format!("{}/users/steamuser", prefix))
.replace("<storeUserId>", "*")
.replace("<osUserName>", "steamuser")
.replace("<winAppData>", &format!("{}/users/steamuser/Application Data", prefix))
.replace(
"<winLocalAppData>",
&format!("{}/users/steamuser/Application Data", prefix),
)
.replace("<winDocuments>", &format!("{}/users/steamuser/My Documents", prefix))
.replace("<winPublic>", &format!("{}/users/Public", prefix))
.replace("<winProgramData>", &format!("{}/ProgramData", prefix))
.replace("<winDir>", &format!("{}/windows", prefix))
.replace("<xdgData>", &check_nonwindows_path(dirs::data_dir()))
.replace("<xdgConfig>", &check_nonwindows_path(dirs::config_dir()))
.replace("<regHkcu>", SKIP)
.replace("<regHklm>", SKIP),
);
}

I'm not sure which of those mappings are accurate for Wine and Proton when used without Steam, and some like <home> = {prefix}/users/steamuser definitely aren't. Do you happen to have any info about the mappings you'd need?

@mtkennerly mtkennerly added the enhancement New feature or request label Sep 24, 2020
@kourm
Copy link
Author

kourm commented Sep 25, 2020

So, proton currently (see ValveSoftware/Proton#605) always uses "steamuser" as the wine username (https://github.com/ValveSoftware/wine/blob/2409bd1f74be116172688a25df725290637c255a/dlls/advapi32/advapi.c#L87), so if we only support proton for now, we can keep that.

When not using steam games with proton, we need to adjust the prefix.

Since steam-buddy currently uses steams shortcut system with predictable steamids/app ids, it would suffice to be able to supply this app id for a given game (https://github.com/gamer-os/steam-tweaks/blob/ce2b0f13efbd61ec4325e8f6b287e4f270b9fb42/steam-shortcuts#L11). Even if it's the same game, the app id won't match the steamid if bought from steam.

AFAIK, most launchers (lutris & gamehub, maybe playonlinux, legendary) don't use steam for that purpose, so the prefixes depend on the launcher/user settings. For example:

  • Legendary uses the system wine & system prefix per default (although configurable), which means it's ~/.wine or ~/.wine/pfx when using proton.
  • Gamehub places it alongside the game, for example ~/Games/GOG/Serious_Sam_The_First_Encounter/_gamehub/compat/proton_latest/pfx (but this is probably configurable, can't check right now)

So doing it automatically for most cases is probably impossible without a huge amount of effort, so I'd just add a command line option --prefix to set it for non-steam windows games. I'm not sure how to combine with multiple games in different places, but I can just call ludusavi separately for each game.

We can probably ignore wine for now & leave the username hardcoded.

@mtkennerly
Copy link
Owner

Got it, so when the CLI option is passed, it would check the configured roots (as it already does) plus check the additional prefix folder. For Wine, I might just have it check all user folders since I'm assuming there would typically only be one per prefix anyway.

Roughly what kind of timeline are you looking at for the integration? I could make a devcut for you to try out, probably this or next weekend.

@kourm
Copy link
Author

kourm commented Sep 25, 2020

Got it, so when the CLI option is passed, it would check the configured roots (as it already does) plus check the additional prefix folder.

Sound good!

Roughly what kind of timeline are you looking at for the integration?

There's really no set timeline, it's ready when it's ready.

@mtkennerly
Copy link
Owner

@kourm Took a little longer than I expected to get back to this, but I have a build ready for you to try out with a --wine-prefix option:

ludusavi-v0.9.0-post.3+9e84355-linux.zip

Let me know if you need an OpenGL build instead. For references, these are the mappings it uses:

ludusavi/src/prelude.rs

Lines 306 to 326 in 9e84355

if root.store == Store::OtherWine {
let prefix = format!("{}/drive_*", root.path.interpret());
paths.insert(
path.replace("<root>", &root.path.interpret())
.replace("<game>", &install_dir)
.replace("<base>", &format!("{}/{}", root.path.interpret(), install_dir))
.replace("<home>", &format!("{}/users/*", prefix))
.replace("<storeUserId>", "*")
.replace("<osUserName>", "*")
.replace("<winAppData>", &format!("{}/users/*/Application Data", prefix))
.replace("<winLocalAppData>", &format!("{}/users/*/Application Data", prefix))
.replace("<winDocuments>", &format!("{}/users/*/My Documents", prefix))
.replace("<winPublic>", &format!("{}/users/Public", prefix))
.replace("<winProgramData>", &format!("{}/ProgramData", prefix))
.replace("<winDir>", &format!("{}/windows", prefix))
.replace("<xdgData>", &check_nonwindows_path(dirs::data_dir()))
.replace("<xdgConfig>", &check_nonwindows_path(dirs::config_dir()))
.replace("<regHkcu>", SKIP)
.replace("<regHklm>", SKIP),
);
}

@kourm
Copy link
Author

kourm commented Dec 16, 2020

Thank you very much!

I need to test it a bit more, but it seems to pick up at least some games (although I'm running into issues with Pikuniku, but that may be because of wrong data in the wiki or some weird steam/windows path mangling).

@mtkennerly
Copy link
Owner

Ah, looks like Pikuniku stores saves in the registry, and I forgot to add registry handling in the Wine prefix code. Does it work like Steam/Proton where there are *.reg files directly inside of the prefix folder?

@kourm
Copy link
Author

kourm commented Dec 19, 2020

I tested it with proton, via the proton support for steam shortcuts.
Seems like it's (at least also) saved on the filesystem directly, but there's also stuff in the registry

[gamer@gameros ~]$ find -name Pikuniku
./.local/share/Steam/steamapps/compatdata/2153646982/pfx/drive_c/users/steamuser/AppData/LocalLow/Sectordub/Pikuniku
./.local/share/steam-buddy/content/epic-store/Pikuniku
[gamer@gameros ~]$ ls -lah ./.local/share/Steam/steamapps/compatdata/2153646982/pfx/drive_c/users/steamuser/AppData/LocalLow/Sectordub/Pikuniku/saves/
total 44K
drwxr-xr-x 1 gamer gamer  42 Dec 16 21:01 .
drwxr-xr-x 1 gamer gamer  40 Dec 16 21:01 ..
-rw-r--r-- 1 gamer gamer 41K Dec 16 21:22 PikunikuSaveFile_Epic
[gamer@gameros ~]$ ~/devel/backup/ludusavi-v0.9.0-post.3+9e84355-linux/ludusavi backup --wine-prefix ./.local/share/Steam/steamapps/compatdata/2153646982/pfx/ --preview | grep Pikuniku
[gamer@gameros ~]$ ls -lah ./.local/share/Steam/steamapps/compatdata/2153646982/pfx/
dosdevices/        drive_c/           system.reg         .update-timestamp  userdef.reg        user.reg
[gamer@gameros ~]$ ls -lah ./.local/share/Steam/steamapps/compatdata/2153646982/pfx/
total 2.5M
drwxr-xr-x 1 gamer gamer  126 Dec 16 21:01 .
drwxr-xr-x 1 gamer gamer   62 Dec 16 21:01 ..
drwxr-xr-x 1 gamer gamer   40 Dec 16 21:01 dosdevices
drwxr-xr-x 1 gamer gamer  126 Dec 16 21:01 drive_c
-rw-r--r-- 1 gamer gamer 2.5M Dec 16 21:01 system.reg
-rw-r--r-- 1 gamer gamer   12 Dec 16 21:01 .update-timestamp
-rw-r--r-- 1 gamer gamer 3.3K Dec 16 21:01 userdef.reg
-rw-r--r-- 1 gamer gamer  27K Dec 16 21:01 user.reg
[..]
[gamer@gameros pfx]$ cat user.reg | grep Pikuniku
[Software\\Sectordub\\Pikuniku] 1608148888

After some saving, it seems like the data in pcgamingwiki is wrong, as the registry mtime gets updated at the start, but the PikunikuSaveFile_Epic mtime gets updated when saving.

But TLDR: registry handling is the same as proton in wine (although for my usecase it's also just proton), checked separately

@mtkennerly
Copy link
Owner

Since the functionality is complete now with the touch-up commits above, I'm going to close this for tracking purposes. It's just waiting for the next release, which should be pretty soon. Here's the work remaining before the release: https://github.com/mtkennerly/ludusavi/milestone/8

@pktiuk
Copy link

pktiuk commented Jan 4, 2022

You could mention this feature in readme.

(I was looking for issue asking about this, and it appeared already resolved :) )

@mtkennerly
Copy link
Owner

It's covered under GUI > Backup mode, but it's collapsed by default. After expanding the section, look for For a Wine prefix root. I'd be happy to expand the info if anything's unclear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants