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

Detect games using proton #8

Merged
merged 4 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ release:
Don't panic, this is really simple.
1. (Optional) Switch to Desktop Mode on your Steam Deck.
1. Switch to Desktop Mode on your Steam Deck.
2. Use Chrome or Firefox to download `sd-ge-proton-updater` and run it.
3. Click Install.
3. Reboot your Steam Deck.
4. Wait a little while for it to download, verify and extract the latest installation of GE-Proton from the official GitHub repo. Timing highly depends on Internet connection speed.
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# About

This will automatically install the latest stable version of GloriousEggroll's proton-ge-custom fork. The fork includes many improvements to run games more betterer, including ones marked as unsupported by Valve.
This will automatically install the latest stable version of GloriousEggroll's proton-ge-custom fork. GE-Proton includes many improvements to run games more betterer, including many of the games marked as "unsupported" by Valve.

# How it works

Steam Deck GE-Proton Updater will run at every boot. In order, it will...
1. check for the latest version of itself and attempt to update itself if a newer version is found. You shouldn't need to worry about getting a newer version manually, but you still can try if you want to by clicking the Update button.
2. ensure that itself is configured correctly. This generally means that the binary is installed to the correct location (`~/.sd-ge-proton-updater`), that the binary is executable and that the systemd unit is installed and set to run on boot.
3. attempt to get information about the latest GE-Proton release,
4. install the latest release if you don't already have it.

# Caveats

Unfortunately, the Steam UI, even in Gaming Mode, needs to be restarted for new versions of Proton to show up. So, even if you get an update, you may need to reboot for it to become available in the Steam interface.

# Installation & Use

Expand Down
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.19

