-
-
Save NadnerbD/193484b9ac1a0b9e622feed5c332da48 to your computer and use it in GitHub Desktop.
| from collections import OrderedDict | |
| import re, json, sys, os | |
| def parseObj(tokens): | |
| if(type(tokens) == str): | |
| tokens = re.split(r'[\t\r\n]+', tokens) | |
| tokens.reverse() | |
| obj = OrderedDict() | |
| while len(tokens): | |
| nt = tokens.pop() | |
| if nt in ["}", ""]: | |
| return obj | |
| elif nt.startswith('"'): | |
| nt = json.loads(nt) | |
| val = tokens.pop() | |
| if val.startswith('"'): | |
| obj[nt] = json.loads(val) | |
| elif val == "{": | |
| obj[nt] = parseObj(tokens) | |
| else: | |
| raise Exception("nt = %r" % nt) | |
| def dumpObj(obj, indent=0): | |
| s = "" | |
| for key in obj: | |
| s += "\t" * indent + json.dumps(key) | |
| if type(obj[key]) == OrderedDict: | |
| s += "\n" + "\t" * indent + "{\n" + dumpObj(obj[key], indent + 1) + "\t" * indent + "}\n" | |
| else: | |
| s += "\t\t%s\n" % json.dumps(obj[key]) | |
| return s | |
| with open(sys.argv[1], "r") as f: | |
| manifestpath = os.path.dirname(f.name) | |
| data = f.read() | |
| manifest = parseObj(data) | |
| print(dumpObj(manifest)) | |
| if "-username" in sys.argv: | |
| username = sys.argv[sys.argv.index("-username") + 1] | |
| appstate = manifest['AppState'] | |
| for depotkey in appstate['StagedDepots']: | |
| cmd = \ | |
| "DepotDownloader.exe -app " + appstate['appid'] + \ | |
| " -depot " + depotkey + " -manifest " + appstate['StagedDepots'][depotkey]['manifest'] + \ | |
| " -username " + username + " -remember-password -dir \"" + \ | |
| manifestpath + "\\common\\" + appstate['installdir'] + "\" -validate" | |
| print(cmd) | |
| os.system(cmd) | |
| installed_depot = appstate['StagedDepots'][depotkey] | |
| del installed_depot['dlcappid'] | |
| appstate['InstalledDepots'][depotkey] = installed_depot | |
| del appstate['StagedDepots'][depotkey] | |
| appstate['StateFlags'] = "4" | |
| appstate['UpdateResult'] = "0" | |
| appstate['StagingSize'] = "0" | |
| appstate['buildid'] = appstate['TargetBuildID'] | |
| appstate['BytesStaged'] = appstate['BytesToStage'] | |
| appstate['BytesDownloaded'] = appstate['BytesToDownload'] | |
| print(dumpObj(manifest)) | |
| with open(sys.argv[1], "w") as f: | |
| f.write(dumpObj(manifest)) | |
I have an add-on suggestion if you're interested? I might give it a burl myself if not, just I would have to learn some python first XD
Rather than the user providing the path and .acf filename at runtime, we could loop through *.acf in a set (default steamapps folder on c:) or configured folder and open each .acf, check if the StateFlags <> 4 and perform required updates rather automatically for any game that needs it? :D
or we could be specific and check if StateFlags == 1030 or 1542 instead of each file, if there might somehow be a problem otherwise like an additional state other than 4 where we don't want to update anything for whatever reason?
Could even go super-classy, and prompt the user with the name field of the .acf to ask This game isn't in 4 (Installed) state, wanna update it Y/N? Could even say what state it Is in, and advise.
Not that it's necessarily a huge trouble to read each of the files to determine which is the right game, then pass that to the updater, and rinse and repeat per game/update, but we could save people who don't know "how to open an .acf file" the trouble entirely I think, and essentially provide a complete drop-in bandaid for this new zstd drama? I mean you've basically done it already, you legend!
@metapea Found the reason for that error XD This testing and adding onto things with almost no knowledge has been painfully fun lol
The .acf file you feed to this script is intended to have been written by Steam, with details inside of what update it's trying (and failing) to install.
If your game is already updated, or if for any reason Steam has not filled out the StagedDepots details inside the game's .acf file while trying to update it, this script can't help you right now I think. You might wanna have Steam try to update the game, so it fills out the details in the game's .acf file with the details of the update first. Pretty sure that should have happened before it started trying to download or update anything tho idk whats up with that.
You can just open .acf files with your preferred text editor too, to make sure it's the right file/game and verify what's in there at what point.
@metapea Found the reason for that error XD This testing and adding onto things with almost no knowledge has been painfully fun lol The .acf file you feed to this script is intended to have been written by Steam, with details inside of what update it's trying (and failing) to install.
If your game is already updated, or if for any reason Steam has not filled out the StagedDepots details inside the game's .acf file while trying to update it, this script can't help you right now I think. You might wanna have Steam try to update the game, so it fills out the details in the game's .acf file with the details of the update first. Pretty sure that should have happened before it started trying to download or update anything tho idk whats up with that.
You can just open .acf files with your preferred text editor too, to make sure it's the right file/game and verify what's in there at what point.
It doesn't change at all before, in the middle of, or after a corrupt download update.
the .acf should say what it's downloading with "TargetBuildID", "InstalledDepots" or maybe "SharedDepots"
Oh, so you didn't need an answer for your question what is KeyError: 'StagedDepots'? cool :)
A other quick fix was to just drop the
Update_Manifest.pyand maybe theDepotDownloader.exeon thesteamappsfolder.then i got: