Skip to content

Commit

Permalink
Finally working restarter
Browse files Browse the repository at this point in the history
  • Loading branch information
jan-bures committed Jan 10, 2024
1 parent 2911f2f commit 5f4e92f
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 300 deletions.
3 changes: 2 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<RestarterObjPath>$(SolutionDir)build/obj/restarter/$(Configuration)</RestarterObjPath>
<PreloaderBinPath>$(SolutionDir)build/bin/preloader/$(Configuration)</PreloaderBinPath>
<PreloaderObjPath>$(SolutionDir)build/obj/preloader/$(Configuration)</PreloaderObjPath>
<RestarterDistPath>$(SolutionDir)dist/$(Configuration)/BepInEx/plugins/SpaceWarp/restarter</RestarterDistPath>
<BaseOutputPath>$(ModulesBinPath)/$(MSBuildProjectName)</BaseOutputPath>
<BaseIntermediateOutputPath>$(ModulesObjPath)/$(MSBuildProjectName)</BaseIntermediateOutputPath>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
Expand Down Expand Up @@ -65,4 +66,4 @@
<SpaceWarpPluginVersion>$(Version)</SpaceWarpPluginVersion>
</PropertyGroup>
</Target>
</Project>
</Project>

This file was deleted.

2 changes: 1 addition & 1 deletion plugin_template/doorstop_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ targetAssembly=BepInEx\core\SpaceWarp.Preloader.dll
redirectOutputLog=false
# If enabled, DOORSTOP_DISABLE env var value is ignored
# USE THIS ONLY WHEN ASKED TO OR YOU KNOW WHAT THIS MEANS
ignoreDisableSwitch=false
ignoreDisableSwitch=true
# Overrides default Mono DLL search path
# Sometimes it is needed to instruct Mono to seek its assemblies from a different path
# (e.g. mscorlib is stripped in original game)
Expand Down
89 changes: 0 additions & 89 deletions src/SpaceWarp.UI/Backend/Processes/ProcessStarter.cs

This file was deleted.

41 changes: 16 additions & 25 deletions src/SpaceWarp.UI/UI/ModList/ModListController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using UnityEngine;
using UnityEngine.UIElements;
using SpaceWarp.Backend.Extensions;
using SpaceWarp.Backend.Processes;
using Enumerable = System.Linq.Enumerable;

namespace SpaceWarp.UI.ModList;
Expand Down Expand Up @@ -352,36 +351,28 @@ private void SetupButtons()
_applyChangesButton.style.display = DisplayStyle.None;
_applyChangesButton.RegisterCallback<ClickEvent>(_ =>
{
var currentPid = Process.GetCurrentProcess().Id;

// We call on restarter to kill the current process
// and it will call the restarter to restarter.
var restarterPath = Path.Combine(
SpaceWarpPlugin.Instance.SWMetadata.Folder.FullName,
"restarter",
"invoke_restarter.bat"
"SpaceWarpRestarter.exe"
);
Modules.UI.Instance.ModuleLogger.LogDebug($"Restarter path: {restarterPath}");

var cmd = $"cmd.exe /C \"" +
$"\"{restarterPath}\" " +
$"{currentPid} " +
$"\"{string.Join(" ", Environment.GetCommandLineArgs()[1..])}\"" +
$"\"";

Modules.UI.Instance.ModuleLogger.LogDebug($"Starting restarter: {cmd}");
var result = ProcessStarter.StartDetachedProcess(
null,
cmd
);

Modules.UI.Instance.ModuleLogger.LogDebug($"Restarter result: {result}");

// Hang the current process so that the restarter can kill it.
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while (result)
new Process
{
Thread.Sleep(1000);
}
StartInfo = new ProcessStartInfo
{
FileName = restarterPath,
Arguments = Environment.CommandLine,
CreateNoWindow = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
}
}.Start();

Application.Quit();
});

