initial NVIDIA Shield streaming support implementation

pull/85/head
Sectorbob 2 years ago
parent db6098b7fe
commit 57f5af399b

@ -348,7 +348,7 @@ namespace UWPHook
{
var users = SteamManager.GetUsers(steam_folder);
var selected_apps = Apps.Entries.Where(app => app.Selected);
var exePath = @"""" + System.Reflection.Assembly.GetExecutingAssembly().Location + @"""";
var exePath = GenerateExePath();
var exeDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
List<Task> gridImagesDownloadTasks = new List<Task>();
@ -370,6 +370,85 @@ namespace UWPHook
// Export the selected apps and the downloaded images to each user
// in the steam folder by modifying it's VDF file
ExportAppsToSteamShortcuts(tags, users, selected_apps, exePath, exeDir);
ExportAppsToShieldShortcuts(selected_apps, exePath, exeDir);
if (gridImagesDownloadTasks.Count > 0)
{
await Task.WhenAll(gridImagesDownloadTasks);
await Task.Run(() =>
{
foreach (var user in users)
{
CopyTempGridImagesToSteamUser(user);
CopyTempGridImagesToShieldStreamingAssets(selected_apps);
}
RemoveTempGridImages();
});
}
}
if (restartSteam)
{
Func<Process> getSteam = () => Process.GetProcessesByName("steam").SingleOrDefault();
Process steam = getSteam();
if (steam != null)
{
string steamExe = steam.MainModule.FileName;
//we always ask politely
Debug.WriteLine("Requesting Steam shutdown");
Process.Start(steamExe, "-exitsteam");
bool restarted = false;
Stopwatch watch = new Stopwatch();
watch.Start();
//give it N seconds to sort itself out
int waitSeconds = 8;
while (watch.Elapsed.TotalSeconds < waitSeconds)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5f));
if (getSteam() == null)
{
Debug.WriteLine("Restarting Steam");
Process.Start(steamExe);
restarted = true;
break;
}
}
if (!restarted)
{
Debug.WriteLine("Steam instance not restarted");
MessageBox.Show("Failed to restart Steam, please launch it manually", "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
return false;
}
}
else
{
Debug.WriteLine("Steam instance not found to be restarted");
}
}
return true;
}
/// <summary>
/// Extracted method to simplify the complexity of the ExportGames method.
///
/// This method updates and existing steam vdf file to add or update shortcuts for the selected windows apps.
/// </summary>
/// <param name="tags"></param>
/// <param name="users"></param>
/// <param name="selected_apps"></param>
/// <param name="exePath"></param>
/// <param name="exeDir"></param>
private static void ExportAppsToSteamShortcuts(string[] tags, string[] users, IEnumerable<AppEntry> selected_apps, string exePath, string exeDir)
{
foreach (var user in users)
{
try
@ -453,68 +532,6 @@ namespace UWPHook
MessageBox.Show("Error: Program failed exporting your games:" + Environment.NewLine + ex.Message + ex.StackTrace);
}
}
if (gridImagesDownloadTasks.Count > 0)
{
await Task.WhenAll(gridImagesDownloadTasks);
await Task.Run(() =>
{
foreach (var user in users)
{
CopyTempGridImagesToSteamUser(user);
}
RemoveTempGridImages();
});
}
}
if(restartSteam)
{
Func<Process> getSteam = () => Process.GetProcessesByName("steam").SingleOrDefault();
Process steam = getSteam();
if (steam != null)
{
string steamExe = steam.MainModule.FileName;
//we always ask politely
Debug.WriteLine("Requesting Steam shutdown");
Process.Start(steamExe, "-exitsteam");
bool restarted = false;
Stopwatch watch = new Stopwatch();
watch.Start();
//give it N seconds to sort itself out
int waitSeconds = 8;
while (watch.Elapsed.TotalSeconds < waitSeconds)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5f));
if (getSteam() == null)
{
Debug.WriteLine("Restarting Steam");
Process.Start(steamExe);
restarted = true;
break;
}
}
if (!restarted)
{
Debug.WriteLine("Steam instance not restarted");
MessageBox.Show("Failed to restart Steam, please launch it manually", "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
return false;
}
}
else
{
Debug.WriteLine("Steam instance not found to be restarted");
}
}
return true;
}
public static void ClearAllShortcuts()
@ -695,5 +712,140 @@ namespace UWPHook
}
}
}
/// <summary>
/// Generates the exe path used by Steam and NVIDIA Shield to call UWPHook
/// </summary>
/// <returns></returns>
private static string GenerateExePath()
{
return @"""" + System.Reflection.Assembly.GetExecutingAssembly().Location + @"""";
}
/// <summary>
/// Iterates through the selected apps and creates windwos shortcut files for each inside the NVIDIA Shield Apps directory.
/// Will place an NVIDIA required placeholder box-art.png file inside the StreamingAssets/{app-name} dir.
/// </summary>
/// <param name="selected_apps"></param>
/// <param name="exePath"></param>
/// <param name="exeDir"></param>
private static void ExportAppsToShieldShortcuts(IEnumerable<AppEntry> selected_apps, string exePath, string exeDir)
{
string shieldAppsDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "NVIDIA Corporation", "Shield Apps");
string streamingAssetsDir = Path.Combine(shieldAppsDir, "StreamingAssets");
if (!Directory.Exists(streamingAssetsDir))
{
DirectoryInfo di = Directory.CreateDirectory(streamingAssetsDir);
di.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
}
foreach (AppEntry app in selected_apps)
{
string scrubbedAppName = app.Name;
foreach (char c in Path.GetInvalidFileNameChars())
{
scrubbedAppName = scrubbedAppName.Replace(c, '_');
}
string shortcutFile = Path.Combine(shieldAppsDir, scrubbedAppName + ".lnk");
Debug.WriteLine("Creating NVIDIA Shield shortcut: " + shortcutFile);
IWshRuntimeLibrary.IWshShell3 wsh = new IWshRuntimeLibrary.IWshShell_Class();
IWshRuntimeLibrary.IWshShortcut shortcut = wsh.CreateShortcut(shortcutFile);
shortcut.Arguments = app.Aumid;
shortcut.TargetPath = exePath;
// not sure about what this is for
shortcut.WindowStyle = 1;
shortcut.Description = "test link for " + app.Name;
shortcut.WorkingDirectory = exeDir;
//shortcut.IconLocation = "specify icon location";
shortcut.Save();
// Copy over placeholder box-art.png (required by NVIDIA)
string boxArtDir = Path.Combine(streamingAssetsDir, scrubbedAppName);
string boxArtFile = Path.Combine(streamingAssetsDir, scrubbedAppName, "box-art.png");
if (!Directory.Exists(boxArtDir))
{
Debug.WriteLine("creating directory for game streaming assets: " + boxArtDir);
try
{
Directory.CreateDirectory(boxArtDir);
}
catch (Exception e)
{
Console.Error.WriteLine("unable to create game streaming assets dir: {0}", e);
}
}
try
{
Debug.WriteLine("copying placeholder box-art to " + boxArtFile);
Properties.Resources.box_art.Save(boxArtFile);
}
catch (Exception e)
{
Console.Error.WriteLine("unable to copy placeholder box-art: {0}", e);
}
}
}
/// <summary>
/// Copies all temporary images to the {drive}:/Users/{user}/Appdata/Local/NVIDIA Corporation/Shield Apps/StreamingAssets/{scrubbed game name} dirs
/// </summary>
/// <param name="selectedApps">Selected app entrys to copy images for</param>
private void CopyTempGridImagesToShieldStreamingAssets(IEnumerable<AppEntry> selectedApps)
{
string tmpGridDirectory = Path.Combine(Path.GetTempPath(), "UWPHook", "tmp_grid");
string streamingAssetsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "NVIDIA Corporation", "Shield Apps", "StreamingAssets");
// No images were downloaded, maybe the key is invalid or no app had an image
if (!Directory.Exists(tmpGridDirectory))
{
return;
}
if (!Directory.Exists(streamingAssetsDirectory))
{
DirectoryInfo di = Directory.CreateDirectory(streamingAssetsDirectory);
di.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
}
foreach (AppEntry app in selectedApps)
{
string scrubbedAppName = app.Name;
foreach (char c in Path.GetInvalidFileNameChars())
{
scrubbedAppName = scrubbedAppName.Replace(c, '_');
}
ulong gameId = GenerateSteamGridAppId(app.Name, GenerateExePath());
string srcFile = Path.Combine(tmpGridDirectory, string.Format("{0}p.png", gameId));
string destDir = Path.Combine(streamingAssetsDirectory, scrubbedAppName);
string destFile = Path.Combine(destDir, "box-art.png");
if (!Directory.Exists(destDir))
{
try
{
Debug.WriteLine("Creating directory: ", destDir);
_ = Directory.CreateDirectory(destDir);
}
catch (Exception e)
{
Console.Error.WriteLine("unable to create directory: ", e);
}
}
try
{
Debug.WriteLine("Copying box-art image from {0} to {1}", new object[] { srcFile, destFile });
File.Copy(srcFile, destFile, true);
}
catch (Exception e)
{
Console.Error.WriteLine("unable to copy box-art: ", e);
}
}
}
}
}

Loading…
Cancel
Save