Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ModSupport & ModManager] Edit launch logic and create shortcut button #314

Merged
merged 12 commits into from
Sep 29, 2023
16 changes: 16 additions & 0 deletions FrostyEditor/Windows/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,22 @@
Margin="4 0 0 0" />
</StackPanel>
</Button>
<Button x:Name="prevLaunchButton"
Margin="4 0 0 0"
Click="prevLaunchButton_Click"
ToolTip="Launch with previously generated data"
IsEnabled="false">
<StackPanel Orientation="Horizontal"
Margin="4 0 4 0">
<Grid Grid.Column="0" Width="16">
<Image Source="../Images/Play.png"
Width="16" />
<Image Source="../Images/Recent.png"
Width="12"
Margin="8, 8, 0, 0"/>
</Grid>
</StackPanel>
</Button>
</StackPanel>
</Border>
<!-- Filler -->
Expand Down
74 changes: 74 additions & 0 deletions FrostyEditor/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public MainWindow()
RoutedCommand addBookmarkCmd = new RoutedCommand();
RoutedCommand removeBookmarkCmd = new RoutedCommand();
RoutedCommand launchGameCmd = new RoutedCommand();
RoutedCommand prevLaunchGameCmd = new RoutedCommand();
RoutedCommand focusAssetFilterCmd = new RoutedCommand();

newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
Expand All @@ -116,7 +117,16 @@ public MainWindow()
if (ProfilesLibrary.EnableExecution)
{
CommandBindings.Add(new CommandBinding(launchGameCmd, launchButton_Click));
CommandBindings.Add(new CommandBinding(launchGameCmd, prevLaunchButton_Click));
launchButton.IsEnabled = true;
if (Directory.Exists($"{App.FileSystem.BasePath}\\ModData\\Editor"))
{
prevLaunchButton.IsEnabled = true;
}
else
{
prevLaunchButton.IsEnabled = false;
}
}

InitGameSpecificMenus();
Expand Down Expand Up @@ -466,6 +476,8 @@ private void launchButton_Click(object sender, RoutedEventArgs e)
{
executionAction.PostLaunchAction(task.TaskLogger, PluginManagerType.Editor, cancelToken.Token);
}

prevLaunchButton.IsEnabled = true;
}
catch (OperationCanceledException)
{
Expand Down Expand Up @@ -495,6 +507,68 @@ private void launchButton_Click(object sender, RoutedEventArgs e)
GC.Collect();
}

private void prevLaunchButton_Click(object sender, RoutedEventArgs e)
{
if (!ProfilesLibrary.EnableExecution)
return;

if (!Directory.Exists($"{App.FileSystem.BasePath}\\ModData\\Editor"))
{
prevLaunchButton.IsEnabled = false;
return;
}

// setup ability to cancel the process
CancellationTokenSource cancelToken = new CancellationTokenSource();

prevLaunchButton.IsEnabled = false;

// apply mod
string additionalArgs = Config.Get<string>("CommandLineArgs", "", ConfigScope.Game) + " ";

// Set pack
App.SelectedPack = "Editor";
string modDirName = "ModData\\" + App.SelectedPack;
string modDataPath = App.FileSystem.BasePath + modDirName + "\\";

try
{
// run mod applying process
FrostyTaskWindow.Show("Launching", "", (task) =>
{
App.Logger.Log("Launching");
try
{
foreach (ExecutionAction executionAction in App.PluginManager.ExecutionActions)
executionAction.PreLaunchAction(task.TaskLogger, PluginManagerType.Editor, cancelToken.Token);

FrostyModExecutor.LaunchGame(App.FileSystem.BasePath, modDirName, modDataPath, additionalArgs);

App.Logger.Log("Done");
}
catch (OperationCanceledException)
{
// process was cancelled
App.Logger.Log("Launch Cancelled");
}
catch (Exception ex)
{
App.Logger.Log("Error Launching Game: " + ex);
}

}, showCancelButton: true, cancelCallback: (task) => cancelToken.Cancel());
}
catch (OperationCanceledException)
{
// process was cancelled
App.Logger.Log("Launch Cancelled");
}

prevLaunchButton.IsEnabled = true;

GC.Collect();
}

