-
Notifications
You must be signed in to change notification settings - Fork 73
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 Poster, Banner, Logo, etc to steamtinkerlaunch add Non-Steam game as launch options #738
Comments
This would be great, but it looks like it relies on Python to get the AppID for the Non-Steam Games? Otherwise nice find! Also wondering that even though it relies on Python, can it generate the AppID? The discussion in ProtonUp-Qt that I was involved in ended up just parsing it instead of calculating it. SteamTinkerLaunch is a Bash script and will not use Python in any capacity, so we need a way to calculate this from Bash. It also probably has to be written out to the shortcuts file. As an aside, if we can generate this with pure Bash, this can also be included in the Add Non-Steam Game UI, which I originally tried and failed to do in a PR several months ago. (This specifically refers to Non-Steam Games it seems so just editing the title of your proposal to reflect this 😄) |
It does. Line 104 parses shortcuts.vdf and returns appid. That's too bad about python, seems like the correct way to parse these files, though it does have the requirement of both python and the vdf module which I assume is what you're trying to avoid. If we can pick apart https://github.com/ValvePython/vdf/blob/d76292623e326fb165fe3bdb684832cdf30959d4/vdf/__init__.py |
That sounds like reading, not calculating :-) We need to calculate the AppID, since we are adding artwork etc before Steam calcuates the AppID. Please let me know if I'm misunderstanding here
Nope, it's also possible with Go and TypeScript :-) There is no "correct" way, Python is just one way. In fact, various parts of STL can parse VDF files in Bash. I just don't really understand how Frostworx did it or how to apply it to this instance. Probably it can't be applied here in this specific case at all since we have to calculate the Non-Steam AppID.
Absolutely, SteamTinkerLaunch is a Bash utility. It has various command-line related dependencies but it is focused on being as light on dependencies as possible. I love Python, but it has no place in SteamTinkerLaunch. I don't intend to mix languages and introduce huge dependencies in the process. Most of what STL depends on will come with a standard rolling distro except for the front-end Yad dependency. Having to introduce Python and on top of that, tell users to install the VDF library (and trying to do this on Steam Deck, not to mention bloating the STL Flatpak even more) will just be a major pain.
I totally agree! I don't understand how the parsing works even for the VDF library, I did take a look before to try and figure it out but it's not something I'm knowledgeable on. Hopefully someone else can step up and implement it, I really want to see more community development in SteamTinkerLaunch. |
I think it was discussed before in the issue you linked, but just to mention again: ProtonUp-Qt author DavidoTek actually figured out how it was calculated by looking at a Go implementation: DavidoTek/ProtonUp-Qt#175 (comment). The full Go code for the Non-Steam Game generation is here: https://github.com/boppreh/steamgrid/blob/9c8788db4f04613ecfb3e8fb36a0af02395e4593/games.go#L105-L137 It seems they parse the gameID := fmt.Sprint(binary.LittleEndian.Uint32(gameGroups[1])) // DavidoTek confirmed that this gameID is the correct AppID So the solution to the AppID pain in my mind is this:
Essentially we need to implement that Go function in Bash. I unfortunately have next to zero experience writing Go code and certainly no practical experience with using any sort of packages with it and whatnot, I also have no real understanding of the calculation that's going on here as my maths skills are not the greatest. If anyone wants to tackle this (doesn't have to be OP), this issue can be left open and used for discussion and collaboration on development. I'll help out where I can and would also be happy to review and PRs that came off the back of this. This is a feature I would like to see added to SteamTinkerLaunch (see #550, #576) but that after a lot of trying I could not figure out with my limited understanding. Back then I was even on the wrong track, it wasn't until DavidoTek/ProtonUp-Qt#175 that I saw they were calculated differently (e.g. without a CRC). I am a bit burned out on figuring this out personally at least for now so I did not look into it all that deeply. Maybe this background will be useful to someone who wants to add this :-) It is pretty much essential that it be done with Bash, external command-line utility dependencies could be used no problem though adding a dependency like Python or Go is not the solution for STL. Perhaps someone that understands how to do the calculation and regex matching can implement it with |
I found that when applications have already been added, the new settings may be ignored. Thus, I thought I messed up my installment. I had to reinstall steam to cleanup the vdf file. Cause my passed proton ver was ignored. Was the easiest way. By the way, attached is a bash script to process many games at once. All you need is a filelist! By the way, checking the proton thing does not seem consistent, and I dont know why. Do you think ChatGPT would be a candidate to "convert" one language into another? I don't have a account on ChatGPT, cause of privacy concerns, but it may be worth a try... |
I saw a little bit about that in the discussion on #729, though that isn't really a goal for this feature proposal, it's still useful to know. It is something I had hoped would be possible. It's something that can be explored once the AppID can be generated. To this point...
Heh, ChatGPT is something I find quite fascinating, and I had actually asked it previously to convert between languages (not for any "real" use-case, just to see if it could convert basic programs). I think I only tested once or twice but I think it was able to do it. If we could get a better understanding of how the calculation is done for the Non-Steam AppID it may be possible to ask ChatGPT :-) Though are projects """allowed""" to use code generated by ChatGPT? I would guess so but I am not 100% sure and would err on the side of caution here. |
Privately, you can ask it to learn how code X works... But corporate / private information does not belong to ChatGPT. It's not forbidden to ask privately. You could gain knowledge, and abstract / change it from there. However, I would never trust ChatGPT, thats exactly why it is a necessity to analyze the output thoroughly. But it may ease the research. It is nice when it comes to explaining code, but not always. I'm also not a fan of ChatGPT answers or Projects. Its just like, you know ... it may provide insights. |
I used it to parse the shortcuts vdf, super useful! But converting large libraries is not its strong suite. Short bits of code at a time can be accomplished. |
I did a little investigation into using ChatGPT to convert the Go parser into Bash, but did not get anywhere, it simply did not read any information properly from the |
Perhaps if we take the format that we write out to the file we can calculate the App ID for that shortcut based on the data we already have. Maybe if we try to get the AppID from what we would parse from the Not sure though. |
I don't think you need it, but I found a nodeJS way to calculate steam_id, converted it to python using our best friend and published that in my repo (horizon_scripts). Supposedly there's a way to do it in bash but requires the crc32 utility which doesn't come pre-installed. I think it's unrelated to AppID (Sorry, bit off topic here), but interesting nonetheless:
wasn't able to test bash version, but python version works nicely. |
The CRC32 algorithm is only for Big Picture, and possibly only old Big Picture. Regular Steam apps no longer use the CRC algorithm. See here (https://github.com/boppreh/steamgrid/blob/master/games.go#L115-L137) and this comment by DavidoTek that verifies that the CRC calculation is not correct anymore (DavidoTek/ProtonUp-Qt#175 (comment)). EDIT: I'm looking into a potential solution for this issue that won't involve calculating the AppID. No ETA, just something I'm investigating. |
Still haven't found a way of extracting the AppID using Bash, but with a little help from ChatGPT I did come up with a Python solution that doesn't rely on the import re
pattern = re.compile(b"(?i)\x00\x02appid\x00(.{1,4})\x01appname\x00([^\x08]+?)\x00\x01exe\x00([^\x08]+?)\x00\x01.+?\x00tags\x00(?:\x01([^\x08]+?)|)\x08\x08") # Taken from SteamGrid Go code
with open('shortcuts.vdf', 'rb') as f:
data = f.read()
matches = pattern.findall(data)
for match in matches:
appid = int.from_bytes(match[0], byteorder='little')
print(appid) This properly extracts each AppID from the If this can be converted to Bash it should be possible to extract the AppID and then use the newly-implemented Game Art Selection feature to set the artwork. My own attempts including with ChatGPT have come up short, but a PR would be more than welcome from someone that could add a function to do what this Python code does. |
I managed to come up with something pretty close by looking at the offsets with a #!/bin/bash
## CLOSE!!
# Get the AppID field (little-endian unsigned 32-bit integer starting at offset 0x1c)
APP_ID=$(xxd -p -s 0x1c -l 4 shortcuts.vdf | tac -rs .. | tr -d '\n' | xxd -r -p | od -N 4 -tu4 -v | awk '{print $2}') # CLOSEST
echo "AppID: $APP_ID"
# Get the AppName field (null-terminated string starting at offset 0x26)
APP_NAME=$(xxd -p -s 0x22 shortcuts.vdf | tr -d '\n' | sed 's/00/\n/' | head -n 1 | xxd -r -p)
echo "AppName: $APP_NAME" This returns an AppID but the correct app name for one entry. I have two shortcuts in this file, but this code just gets the first one. The AppID it returns is incorrect. It returns |
Hmm, not sure what the issue is yet but that's a nice start. As you mentioned it seems to print the wrong appID, but the appname is correct for me. it only picks the first entry as well in a list of many--what's making it do that in the "APP_ID=" bash command? here first two are from your bash script, others a loop from vdf library in python (with correct app ids)
|
I think it only returns one, maybe because of the To be clear and fair I wasn't trying to get it to do it in a loop yet, and I'm honestly amazed it actually gets the name right for any entry. For the AppID being wrong it could be that the offset is wrong, I haven't delved too deeply yet. But we're getting somewhere! |
The following Bash one-liner will extract all AppNames from the grep -a -o -P '(?i)\x01appname\x00(\K[^\x00-\x08]+?)(?=\x00\x01)' shortcuts.vdf Now I need to figure out how to do something similar for the AppIDs. Then it could go in one grep command and we can get the AppID and AppName for a shortcut from the The difference in this approach and earlier is that earlier it was using In Python, this regex works, but it doesn't in Bash: Once we get the value we have to convert it from a little endian to a 32bit unsigned integer. |
ChatGPT is depressing for this complex stuff. this is as far as I got (with a shortcuts.vdf with 3 appids so its printing appid 3 times basically):
as you mentioned anytime we're adding some regex filter to grep ( i.e. {1,4} ) it poops the bed. https://drive.google.com/file/d/1cZvQdSCSfVbHu5WmM7drjG4GIqrI3v9V/view?usp=sharing And the proper 3 appids (expected result):
|
Oh. I get it. I should take the sample as thing to play around in the bash. E.g copy paste the string into a new file and then come up with those 3 results reproducibly. But then again. What if we ask ChatGPT the following:
I really hope it doesnt end up in a simple subtraction :D |
Just
|
|
Try |
Nice to see the discussion going on here :-) I don't have anything more to add (for now anyway) but please feel free to continue discussing here and sharing whatever you find out! |
Maybe GPT 4 will answer the question for us... lol |
Whats the current question? |
https://www.youtube.com/live/outcGtbnMuQ?feature=share GPT 4 Looks amazing, so far I haven't been able to use GPT 3.5 to successfully convert that python script above to bash. Ultimately its the question this entire thread is based on I was just making a remark that if we wait until GPT 4 is live maybe it will translate for us better. |
This seems like the kind of problem that in 3-4 years we'll look back on and think "wow, AI was so bad back then" haha. I have not made much progress with regards to this issue, but just once again this is something I would love to see in STL. Hell, even as a proof-of-concept I think it would be really cool to have this done completely in Bash. I really appreciate all the time and discussion that has gone into this, so I think I will actually pin this issue in the hopes of bringing even more attention to it. Maybe someone a lot more experienced in Bash and parsing binary files will be able to help solve this :-) |
GPT4 does seem to do better than 3.5, but still returns the wrong result. example:
Result
It tried a number of permutations on this but the result was always an incorrect hex or appid or unsigned int. I'll try again later as it's rate limiting us :) |
Perhaps the data its pulling needs to be converted in some way. The Python code I have seen had to do something along these lines: |
It's getting so close. GPT4 is able to go backwards and calculate the correct hex from an unsigned 32-bit integer via this script:
output:
It just fails to convert the hex back to an unsigned int from this script which it seems to like
output
|
For what it's worth, I tried running this Bash snippet you posted earlier for for reading the Snippet:#!/bin/bash
file="shortcuts.vdf"
hex_data=$(xxd -p -c 20000 "${file}")
echo "Hex data:"
echo "${hex_data}"
echo
hex_matches=$(echo "${hex_data}" | grep -oP '(?<=617070696400)[0-9a-fA-F]{8}')
echo "Hex matches:"
echo "${hex_matches}"
echo
for hex_appid in $hex_matches; do
appid=$((16#${hex_appid}))
echo "Hex: ${hex_appid} Appid: ${appid}"
echo "${appid}"
echo
done With two shortcuts in my file, it outputs this:
Apart from that, this is getting really close! |
probably worth posting a link to a google drive for your shortcuts.vdf (copy paste doesn't seem to translate properly) |
Oops, totally forgot about attaching the shortcuts file. I'll create a better reproduction file with more shortcuts and attach it once I have some more time for this. I did a bit of testing on this tonight and noticed that Steam overwrites the AppID for a shortcut the first time it's launched. Or it seems to anyway. But when using the AppID written out to the file to set the game art, it still doesn't see it. Probably instead of parsing I would guess this will still come down to generating the AppID somehow... |
I had a thought earlier this week about Non-Steam Game AppIDs. Going back over everything here and retracing a lot of my steps, I had this crazy idea: What if we just wrote out our own AppID to the Okay, it wasn't as simple as that, but locally I have a working implementation of generating and writing out a custom Steam shortcut AppID that I'm going to push after I finish writing this. It doesn't yet have any functionality to copy over the artwork, but actually setting and knowing the AppID works, so all that's needed is some UI and logic to take in the artwork. We should also be able to re-use some stuff from #757 to accomplish this, meaning we shouldn't need to re-implement logic to copy over artwork! I'll try and explain the parameters for generating the AppID, because the answer was under our noses the whole time! Two useful resources I referred to during this test was the Python VDF library, which I used to read the expected values from the VDF file. The other resource was Integer Encoder, which I used to encode/decode from signed integers, unsigned integers, and hex. This allowed me to check at each stage that my code was matching the VDF file expected values. Steam stores shortcuts in a binary file called The most useful thing I got from this was, of course, how this file stores the AppID. It's something like this: All of those So now we know Steam stores the Non-Steam AppID as hex, but the AppID we need is an integer! This hexidecimal doesn't represent a regular integer that you might be used to though, it is a signed 32bit little-endian integer. This can be seen by using the Python Once converted, we'll be able to turn our hex that we got from the binary So to recap, to go from the value in the
Now we know how Steam stores those pesky AppIDs. But how do we write these out, and why did it not work before? The crux of why all of this wasn't working before is because the shortcuts.vdf was getting a positive hex value that was then written out as a Big-Endian integer instead of a Little-Endian. A Little-Endian is basically the hex string but with a swapped byte order, I'm sure there's a lot more to it that computer scientists would scream at me over, but that's what is relevant for this. Essentially, we were just generating a random integer (ex What we really have to do to get this right, is generate a random 32bit signed integer, and then convert that to a 4byte little-endian hex string which we write out to the AppID. This allows us to set our custom AppID for the Non-Steam Game. But to actually solve the grids issue, we need to then get the unsigned 32bit integer from this base signed integer we generated the little-endian hex from. Once we have this unsigned integer, we can put some artwork into the Steam artwork grids folder using that unsigned integer, and just like magic, our artwork will show up in Steam! I was able to accomplish this, and I have the Bash code to actually generate a Non-Steam AppID that we can know ahead of time, allowing us to eventually set the artwork. This AppID and its other variations (hex, formatted hex, and the raw signed integer) are also logged. This proposal should be possible to implement now, and I'll look into implementing it as soon as I can :-) |
nice! |
#902 was merged, so the next step is to add the logic for Non-Steam Games to (optionally) take in the artwork. This is probably going to reuse a lot of the set game artwork logic, as well as a bunch of strings and UI stuff from #576. It looks like I started my journey into Non-Steam AppID's just over a year ago because that PR is from September 5th 2022, wow! I'll also implement the command-line Fingers crossed that this should be straightforward to implement! The hard part (getting the AppID) should be done now. |
This feature has been implemented with #903. SteamTinkerLaunch v14.0.20230916-1 or above (8f24849) will now include this feature. I tested it out with a Non-Steam Game (screenshot of UI and moved files in that PR) and it worked. It's pretty useful, I've wanted this feature for a while. This also applies to the commandline usage as well ( This opens the door to future possibilities, such as using a specific compatibility tool with a Non-Steam Game and writing it out to the Another set of features I'm considering are ways to "clean up" after a Non-Steam Game has been removed, such as the ability to remove compatdatas, game artwork, and STL config files/other STL files for games which are no longer in the My year-long journey to understand these whacky Non-Steam AppIDs ends here for now. And very happily, I can say that this issue can now be closed with a happy resolution :-) |
I'm excited to test/implement these updates downstream, A bit busy now but will take a look soon as I get some time. I'm doing some manual hacky (unreliable) stuff to modify the config.vdf adding the proton compatibility so I'd definitely be a customer for that feature as well. |
Took me a long time to figure it all out, if you run into issues it might be better to open a separate issue tracking problems. Just because this issue is a bit old and mainly tracking the feature request. But if you feel it's better here please comment and re-open for visibility (so I don't miss it 😅). There are a couple of caveats which I guess I failed to mention, but very exotic filenames (I have some with As for the |
yes, of course. #905 added to continue later. |
System Information
Feature Description
@sonic2kk Since we have app id, this also unlocks the ability to add poster, banner, logo per app. Would be a nice addition to steamtinkerlaunch:
Working example in bash/python:
https://github.com/trentondyck/horizon_scripts/blob/70bd701f06596ff4f4f2fa96054abc6a7c03a0a5/install-or-update-horizon.sh#L107
Context:
#729
The text was updated successfully, but these errors were encountered: