We need to generate a 4byte little endian hex from a signed 32bit integer. This is what gets written to the shortcuts.vdf file. Steam will reject the AppID if it is not in this format, and will overwrite it.
This fixes the AppID generation, allowing us to 'predict' the AppID and will allow for implementing Non-Steam Game artwork selection.
It was discovered that the shortcut AppID is not actually generated by Steam itself, it can be anything so long as it is written out to the shortcuts.vdf file as a 4byte little endian hexadecimal representation of a signed 32bit integer. We aren't currently doing this, we're generating a random integer, converting it to hex, and attempting to write that out, which is why the AppID is always overwritten.
To fix this, essentially we have to generate a random nine-digit negative number and write that out as little-endian hex. Numerous functions were created to do this, but I'll explain the overall process here.
To start, we use shuf with a seed based on an optional argument to generate our signed 32bit integer. For our seed, we pass it a seed of the EXE name and path to it (ex: Bad Piggies/home/Gaben/Games/Bad Piggies), though the seed is an optional component to this function. Since shuf can't have a signed range, we cheat and add a - in front. This AppID is the decimal representation of what gets stored as a shortcut AppID in the shortcuts.vdf file (this is how the Python VDF library displays it, for example).
Once we have this signed integer, we need to convert it to a 4byte little-endian hexadecimal number. Since the shortcuts.vdf file is a binary file, it needs the value in hex representation. We first convert the signed integer to hex, and then convert that hex from big endian to little endian (which is basically the reverse byte order, this Integer Encoder website is very useful for checking out converting integers been signed, unsigned, hex, big endian, and little endian).
This value then needs some formatting to prefix each byte with \x, which Frostworx already wrote code for. This ensures it's written out to the binary file correctly. Once we do this, we've successfully written out our own custom AppID to the shortcuts.vdf file!
One final step which is useful for #738 specifically, is converting from our initial signed integer to unsigned. This unsigned integer is the one used to set the game artwork in the /path/to/steamroot/userdata/<userid>/config/grid folder, allowing that feature proposal to be implemented since we now have a knowable AppID.
Future Implementations
This opens the door to various other features, one main feature that comes to mind is the ability to remove game configs for Non-Steam games which are no longer on Steam. For example adding a game shortcut to Steam, using STL with it, and then removing the game. That shortcut is going to hang around!
We can check if AppIDs over a certain length are in the shortcuts.vdf file, and if not, we can assume they were removed shortcuts, and remove these config files. We could also implement something similar for compatdata directories, as Steam does not clean these up. These compatdata directories are always stored on the root Steam install's steamapps, so we can simply check for and remove these folders.
Of course, both of these features should be implemented as commands with warnings, as checking based on AppID length is not the strongest test, but it should work for the meantime.
Pending a tiny bit of further testing on a last-minute change to appease ShellCheck, and a version bump, this is ready to be merged!
Fixed a few silly mistakes which I forgot to refactor and pushed the version bump. As long as ShellCheck is still green, this will be good to merge now!
Part of work for #738, at long last!
We need to generate a 4byte little endian hex from a signed 32bit integer. This is what gets written to the shortcuts.vdf file. Steam will reject the AppID if it is not in this format, and will overwrite it.
This fixes the AppID generation, allowing us to 'predict' the AppID and will allow for implementing Non-Steam Game artwork selection.
Implementation
(A more thorough explanation of how Steam stores Non-Steam AppIDs can be found at https://github.com/sonic2kk/steamtinkerlaunch/issues/738#issuecomment-1720263749)
It was discovered that the shortcut AppID is not actually generated by Steam itself, it can be anything so long as it is written out to the
shortcuts.vdf
file as a 4byte little endian hexadecimal representation of a signed 32bit integer. We aren't currently doing this, we're generating a random integer, converting it to hex, and attempting to write that out, which is why the AppID is always overwritten.To fix this, essentially we have to generate a random nine-digit negative number and write that out as little-endian hex. Numerous functions were created to do this, but I'll explain the overall process here.
To start, we use
shuf
with a seed based on an optional argument to generate our signed 32bit integer. For our seed, we pass it a seed of the EXE name and path to it (ex:Bad Piggies/home/Gaben/Games/Bad Piggies
), though the seed is an optional component to this function. Sinceshuf
can't have a signed range, we cheat and add a-
in front. This AppID is the decimal representation of what gets stored as a shortcut AppID in theshortcuts.vdf
file (this is how the Python VDF library displays it, for example).Once we have this signed integer, we need to convert it to a 4byte little-endian hexadecimal number. Since the
shortcuts.vdf
file is a binary file, it needs the value in hex representation. We first convert the signed integer to hex, and then convert that hex from big endian to little endian (which is basically the reverse byte order, this Integer Encoder website is very useful for checking out converting integers been signed, unsigned, hex, big endian, and little endian).This value then needs some formatting to prefix each byte with
\x
, which Frostworx already wrote code for. This ensures it's written out to the binary file correctly. Once we do this, we've successfully written out our own custom AppID to theshortcuts.vdf
file!One final step which is useful for #738 specifically, is converting from our initial signed integer to unsigned. This unsigned integer is the one used to set the game artwork in the
/path/to/steamroot/userdata/<userid>/config/grid
folder, allowing that feature proposal to be implemented since we now have a knowable AppID.Future Implementations
This opens the door to various other features, one main feature that comes to mind is the ability to remove game configs for Non-Steam games which are no longer on Steam. For example adding a game shortcut to Steam, using STL with it, and then removing the game. That shortcut is going to hang around!
We can check if AppIDs over a certain length are in the
shortcuts.vdf
file, and if not, we can assume they were removed shortcuts, and remove these config files. We could also implement something similar forcompatdata
directories, as Steam does not clean these up. These compatdata directories are always stored on the root Steam install'ssteamapps
, so we can simply check for and remove these folders.Of course, both of these features should be implemented as commands with warnings, as checking based on AppID length is not the strongest test, but it should work for the meantime.
Pending a tiny bit of further testing on a last-minute change to appease ShellCheck, and a version bump, this is ready to be merged!