private void unimplementedMenuItem_Click(object sender, RoutedEventArgs e)
{
FrostyMessageBox.Show("This feature is currently unimplemented", "Frosty Editor");
Expand Down
12 changes: 12 additions & 0 deletions FrostyModManager/FrostyModManager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@
<Resource Include="Images\PrimaryActionAdd.png" />
<Resource Include="Images\PrimaryActionMerge.png" />
<Resource Include="Images\Open.png" />
<Resource Include="Images\SaveAs.png" />
<Content Include="ThirdParty\Newtonsoft.Json.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand All @@ -301,6 +302,17 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
wannkunstbeikor marked this conversation as resolved.
Show resolved Hide resolved
<COMReference Include="IWshRuntimeLibrary">
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
Expand Down
Binary file added FrostyModManager/Images/SaveAs.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion FrostyModManager/Windows/ManageModDataWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ ResizeMode="NoResize" WindowStartupLocation="CenterOwner">
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="16"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0" Text="{Binding Name}" VerticalAlignment="Center"/>
Expand All @@ -39,7 +41,10 @@ ResizeMode="NoResize" WindowStartupLocation="CenterOwner">
<Button x:Name="openModData" Grid.Column="3" Click="openModData_Click" ToolTip="Open Folder">
<Image Source="/FrostyModManager;component/Images/Open.png"/>
</Button>
<Button x:Name="deleteModData" Grid.Column="5" Click="deleteModData_Click" ToolTip="Delete Folder">
<Button x:Name="createShortcutToModData" Grid.Column="5" Click="createShortcutToModData_Click" ToolTip="Create shortcut to launch game with ModData">
<Image Source="/FrostyModManager;component/Images/SaveAs.png"/>
</Button>
<Button x:Name="deleteModData" Grid.Column="7" Click="deleteModData_Click" ToolTip="Delete Folder">
<Image Source="/FrostyModManager;component/Images/Remove.png"/>
</Button>
</Grid>
Expand Down
120 changes: 118 additions & 2 deletions FrostyModManager/Windows/ManageModDataWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
using System.Diagnostics;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Frosty.Controls;
using Frosty.Core;
using Frosty.Core.Controls;
using Frosty.Core.Windows;
using Frosty.ModSupport;
using FrostySdk;
using IWshRuntimeLibrary;
using Microsoft.SqlServer.Server;
using Microsoft.Win32;

namespace FrostyModManager
{
Expand Down Expand Up @@ -122,9 +130,117 @@ private void openModData_Click(object sender, RoutedEventArgs e)
/// Method <c>launchModData_Click</c> Attempts to launch game with existing ModData pack folder
/// </summary>
private void launchModData_Click(object sender, RoutedEventArgs e)
{
// setup ability to cancel the process
CancellationTokenSource cancelToken = new CancellationTokenSource();

Pack selectedPack = ((Button)sender).DataContext as Pack;
string modDirName = "ModData\\" + selectedPack.Name;
string modDataPath = getModDataPath() + $"\\{selectedPack.Name}\\";

try
{
// run mod applying process
FrostyTaskWindow.Show("Launching", "", (task) =>
{
App.Logger.Log("Launching");
try
{
foreach (var executionAction in App.PluginManager.ExecutionActions)
executionAction.PreLaunchAction(task.TaskLogger, PluginManagerType.ModManager, cancelToken.Token);

FrostyModExecutor.LaunchGame(Config.Get<string>("GamePath", "", ConfigScope.Game, ProfilesLibrary.ProfileName) + "\\", modDirName, modDataPath, Config.Get<string>("CommandLineArgs", "", ConfigScope.Game));

App.Logger.Log("Done");
}
catch (OperationCanceledException)
{
// process was cancelled
App.Logger.Log("Launch Cancelled");
}
catch (Exception ex)
{
App.Logger.Log("Error Launching Game: " + ex);
}

}, showCancelButton: true, cancelCallback: (task) => cancelToken.Cancel());
}
catch (OperationCanceledException)
{
// process was cancelled
App.Logger.Log("Launch Cancelled");
}

}

/// <summary>
/// Method <c>createShortcutToModData_Click</c> Attempts to create shortcut to launch game with ModData
/// </summary>
private void createShortcutToModData_Click(object sender, RoutedEventArgs e)
{
Pack selectedPack = ((Button)sender).DataContext as Pack;
FrostyModExecutor.ExecuteProcess($"{Path.GetDirectoryName(getModDataPath())}\\{ProfilesLibrary.ProfileName}.exe", $"-dataPath \"{selectedPack.Path.Trim('\\')}\"");
string basePath = Config.Get<string>("GamePath", "", ConfigScope.Game, ProfilesLibrary.ProfileName) + '\\';
string modDirName = "ModData\\" + selectedPack.Name;
string modDataPath = getModDataPath() + $"\\{selectedPack.Name}\\";
string additionalArgs = Config.Get<string>("CommandLineArgs", "", ConfigScope.Game);

string steamAppIdPath = $"{basePath}steam_appid.txt";
if (System.IO.File.Exists(steamAppIdPath))
{
SaveFileDialog dialog = new SaveFileDialog();
shoushou1106 marked this conversation as resolved.
Show resolved Hide resolved
dialog.FileName = $"{ProfilesLibrary.DisplayName}_{selectedPack.Name}"; // Default file name
dialog.Filter = "Steam Shortcut|*.url"; // Filter files by extension
dialog.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

if (dialog.ShowDialog() == true)
{
try
{
string steamAppId = System.IO.File.ReadAllLines(steamAppIdPath).First();
string arguments = $"-dataPath \"{modDirName.Replace('\\', '/')}\" {additionalArgs}".Trim();
string url = Uri.EscapeDataString(arguments);
App.Logger.Log($"Launch: {arguments}");
App.Logger.Log($"Encoded: {url}");
using (StreamWriter writer = new StreamWriter(dialog.FileName))
{
writer.WriteLine("Prop3=19,0");
writer.WriteLine("[InternetShortcut]");
writer.WriteLine($"URL=steam://run/{steamAppId}//{url}/");

App.Logger.Log($"Steam shortcut write to: {dialog.FileName}");
}
}
catch (Exception ex)
{
FrostyExceptionBox.Show(ex, "Create Shortcut failed");
}
}
}
else
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.FileName = $"{ProfilesLibrary.DisplayName.Replace("™", "")}_{selectedPack.Name}"; // Default file name
dialog.Filter = "Shortcut|*.lnk"; // Filter files by extension
dialog.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

if (dialog.ShowDialog() == true)
{
try
{
WshShell shell = new WshShell();
IWshShortcut shortcut = shell.CreateShortcut(dialog.FileName.Replace("™", "")) as IWshShortcut;
shortcut.TargetPath = $"{basePath + ProfilesLibrary.ProfileName}.exe";
shortcut.Arguments = $"-dataPath \"{modDataPath.Trim('\\')}\" {additionalArgs}";
shortcut.Save();

App.Logger.Log($"Shortcut write to: {dialog.FileName}");
}
catch (Exception ex)
{
FrostyExceptionBox.Show(ex, "Create Shortcut failed");
}
}
}
}
}
}
34 changes: 19 additions & 15 deletions FrostyModSupport/FrostyModExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1814,21 +1814,7 @@ public int Run(FileSystem inFs, CancellationToken cancelToken, ILogger inLogger,

try
{
string steamAppIdPath = $"{fs.BasePath}steam_appid.txt";
if (File.Exists(steamAppIdPath))
{
string steamAppId = File.ReadAllLines(steamAppIdPath).First();
string arguments = $"-dataPath \"{modDirName.Replace('\\', '/')}\" {additionalArgs}".Trim();
string url = Uri.EscapeDataString(arguments);
App.Logger.Log($"Launch: {arguments}");
App.Logger.Log($"Encoded: {url}");
Process.Start($"steam://run/{steamAppId}//{url}/");
}
else
{
ExecuteProcess($"{fs.BasePath + ProfilesLibrary.ProfileName}.exe", $"-dataPath \"{modDataPath.Trim('\\')}\" {additionalArgs}");
}

LaunchGame(fs.BasePath, modDirName, modDataPath, additionalArgs);
}
catch (Exception ex)
{
Expand All @@ -1841,6 +1827,24 @@ public int Run(FileSystem inFs, CancellationToken cancelToken, ILogger inLogger,
return 0;
}

public static void LaunchGame(string basePath, string modDirName, string modDataPath, string additionalArgs)
{
string steamAppIdPath = $"{basePath}steam_appid.txt";
if (File.Exists(steamAppIdPath))
{
string steamAppId = File.ReadAllLines(steamAppIdPath).First();
string arguments = $"-dataPath \"{modDirName.Replace('\\', '/')}\" {additionalArgs}".Trim();
string url = Uri.EscapeDataString(arguments);
App.Logger.Log($"Launch: {arguments}");
App.Logger.Log($"Encoded: {url}");
Process.Start($"steam://run/{steamAppId}//{url}/");
}
else
{
ExecuteProcess($"{basePath + ProfilesLibrary.ProfileName}.exe", $"-dataPath \"{modDataPath.Trim('\\')}\" {additionalArgs}");
}
}

private List<ModInfo> GenerateModInfoList(string[] modPaths, string rootPath)
{
List<ModInfo> modInfoList = new List<ModInfo>();
Expand Down