require (
github.com/AllenDang/giu v0.6.2
github.com/andygrunwald/vdf v1.0.0
github.com/blang/semver v3.5.1+incompatible
github.com/google/go-github/v47 v47.1.0
github.com/rhysd/go-github-selfupdate v1.2.3
Expand All @@ -27,11 +28,11 @@ require (
github.com/stretchr/testify v1.8.0 // indirect
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b // indirect
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect
golang.org/x/net v0.0.0-20220921203646-d300de134e69 // indirect
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1 // indirect
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/eapache/queue.v1 v1.1.0 // indirect
Expand Down
18 changes: 10 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/andygrunwald/vdf v1.0.0 h1:2HuC85EVF1Sm1bwKH8tiyucny2qzf9GSjB3flsdqoM4=
github.com/andygrunwald/vdf v1.0.0/go.mod h1:qi5jZfY3lrHXbibKeC2MCEge1tOsLODBgOHoS+RbRLk=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -69,28 +71,28 @@ github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20220921203646-d300de134e69 h1:hUJpGDpnfwdJW8iNypFjmSY0sCBEL+spFTZ2eO+Sfps=
golang.org/x/net v0.0.0-20220921203646-d300de134e69/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA=
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1 h1:3VPzK7eqH25j7GYw5w6g/GzNRc0/fYtrxz27z1gD4W0=
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM=
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
Expand Down
73 changes: 69 additions & 4 deletions gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
var (
protons []Proton
rows []*giu.TableRowWidget
gamesRows []*giu.TableRowWidget
showPruneWindow bool = false
)

Expand Down Expand Up @@ -135,6 +136,22 @@ func buildRows() {
}
}

func buildGamesRows() {
games, err := getSteamGames()
if err != nil {
return
}

gamesRows = make([]*giu.TableRowWidget, len(games))
for i, game := range games {
gamesRows[i] = giu.TableRow(
giu.Label(strconv.Itoa(game.Id)),
giu.Label(game.Name),
giu.Label(game.CompatibilityTool),
)
}
}

func prune() {
for _, proton := range protons {
if !proton.Checked {
Expand Down Expand Up @@ -167,7 +184,6 @@ func checkAllExceptLatest() {
protons[i].Checked = true
}
}

}

func stub() {}
Expand All @@ -176,6 +192,10 @@ func togglePruneWindow() {
giu.OpenPopup("prune")
}

func toggleGamesWindow() {
giu.OpenPopup("games")
}

func popupError(err error) {
giu.Msgbox("Error", err.Error())
}
Expand Down Expand Up @@ -241,7 +261,43 @@ func popupVersion() {
)
}

func loop() {
func buildGamesPopup() *giu.PopupModalWidget {
gamesTable := giu.Table().Size(
float32(mainWindowWidth-36), // fit scrollbar
float32(mainWindowHeight-112), // fit other widgets
).Flags(
giu.TableFlagsSortable,
).Columns(
giu.TableColumn("App ID").Flags(
giu.TableColumnFlagsNoDirectResize+giu.TableColumnFlagsNoResize+giu.TableColumnFlagsNoSort,
),
giu.TableColumn("App Name").Flags(
giu.TableColumnFlagsWidthStretch+giu.TableColumnFlagsNoDirectResize+giu.TableColumnFlagsNoResize+giu.TableColumnFlagsNoSort,
),
giu.TableColumn("Compatibility Tool").Flags(
giu.TableColumnFlagsWidthStretch+giu.TableColumnFlagsNoDirectResize+giu.TableColumnFlagsNoResize+giu.TableColumnFlagsNoSort,
),
).Rows(
gamesRows...,
)

return giu.PopupModal(
"games",
).Flags(
giu.WindowFlagsAlwaysAutoResize+giu.WindowFlagsNoMove+giu.WindowFlagsNoTitleBar,
).Layout(
giu.Row(
giu.Button("Refresh").Size(pruneSubButtonWidth, pruneSubButtonHeight).OnClick(buildGamesRows),
giu.Button("Close").Size(pruneSubButtonWidth, pruneSubButtonHeight).OnClick(giu.CloseCurrentPopup),
),
giu.Row(
giu.Label("Games using Proton, and what version of Proton each is set to use:"),
),
gamesTable,
)
}

func buildPrunePopup() *giu.PopupModalWidget {
pruneTable := giu.Table().Size(
float32(mainWindowWidth-36), // fit scrollbar
float32(mainWindowHeight-152), // fit other widgets
Expand All @@ -253,7 +309,7 @@ func loop() {
rows...,
)

prunePopup := giu.PopupModal(
return giu.PopupModal(
"prune",
).Flags(
giu.WindowFlagsAlwaysAutoResize+giu.WindowFlagsNoMove+giu.WindowFlagsNoTitleBar,
Expand All @@ -269,13 +325,17 @@ func loop() {
pruneTable,
giu.Button("Close").Size(pruneSubButtonWidth, pruneSubButtonHeight).OnClick(giu.CloseCurrentPopup),
)
}

func loop() {

aboutButton := giu.Button("About").Size(mainButtonWidth, mainButtonHeight).OnClick(popupVersion)
updateButton := giu.Button("Check for updates").Size(mainButtonWidth, mainButtonHeight).OnClick(doUpdate)
installButton := giu.Button("Install").Size(mainButtonWidth, mainButtonHeight).OnClick(doInstall)
uninstallButton := giu.Button("Uninstall").Size(mainButtonWidth, mainButtonHeight).OnClick(promptUninstall)
getProtonButton := giu.Button("Get latest GE-Proton release").Size(mainButtonWidth, mainButtonHeight) //.OnClick(stub)
pruneProtonButton := giu.Button("Prune chosen GE-Proton releases").Size(mainButtonWidth, mainButtonHeight).OnClick(togglePruneWindow)
listGamesButton := giu.Button("Show list of games").Size(mainButtonWidth, mainButtonHeight).OnClick(toggleGamesWindow)

// buttons we want disabled when we aren't running the real deal
if !installed {
Expand All @@ -288,7 +348,8 @@ func loop() {

giu.SingleWindow().Layout(
giu.PrepareMsgbox(),
prunePopup,
buildPrunePopup(),
buildGamesPopup(),
giu.Row(
aboutButton,
updateButton,
Expand All @@ -301,13 +362,17 @@ func loop() {
getProtonButton,
pruneProtonButton,
),
giu.Row(
listGamesButton,
),
)
}

func gui() {
mainWindow := giu.NewMasterWindow("Steam Deck GE-Proton Updater "+version+" "+commit, mainWindowWidth, mainWindowHeight, mainWindowFlags)

buildRows()
buildGamesRows()

mainWindow.Run(loop)
}
11 changes: 9 additions & 2 deletions install.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ func setupThis() (err error) {
return err
}

if thisElf == elfPath { // avoid copying self over self
return err
// avoid copying self over self
if thisElf == elfPath {
err = os.Chmod(elfPath, regExecMode) // still make sure we're executable!
if err != nil {
return err // shouldn't be a problem since we're already running :)
}

return err // stop further processing
}

// mkdir -p
Expand All @@ -38,6 +44,7 @@ func setupThis() (err error) {
return err
}

// ensure executable
err = os.Chmod(elfPath, regExecMode)
if err != nil {
return err
Expand Down
43 changes: 26 additions & 17 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,30 @@ import (
)

var (
version string = "" // to be filled in by goreleaser
commit string = "" // to be filled in by goreleaser
date string = "" // to be filled in by goreleaser
builtBy string = "" // to be filled in by goreleaser
cmdname string = filepath.Base(os.Args[0])
installed bool = false
protonPath string = "/home/deck/.local/share/Steam/compatibilitytools.d"
opsys string = runtime.GOOS
version string = "" // to be filled in by goreleaser
commit string = "" // to be filled in by goreleaser
date string = "" // to be filled in by goreleaser
builtBy string = "" // to be filled in by goreleaser
cmdname string = filepath.Base(os.Args[0])
installed bool = false
opsys string = runtime.GOOS
gamesInfoMap map[int]string
)

const (
protonGeApiUrl string = "https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases"
protonGeUrl string = "https://github.com/GloriousEggroll/proton-ge-custom"
systemdPath string = "/home/deck/.config/systemd/user/sd-ge-proton-updater.service"
elfPath string = "/home/deck/.sd-ge-proton-updater"
regExecMode os.FileMode = 0755
dirMode os.FileMode = 0755
regMode os.FileMode = 0644
dirModeDeck os.FileMode = 0775
regModeDeck os.FileMode = 0664
protonGeApiUrl string = "https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases"
protonGeUrl string = "https://github.com/GloriousEggroll/proton-ge-custom"
systemdPath string = "/home/deck/.config/systemd/user/sd-ge-proton-updater.service"
elfPath string = "/home/deck/.sd-ge-proton-updater"
protonPath string = "/home/deck/.local/share/Steam/compatibilitytools.d"
vdfPathConfig string = "/home/deck/.local/share/Steam/config/config.vdf"
vdfPathLibraryFolders string = "/home/deck/.local/share/Steam/config/libraryfolders.vdf"
regExecMode os.FileMode = 0755
dirMode os.FileMode = 0755
regMode os.FileMode = 0644
dirModeDeck os.FileMode = 0775
regModeDeck os.FileMode = 0664
// vdfPathAppInfo string = "/home/deck/.local/share/Steam/appcache/appinfo.vdf" // FIXME: VDF binary parser and patcher needed before this is useful
)

func main() {
Expand All @@ -50,6 +54,11 @@ func main() {
log.Fatalln(opsys + " is not supported")
}

gamesInfoMap, err = getAllSteamAppsInfo() // this should only happen one time per run
if err != nil {
log.Fatalln(err)
}

// main decision tree
switch args { // look for operations at the root of the command

Expand Down
Loading