_detailsSourceLink.RegisterCallback<ClickEvent>(_ =>
Expand Down
20 changes: 5 additions & 15 deletions src/SpaceWarp/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,10 @@
<Copy SourceFiles="@(PreloaderPDBs)"
DestinationFolder="$(SolutionDir)/dist/$(ConfigurationName)/BepInEx/core"/>

<!-- Copying compiled restarter to build directory -->
<Message Text="Copying restarter to build directory"/>
<ItemGroup Label="Restarter EXE to be copied">
<RestarterEXE Include="$(RestarterBinPath)/**/*.exe"/>
</ItemGroup>
<Copy SourceFiles="@(RestarterEXE)"
DestinationFolder="$(SolutionDir)/dist/$(ConfigurationName)/BepInEx/plugins/$(ProjectName)/restarter"/>

<ItemGroup Label="Restarter PDBs to be copied">
<RestarterPDBs Include="$(RestarterBinPath)/**/*.pdb"/>
</ItemGroup>
<Copy SourceFiles="@(RestarterPDBs)"
DestinationFolder="$(SolutionDir)/dist/$(ConfigurationName)/BepInEx/plugins/$(ProjectName)/restarter"/>
<!-- Publishing restarter to build directory -->
<Message Text="Publishing restarter to build directory"/>
<Exec Command="cd"/>
<Exec Command="dotnet publish &quot;$(SolutionDir)src\SpaceWarpRestarter\SpaceWarpRestarter.csproj&quot; -c $(ConfigurationName) -r win-x64 -o &quot;$(SolutionDir)dist\$(ConfigurationName)\BepInEx\plugins\$(ProjectName)\restarter&quot; /p:SolutionDir=&quot;$(SolutionDir)&quot;"/>

<!-- Compressing build directory for release -->
<Message Text="Compressing built plugin folder" Condition="$(ConfigurationName) == Release"/>
Expand Down Expand Up @@ -178,5 +169,4 @@
<RemoveDir Directories="$(SolutionDir)/temp_nuget"
Condition="Exists('$(SolutionDir)/temp_nuget')"/>
</Target>
</Project>

</Project>
35 changes: 0 additions & 35 deletions src/SpaceWarpRestarter/Properties/AssemblyInfo.cs

This file was deleted.

115 changes: 25 additions & 90 deletions src/SpaceWarpRestarter/Restarter.cs
Original file line number Diff line number Diff line change
@@ -1,104 +1,39 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Management;
using System.Threading;

namespace SpaceWarpRestarter;
if (args.Length < 1)
{
Console.WriteLine(
$"Usage: {Path.GetFileNameWithoutExtension(AppContext.BaseDirectory)} <path to KSP2_x64.exe> " +
$"[optional arguments]"
);
Environment.Exit(1);
}

var processPath = args[0];
var processName = Path.GetFileNameWithoutExtension(processPath);
var processArgs = args.Length > 1 ? args[1..] : Array.Empty<string>();

internal class Restarter
Console.WriteLine($"Waiting for {processName} to exit...");

while (true)
{
public static void Main(string[] args)
if (Process.GetProcessesByName(processName).Length == 0)
{
// Can only run on Windows
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
Console.WriteLine("This can only run on Windows.");
Environment.Exit(1);
}

if (args.Length < 1)
try
{
Console.WriteLine(
$"Usage: {Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location)}.exe " +
$"<target process id> " +
$"[optional arguments that will be passed to KSP2_x64.exe]"
);
Environment.Exit(1);
Console.WriteLine($"{processName}.exe is not running. Attempting to start the process...");
Process.Start(processPath, processArgs);
Console.WriteLine($"{processName}.exe started successfully.");
break;
}

Console.WriteLine($"Args: {string.Join(" ", args)}");

var targetPid = args[0];
var processArgs = string.Join(" ", args.Length > 1 ? args.Skip(1).ToArray() : Array.Empty<string>());

// Get the path to the KSP2_x64.exe
var process = Process.GetProcessById(int.Parse(targetPid));
var processModule = process.MainModule;
Console.WriteLine($"Found process: {process.ProcessName} ({process.Id}) at {processModule?.FileName}");
if (processModule != null)
catch (Exception ex)
{
var processPath = processModule.FileName;

KillProc(int.Parse(targetPid));

Console.WriteLine($"Starting process {processPath} {processArgs}");

Thread.Sleep(1000);

// Launch the process
var ksp2Process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = processPath,
Arguments = processArgs,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};

// Start the ksp2_process and detach from it
ksp2Process.Start();
ksp2Process.Dispose();
} else {
Console.WriteLine("Could not find the process.");
Console.WriteLine($"An error occurred while starting {processName}.exe: {ex.Message}");
Environment.Exit(1);
}

Environment.Exit(0);
}

// Will recursively kill all child processes of the given process and the process itself
private static void KillProc(int pid)
else
{
var process = Process.GetProcessById(pid);

var restarterProcess = Process.GetCurrentProcess();

// We already guaranteed that this will only run on Windows
#pragma warning disable CA1416
var searcher = new ManagementObjectSearcher(
$"SELECT * " +
$"FROM Win32_Process " +
$"WHERE ParentProcessId={pid}"
);

foreach (var child in searcher.Get())
{
var processId = int.Parse(child["ProcessId"].ToString());
if (processId != restarterProcess.Id)
{
KillProc(processId);
}
}

Console.WriteLine($"Killing process {process.ProcessName} ({process.Id})");
process.Kill();
#pragma warning restore CA1416
Thread.Sleep(500);
}
}
Loading

0 comments on commit 5f4e92f

Please sign in to comment.