tralph3 / Steam-Metadata-Editor

An easy to use GUI that edits the metadata of your Steam Apps
GNU General Public License v3.0
161 stars 18 forks source link

Pressing "save" more than once discards all changes #37

Closed rasitayaz closed 9 months ago

rasitayaz commented 1 year ago

In SteamOS, if you edit and save more than one game (or edit the same game and save again), none of the edits will be applied on Steam. After pressing the "save" button, the app needs to be restarted to make further changes because pressing it again just discards every edit made in that session.

AlJoelson commented 10 months ago

This issue also occurs on Windows.

sonic2kk commented 9 months ago

This appears to be a a result of invalid data being written to the VDF file, which occurs when trying to save twice. If you press the save button twice, then close and attempt to re-open SME, it will give an error like this:

Traceback (most recent call last):
  File "/home/user/Programming/Steam-Metadata-Editor/src/main.py", line 45, in <module>
    main()
  File "/home/user/Programming/Steam-Metadata-Editor/src/main.py", line 34, in main
    mainWindow = MainWindow()
                 ^^^^^^^^^^^^
  File "/home/user/Programming/Steam-Metadata-Editor/src/gui/main_window.py", line 91, in __init__
    self.create_main_window()
  File "/home/user/Programming/Steam-Metadata-Editor/src/gui/main_window.py", line 110, in create_main_window
    self.appinfo = Appinfo(self.vdf_path)
                   ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/Programming/Steam-Metadata-Editor/src/appinfo.py", line 58, in __init__
    self.parsedAppInfo = self.read_all_apps()
                         ^^^^^^^^^^^^^^^^^^^^
  File "/home/user/Programming/Steam-Metadata-Editor/src/appinfo.py", line 172, in read_all_apps
    app["sections"] = self.parse_subsections()
                      ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/Programming/Steam-Metadata-Editor/src/appinfo.py", line 105, in parse_subsections
    value = value_parsers[value_type]()
            ~~~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 172

When you open Steam, it simply resolves this corruption, making it seem like the edits are cleared.

I was able to verify the self.appinfo.parsedAppInfo[app] information was correct all the way through MainWindow#write_data_to_appinfo, so the issue is with the VDF file becoming "corrupted."

SME seems to write data out by looking at the modified Steam apps and uses the AppInfo#update_app to generate the updated VDF entry, which is then written out to the VDF file using AppInfo#write_data. This method only writes to the binary VDF file, and this works when save is clicked once, so I suspect the issue occurs there.


I did this test many times, and then after one of my test attempts, SME couldn't find my appinfo.vdf, despite it being present. I tried starting it a few times, and eventually it found the file again. After this, I have not been able to reproduce the problem. It started happening again, it seems reasonably consistent to reproduce but sometimes doesn't happen. My money is still on update_app not generating correct information to write out when a modified app is saved twice sometimes.

tralph3 commented 9 months ago

I have figured out what the issue is. When you press save, the modified data gets encoded into its binary form, and the original data is replaced in a bytearray that contains the entire appinfo.vdf.

In order to know where in that entire bytearray the data for this particular app is located, I grab the binary data for the app's header, and perform a search. The search either returns an index, and I drop the new data, or it doesn't find anything, and I drop the new data at the end of the file.

Now here's the problem. The app data has now been updated, meaning the header has changed too. If you press save again, the search will be performed again, but with the previous state of the header. It won't find anything now. And so the data gets appended at the end, and Steam must see that the info is repeated twice, and it's probably just invalidating the cache and recreating it.

So I need to investigate how to fix that. I can probably make it so it doesn't search for the entire header, and just use the appId, although that introduces the possibility that somewhere in the file that is exact number is repeated, and it will make a mess.

I could probably search for the ID prepended by '0x08' which is the code for the end of a dictionary. The only issue with that is that the very first app wouldn't have a dictionary ending before. But I think the very first one is some internal Steam stuff, and not a real game, so it's not really an issue, although it does feel a bit dirty to me.

Another possibility would be to update the header stored in the variables, but I would need to look into it since I don't quite recall how it's structured.

tralph3 commented 9 months ago

If I were a good developer I'd have tests to ensure everything is actually working. But I'm not, so here's a commit that in my own, personal testing, fixed the issue.