KSPModdingLibs / KSPCommunityFixes

Community patches for bugs in the KSP codebase.
https://github.com/KSPModdingLibs/KSPCommunityFixes/releases/latest
57 stars 19 forks source link

Enable Steam integration for non-steam installs #223

Open gotmachine opened 6 months ago

gotmachine commented 6 months ago

The KSP Steam integration consist of :

Currently, all these are unavailable on KSP installs that aren't the main install tracked by Steam, which is usually the case for most modded installs. It's possible to get back the steam overlay and tracking by adding the modded installs manually in steam, but the workshop integration won't work.

There is a hardcoded check disabling Steam integration by looking at the parent directory, to check for the presence of some Steam files. Disabling that check allow Steam client tracking and workshop integration to work as expected (as long as Steam is running).

Enabling the Steam overlay is however not possible without launching the game from Steam, as this involve Steam doing some code injection to check for the game renderer initialization, and then more code injection. The renderer is already initialized at the earliest point we can run, so too late.

There are apparently ways to force injection to happen (by running GameOverlayUI.exe -steampid {Steam Process ID} -pid {KSP Process ID} -gameid {steam game ID} -manuallyclearframes 0), but I couldn't make this to work for KSP.

Do anyone want/need this ? Could we get in trouble by enabling this, as this can allow steam workshop integration for copies that weren't bought through Steam ?

Anyway, for reference, here is some code to make it work :

[KSPAddon(KSPAddon.Startup.Instantly, true)]
internal class ModdedInstanceSteamIntegration : MonoBehaviour
{
    void Start()
    {
        InitSteam();
        Destroy(gameObject);
    }

    static void InitSteam()
    {
        SteamManager steamManager = SteamManager.Instance;

        if (steamManager._validSteamPlatform || steamManager.m_bInitialized)
            return;

        if (!Packsize.Test() || !DllCheck.Test())
        {
            Debug.LogError("[SteamManager]: Error initializing Steamworks.NET");
            return;
        }

        try
        {
            SteamAPI.RestartAppIfNecessary(AppId_t.Invalid);
        }
        catch (DllNotFoundException ex)
        {
            Debug.LogError("[SteamManager]: Could not load [lib]steam_api.dll/so/dylib.");
            return;
        }

        string steamAppidFilePath = Path.Combine(KSPUtil.ApplicationRootPath, "steam_appid.txt");
        bool steamAppidFileIsValid = File.Exists(steamAppidFilePath);
        if (steamAppidFileIsValid)
        {
            try
            {
                steamAppidFileIsValid = File.ReadAllText(steamAppidFilePath) == SteamManager.AppID.ToString();
            }
            catch
            {
                steamAppidFileIsValid = false;
            }
        }

        if (!steamAppidFileIsValid)
        {
            try
            {
                File.WriteAllText(steamAppidFilePath, SteamManager.AppID.ToString());
            }
            catch
            {
                Debug.LogError("[SteamManager]: Could not create steam_appid.txt");
                return;
            }
        }

        steamManager.m_bInitialized = SteamAPI.Init();
        if (!steamManager.m_bInitialized)
        {
            Debug.Log("[SteamManager]: Steam not installed or not running, disabling Steam integration.");
            return;
        }

        steamManager._validSteamPlatform = true;

        SteamApps.GetAppInstallDir(SteamManager.AppID, out SteamManager._KSPSteamAppFolder, 5242880u);

        steamManager._friendName = steamManager.getFriendName();

        steamManager.m_SteamAPIWarningMessageHook = SteamManager.SteamAPIDebugTextHook;
        SteamClient.SetWarningMessageHook(steamManager.m_SteamAPIWarningMessageHook);
        steamManager.SetupCallbacks();
    }
}
SofieBrink commented 6 months ago

I personally wouldn’t see much if any use in this, the Steam Workshop for sharing crafts is basically the only thing that’d matter here and that itself is pretty terrible since there’s no way to know which mods and which versions of said mods a craft requires unless a creator explicitly states them. I guess the playtime tracking could be fun though.