Fixing redistributables reinstalling every time you start a Proton game

July 26, 2019 - Reading time: 6 minutes

This will focus on Killing Floor 2 but it is basically the same for any Proton game which has this problem.

Killing Floor 2 had this annoying issue, every time I was starting it, it was installing DotNet Framework. In theory when you start the game for the first time, it should install all the redistributables, and add the corresponding registry Keys that tell Steam what have been successfully installed, and then it's done, it shouldn't reinstall one or all again every time you start the game.

To fix this issue it was fairly simple, first I looked at what it was reinstalling every time I was starting the game, as said, I could read it was DotNet Framework.

Then I looked into the Killing Floor 2 ACF file located one folder above the game install directory at ~/.local/share/Steam/steamapps/appmanifest_232090.acf (232090 being the AppID of Killing Floor 2 as you can see at SteamDB.info or in the Steam store page URL) to investigate and find what it should install on first launch, the interesting part was these additional shared depots:

 "SharedDepots"
    {
        "228983"        "228980"
        "228984"        "228980"
        "228986"        "228980"
        "228990"        "228980"
        "229000"        "228980"
        "229004"        "228980"
        "229033"        "228980"
    }

This tells all the needed redistributables files the game needs to run (these shared depots are all part of the depot with AppID 228980, which is 'Steamworks Common Redistributables') so here again I'm following the clues, and I look into the ACF file with this AppID 228980, the interesting part was the installation scripts paths (along with the installation directory for this AppID, which we'll use later):

 "InstallScripts"
    {
        "228983"        "_CommonRedist\\vcredist\\2010\\installscript.vdf"
        "228984"        "_CommonRedist\\vcredist\\2012\\installscript.vdf"
        "228986"        "_CommonRedist\\vcredist\\2015\\installscript.vdf"
        "228987"        "_CommonRedist\\vcredist\\2017\\installscript.vdf"
        "228990"        "_CommonRedist\\DirectX\\Jun2010\\installscript.vdf"
        "229000"        "_CommonRedist\\DotNet\\3.5\\installscript.vdf"
        "229002"        "_CommonRedist\\DotNet\\4.0\\installscript.vdf"
        "229004"        "_CommonRedist\\DotNet\\4.5.2\\installscript.vdf"
        "229033"        "_CommonRedist\\PhysX\\9.14.0702\\installscript.vdf"
    }

We can see the installation script paths for all the 'Steamworks Common Redistributables'.

My issue with Killing Floor 2 was only about the DotNet Framework so I'm ignoring all the others and only look into DotNet. Killing Floor 2 needs both DotNet 3.5 and 4.5.2, if I compare both ACF files.

Let see first what the DotNet 3.5 install script located at (combining path of Steamworks Common Redistributables, its 'installdir' as seen in its ACF file, and the 'install script path') ~/.local/share/Steam/steamapps/common/Steamworks Shared/_CommonRedist/DotNet/3.5/installscript.vdf contains:

"installscript"
{
    "Run Process"
    {
        "3.5 SP1"
        {
            "hasrunkey"     "HKEY_LOCAL_MACHINE\\Software\\Valve\\Steam\\Apps\\CommonRedist\\.NET\\3.5"
            "process 1"     "%INSTALLDIR%\\_CommonRedist\\DotNet\\3.5\\dotnetfx35.exe"
            "command 1"     "/q /norestart"
            "nocleanup"     "1"
        }
    }
}
"kvsignatures"
{
    "installscript"     "152cdbf8587d9d7c0b8f7b3d5f7ecc07d9dc62313c892cfca399bd39eb25380d37efb2710f098560926a6ebb2a8a215ee65f0712515dd76f1ae9a70bfa7eec21784bb7246b60d5ddbaa2dd661fe964a022cdc301353808df3a5fcdda7b9b2d39eeb3340357e9289c3b209358bcaf2674808e11a72e1b710eb14e242e29929347"
}

So from this script we can understand that Steam client (or Proton) is looking for the Key "HKEY_LOCAL_MACHINE\\Software\\Valve\\Steam\\Apps\\CommonRedist\\.NET\\3.5" in the game prefix registry, and inside this Key it needs the DWORD "3.5 SP1" (with a value of "1" for TRUE as in 'is installed = TRUE = 1', I guess). Here is the specific part I'm talking about, after deleting all the rest:

"3.5 SP1"
        {
            "hasrunkey"     "HKEY_LOCAL_MACHINE\\Software\\Valve\\Steam\\Apps\\CommonRedist\\.NET\\3.5"
        }

We could also look into the install script for DotNet 4.5, but this is basically the same thing, and it is irrelevant because, spoiler alert, it was the 3.5 not the 4.5 which was failing to write its registry Key.

If Steam fails to find all of this, it thinks it should install this specific redistributable before starting the game. Proton seems to fail to write these to the Killing Floor 2 prefix registry, so it will always reinstall DotNet 3.5 every time the game is started.

To fix this, first make sure the game properly works in Proton, then manually writing these values in the prefix registry should fix the issue.

To manipulate the prefix registry (or some other settings from Wine), see these tool and explanations to do it very easily.

So, by looking at the Killing Floor 2 prefix registry with the tool linked above, we can see it was missing the DotNet 3.5 registry Key (the DotNet 4.5 Key was properly written though).

Manually adding the DotNet 3.5 Key, and its DWORD with proper value, fixed the problem. The game starts without installing anything now.

Here is an image of the added Key to the Killing Floor 2 prefix registry (Proton 'regedit' like on Windows):

Note that the Key path is slightly different for Proton (the Key in the install script for DotNet 3.5 is originally for Windows, not for Proton under Linux, it is under Wow6432Node, not sure if it is because the system is 64 bit or because it is Proton, whatever, it is there and it works.

This whole process can be done in any Proton game that re-installs its redistributable(s) at game start, by starting over and following the proper ACF file of the game with similar issue, and doing the same as for Killing Floor 2 by investigating and following the clues to find the problematic registry Key(s) and eventually manually fixing them.