bburky / playnite-non-steam-shortcuts

A Playnite extension to create non-Steam shortcuts
MIT License
37 stars 2 forks source link

Playnite 9 Support #26

Open sapphicwench opened 2 years ago

sapphicwench commented 2 years ago

Could this be updated for Playnite 9 please? One of my most used extensions

NightHammer1000 commented 2 years ago

Playnite 9 dropped python support completely. This plugin thus needs a complete Rewrite in another Coding Language like C#. Maybe I will be on that sometime in the future if I feel inspired enough to fight with APIs again.

bburky commented 2 years ago

Yes, a rewrite is needed for this to work in Playnite 9. If you have any current steam shortcuts in your library they should continue to work though.

I found a different solution that I prefer personally. The Special K (wiki, pcgw) software mostly does game patching/modding for better video performance, but it can also manipulate the Steam Overlay. The steps to set it up are:

  1. Ensure Steam is running (it will not be automatically launched)
  2. Manually create an steam_appid.txt in the game's directory with the ID of the equivalent game from the Steam Store
    • If the game isn't available from Steam you can pick a different game's ID or just use 0.
  3. Inject Special K into a game (you can use Special K Injection Frontend (SKIF) to dynamically inject it into all games)
  4. Enable "Load Steam Overlay Early" in Special K's settings. This forces Steam overlay injection, even into non-Steam games.
    • I think you may be able to do this in SpecialK's global settings to avoid configuring each game.
  5. Relaunch the game. The Steam overlay will be present. It will even show correct community controller bindings for the game because the appid is set correctly.

SKIF uses global DLL injection to load the tool. This has some risks (don't use it while playing online games, anti-cheat doesn't like that), but has the significant advantage that you don't need to create non-Steam shortcuts for every game. Also, the overlay is correctly injected even if using a library plugin that launches another store's launcher.

However, there's a bug in "Load Steam Overlay Early" in SpecialK, it doesn't work and fails to load GameOverlayRenderer.dll. I had to patch and fix it to get it to work. I told the dev, but it hasn't been fixed yet. I need to send a pull request to get it fixed I think.

Details on SpecialK bug Inside `SK_Steam_LoadOverlayEarly`, `wszOverlayDLL` is being set to "c:/program files (x86)/steam\\GameOverlayRenderer.dlll" (yes, that's three `l`s). I noticed that `SK_PathCombineW` calls `SK_StripLeadingSlashesW` on it's argument, so the leading slash in the `LR"(\GameOverlayRenderer.dll)"` strings is unnecessary. I'm guessing there's a bug somewhere in the `SK_StripLeadingSlashesW` logic that deletes the slash but doesn't terminate the string properly? This patch fixes the issue by removing the slash in the string literal. Need look into `SK_StripLeadingSlashesW` and figure out what's wrong though, (I think it's just a missing null termination) ```diff diff --git a/src/steam/steam_api.cpp b/src/steam/steam_api.cpp index 8ed5ccc8..08a7f62e 100644 --- a/src/steam/steam_api.cpp +++ b/src/steam/steam_api.cpp @@ -4103,8 +4103,8 @@ SK_Steam_LoadOverlayEarly (void) wchar_t wszOverlayDLL [MAX_PATH + 2] = { }; SK_PathCombineW ( wszOverlayDLL, wszSteamPath, - SK_RunLHIfBitness ( 64, LR"(\GameOverlayRenderer64.dll)", - LR"(\GameOverlayRenderer.dll)" ) ); + SK_RunLHIfBitness ( 64, L"GameOverlayRenderer64.dll", + L"GameOverlayRenderer.dll" ) ); hModOverlay = SK_Modules->LoadLibrary (wszOverlayDLL); ```

Personally, I like the SpecialK workflow much better than non-Steam shortcuts. I think a Playnite extension to automatically create the steam_appid.txt file could be useful. @darklinkpower made one, but I don't think it was published. It might be interesting to modify an extension like that to automatically create the steam_appid.txt file right before launching a game in Playnite (OnGameStarting event).

NightHammer1000 commented 2 years ago

Sorry, but I can't recommend SpecialK to anyone. The DRM loving actions and DRM Bullshit the Dev did in the past and the conflicts with almost anything interacting with Overlay Rendering, Like RTSS for example, produce more issues than its worth.

Not everyone uses this Extension for the Overlay. I for myself use it to use In Home Streaming on games not in Steam.

Your Proposed Solution does not solve this problem.

A rewrite in C# is still the Best Solution. The SpecialK Overlay thing can be its own Plugin. But its not a Replacement for this Extension.

bburky commented 2 years ago

It's also possible to develop a much simpler DLL (less than everything that SpecialK does) and only does steam overlay injection. Also you should be able all the features in SpecialK besides the Steam settings if it's other features cause trouble.

https://gist.github.com/Andon13/d439d5334d8173e5b959f383f1c49b03

Not everyone uses this Extension for the Overlay.
I for myself use it to use In Home Streaming on games not in Steam.

Ah, sorry. I didn't realize people had other usecases for this extension. I originally developed it for using Steam's controller mapping features in non-Steam games.

I don't think I will be developing an alternative non-Steam shortcut Playnite extension if I find a solution that meets my needs. If a rewrite in C# is done I would look into the code in this LaunchBox extension, it uses some SteamPipe APIs to call (undocumented?) Steam APIs for creating shortcuts. This avoids needing to manually manipulate the shortcuts.vdf file or relaunching Steam after creating shortcuts.

sapphicwench commented 2 years ago

Thanks for figuring that out @bburky, I know my way around SK so it's not an issue for me, and hopefully Kal gets back to you about the patch.

People always love to repeat the supposed "drm" of specialk but it all the pirates had to do was disable something in the ini file. I have no issues using SK to inject reshade and 3dmitgo into games and they stream fine on my steam link. There's many a program out there that can import other libraries to steam, then all you have to do is make a desktop shortcut of said game and change the playnite action to the steam url

bburky commented 2 years ago

The Steam Overlay issue in Special K is fixed in version 21.10.18 or newer: https://gitlab.special-k.info/Kaldaien/SpecialK/-/merge_requests/5

I also tested creating My Documents\My Mods\SpecialK\Global\default_SpecialK.ini and add the following text to it. This configures "Load the Steam Overlay Early" to be enabled by default when using the Special K SKIF global injector. Otherwise you must manually enable this setting in each game. This allows using the Steam overlay and controller configuration for non-Steam games without creating non-Steam shortcuts.

[Steam.System]
PreLoadSteamOverlay=true

For now you have to manually create steam_appid.txt files, or appid 0 gets used by the overlay (which does work fine, but all your games will share the same config, and it's missing community controller bindings).

Iruberiam commented 2 years ago

The Steam overlay loads with SK but it's not the Big Picture overlay required for the Steam Controller. As far as I can tell there is no way to force this either. Your extension was the best solution for the job and worked perfectly, it's understandable that you don't feel like doing a rewrite though.

sapphicwench commented 2 years ago

@Iruberiam does checking the "force big picture overlay when using a controller" not work?

Iruberiam commented 2 years ago

@CptVeg Sadly not, I always have that checked, I'm guessing that flag only applies if the game is launched through Steam.

sapphicwench commented 2 years ago

@Iruberiam Bugger, the only other way I can think of making it work is manually adding the games to steam using things like OSOL or steamsync, making a desktop shortcut from steam with that and then adding that URL to playnite. It's what I've been having to do for Gamepass games as you can't create the appid.txt in their protected folders

bburky commented 2 years ago

Using "Load Steam Overlay Early" on Special K 21.10.18+, I have been able to use my Steam Controller with two limitations:

I have been able to configure both gamepad and mouse/keyboard bindings this way.

If editing protected folders is an issue for the steam_appid.txt, you configure the AppID in the per-game SK ini file in your Documents\My Mods\SpecialK\Profiles directory:

[Steam.System]
PreLoadSteamOverlay=true
AppID=620
Iruberiam commented 2 years ago

The desktop overlay is fine for normal controller input but it removes the ability to use many of the advanced features of steam input such as radial menus, touch menus and hotbars as these all rely on using the overlay for displaying their features.

bburky commented 2 years ago

Ok, thanks for the info. I tested that it is possible to force the Steam overlay into Big Picture mode if you set a SteamTenfoot=1 environment variable. This change would need to be done inside Special K. However it crashes if Steam isn't in Big Picture mode, so I'd need to find a good way to detect the current Steam mode during early startup of the game .

Iruberiam commented 2 years ago

Are you aware of this extension by darklinkpower https://playnite.link/forum/thread-659.html

bburky commented 2 years ago

The actual implementation needs to be on the Special K side, but yes an extension like that can make sure Steam is already in the right mode. An extension can handle the appid configuration too, and maybe even enable/disable SKIM.

Maybe an extension that provides a top toolbar button that functions as an on/off button for SKIM, and an OnGameStarted hook that ensures that Big Picture is running and the appid is set up correctly. Need to make sure this method actually works well enough before starting any of that though.

darklinkpower commented 2 years ago

I have a personal script that handles the start or close of Special K that may be of use.

function Start-SpecialkService
{
    param(
        $cpuArchitecture,
        $skifPath
    )

    $dllPath = [System.IO.Path]::Combine($skifPath, "SpecialK" + $cpuArchitecture + ".dll")
    if ([System.IO.File]::Exists($dllPath) -eq $false)
    {
        $__logger.Info("Special K dll not found in $dllPath")
        return $false
    }

    $serviceParams = @{
        FilePath = "rundll32.exe"
        ArgumentList = "`"$dllPath`",RunDLL_InjectionManager Install"
        WorkingDirectory = $skifPath
        Wait = $false
    }
    Start-Process @serviceParams

    $eventName = "Local\SK_GlobalHookTeardown" + $cpuArchitecture
    $i = 0
    do
    {
        try {
            Start-Sleep -Milliseconds 100
            $eventWaitHandle = [System.Threading.EventWaitHandle]::OpenExisting($eventName)
            $eventWaitHandle.Close()
            $eventWaitHandle.Dispose()
            $__logger.Info("Special K process and event for $dllPath started")
            return $true
        } catch {
            $i++
            Start-Sleep -Milliseconds 300
        }
    } while ($i -lt 10)

    $__logger.Info("Special K event `"$eventName`" could not be opened")
    return $false
}

function Stop-SpecialkService
{
    param(
        $cpuArchitecture,
        $skifPath
    )

    $dllPath = [System.IO.Path]::Combine($skifPath, "SpecialK" + $cpuArchitecture + ".dll")
    if ([System.IO.File]::Exists($dllPath) -eq $false)
    {
        $__logger.Info("Special K dll not found in $dllPath")
        return $false
    }

    try {
        $serviceParams = @{
            FilePath = "rundll32.exe"
            ArgumentList = "`"$dllPath`",RunDLL_InjectionManager Remove"
            WorkingDirectory = $skifPath
            Wait = $false
        }
        Start-Process @serviceParams
        $__logger.Info("Special K $cpuArchitecture service has been removed")
        return $true
    } catch {
        $__logger.Info("Special K $cpuArchitecture service could not be removed")
        return $false
    }
}

function OnGameStarting
{
    param(
        $OnGameStartingEventArgs
    )

    $game = $OnGameStartingEventArgs.Game

    $skifPath = [System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "My Mods", "SpecialK")
    $cpuArchitectures = @("32", "64")

    $disableSpecialK = $false
    if ($game.Features)
    {
        foreach ($feature in $game.Features)
        {
            if ($feature.Name -eq "Disable Special K")
            {
                $disableSpecialK = $true
                $__logger.Info("`"Disable Special K`" feature found. Special K will be disabled.")
                break
            }
        }
    }

    foreach ($cpuArchitecture in $cpuArchitectures)
    {
        if ($disableSpecialK -eq $true)
        {
            # Check if leftover service is running and close it
            Stop-SpecialkService $cpuArchitecture $skifPath
        }
        else
        {
            Start-SpecialkService $cpuArchitecture $skifPath
        }
    }
}

function OnGameStopped
{
    param(
        $OnGameStoppedEventArgs
    )

    $game = $OnGameStoppedEventArgs.Game

    $skifPath = [System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "My Mods", "SpecialK")
    $cpuArchitectures = @("32", "64")
    foreach ($cpuArchitecture in $cpuArchitectures)
    {
        Stop-SpecialkService $cpuArchitecture $skifPath
    }
}
darklinkpower commented 2 years ago

And found the extension I shared on the Playnite discord to generate the steam_appid.txt files, although it only works for P9. https://cdn.discordapp.com/attachments/699577276571975760/880682115086319686/Steam_AppId_Generator_1_0.pext

But I think something like this should be better done as a C# extension.

fIows commented 2 years ago

And found the extension I shared on the Playnite discord to generate the steam_appid.txt files, although it only works for P9. https://cdn.discordapp.com/attachments/699577276571975760/880682115086319686/Steam_AppId_Generator_1_0.pext

But I think something like this should be better done as a C# extension.

The extension doesn't work for me on Playnite 9

darklinkpower commented 2 years ago

And found the extension I shared on the Playnite discord to generate the steam_appid.txt files, although it only works for P9. https://cdn.discordapp.com/attachments/699577276571975760/880682115086319686/Steam_AppId_Generator_1_0.pext But I think something like this should be better done as a C# extension.

The extension doesn't work for me on Playnite 9

That one is for Playnite 8. Try with this, it should work https://cdn.discordapp.com/attachments/929214602200379392/929217657100697642/Steam_AppId_Generator_1_0.pext

fIows commented 2 years ago

That one is for Playnite 8. Try with this, it should work https://cdn.discordapp.com/attachments/929214602200379392/929217657100697642/Steam_AppId_Generator_1_0.pext

Thank you very much for the quick response and the help! Also, how would I use this script? https://github.com/bburky/playnite-non-steam-shortcuts/issues/26#issuecomment-951104938

darklinkpower commented 2 years ago

That one is for Playnite 8. Try with this, it should work https://cdn.discordapp.com/attachments/929214602200379392/929217657100697642/Steam_AppId_Generator_1_0.pext

Thank you very much for the quick response and the help! Also, how would I use this script? #26 (comment)

It needs to be made as an extension. Here it is for Playnite 9 with a newer version of the script.

SpecialKHelper.zip

It can also automatically configure a game specific reshade preset when you launch a game https://wiki.special-k.info/en/SpecialK/ReShade

For this you need to extract this file to this location

image

ReShadePresetEmpty.zip


Just be aware that I don't provide support for this extension, that's why I decided not to publish it. Also make sure to disable the extension for games that use anticheat or you'll probably be banned. To disable it for specific games add a feature named [SW] Disable Special K to them.

If you need help or have questions you can contact me in the Playnite discord server.

bburky commented 1 year ago

I just realized that this thread didn't have a link to @darklinkpower's excellent Special K Helper add-on in it. You can install the add-on inside Playnite by searching the add-on browser. It has some great features like easily toggling Special K on and off, and automatically detecting the Steam ID to make injecting the Steam overlay very simple.

Just leaving a link here in case anyone still finds this old playnite-non-steam-shortcuts on GitHub and finds this thread.

Fivefold commented 1 year ago

Since no one mentioned it yet, I want to point out BoilR, which automatically creates non-Steam shortcuts from other launchers in Steam (and even optionally adds images from SteamGridDB).

I don't think there is a way to automatically import those non-Steam shortcuts into Playnite, so the Special K method is the easier solution if you want to primarily use Playnite. Nontheless, it might help someone who mainly wants steam input or easy Steam Link streaming for non-steam games.

NightHammer1000 commented 1 year ago

https://github.com/PhilipK/BoilR/issues/200

NightHammer1000 commented 1 year ago

BoilR now has Playnite Support for those who still want to import everything into Steam

Drakalinou commented 7 months ago

I'd love to have this extension working again :

so we could be able to have steam overlay in all games (i know there is workarounds but it's really not as practical and it's hit or miss)

AND we could have all playnite's games aviable to stream via steam link (wich is now VR compatible), so all our library on steam deck and meta quest :D