Skip to content

Commit

Permalink
Fixed a bug where processes would be elevated when they didn't need t…
Browse files Browse the repository at this point in the history
…o be and vice versa

Implemented progress bar for the 'install all'
Added more mods.
  • Loading branch information
th3w1zard1 committed May 24, 2023
1 parent 506aa3b commit 0e9c8e3
Show file tree
Hide file tree
Showing 62 changed files with 3,402 additions and 231 deletions.
741 changes: 737 additions & 4 deletions KOTORModSync.Core/ConfigFiles/modconfig.toml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions KOTORModSync.Core/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ public static void Log(string message)
Debug.WriteLine(logMessage);
File.AppendAllText(LogFileName, logMessage + Environment.NewLine);

Logged?.Invoke(logMessage); // Raise the Logged event
Logged.Invoke(logMessage); // Raise the Logged event
}

public static void LogException(Exception ex)
{
Log($"Exception: {ex.GetType().Name} - {ex.Message}");
Log($"Stack trace: {ex.StackTrace}");

ExceptionLogged?.Invoke(ex); // Raise the ExceptionLogged event
ExceptionLogged.Invoke(ex); // Raise the ExceptionLogged event
}

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
Expand Down
102 changes: 46 additions & 56 deletions KOTORModSync.Core/Utility/Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using MarkdownSharp;
using static KOTORModSync.Core.ModDirectory;
using Tomlyn.Model;
using static System.Net.Mime.MediaTypeNames;

namespace KOTORModSync.Core.Utility
{
Expand Down Expand Up @@ -97,76 +98,61 @@ public static string FixWhitespaceIssues(string tomlContents)
return tomlContents;
}

/*static string GenerateModDocumentation(Nett.TomlTableArray modArray)
public static string GenerateModDocumentation(List<Component> componentsList)
{
StringBuilder sb = new StringBuilder();
var markdown = new Markdown();
const string indentation = " ";

// Loop through each 'thisMod' entry
foreach (Nett.TomlTable modTable in modArray)
foreach (var component in componentsList)
{
sb.AppendLine();

// Name
string name = modTable.Get<string>("Name");
sb.AppendLine($"# {name}");
// Author
string author = modTable.Get<string>("Author");
sb.AppendLine($"**Author**: {author}");
// Description
string description = modTable.Get<string>("Description");
sb.AppendLine();
sb.AppendLine(description);
// Category & Tier
string categoryAndTier = modTable.Get<string>("Category");
sb.AppendLine();
sb.AppendLine($"**Category & Tier**: {categoryAndTier}");
// Language
List<string> languages = modTable.Get<List<string>>("Language");
bool hasEnglishLanguage = languages.Contains("English");
sb.AppendLine($"**Non-English Functionality**: {(hasEnglishLanguage ? "NO" : "YES")}");
// Directions
string directions = modTable.Get<string>("Directions");
// Component Information
sb.AppendLine($"####**{component.Name}**");
sb.AppendLine($"**Author**: {component.Author}");
sb.AppendLine();
sb.AppendLine("**Instructions**: ");
sb.AppendLine(directions);
sb.AppendLine($"**Description**: {component.Description}");
sb.AppendLine($"**Tier & Category**: {component.Tier} - {component.Category}");
if (component.Language != null)
{
if (string.Equals(component.Language.FirstOrDefault(), "All", StringComparison.OrdinalIgnoreCase))
sb.AppendLine($"**Supported Languages**: ALL");
else
sb.AppendLine($"**Supported Languages**: [{Environment.NewLine}{string.Join($",{Environment.NewLine}", component.Language.Select(item => $"{indentation}{item}"))}{Environment.NewLine}]");
}
sb.AppendLine($"**Directions**: {component.Directions}");

// Instructions
Tomlyn.Model.TomlTableArray instructionsArray = modTable.Get<Tomlyn.Model.TomlTableArray>("Instructions");
sb.AppendLine();
sb.AppendLine("## **Instructions**");
List<Tomlyn.Model.TomlTable> instructionsList = instructionsArray.ToList();
// Get the array of Component tables
Tomlyn.Model.TomlTableArray componentTables = modTable.Get<Tomlyn.Model.TomlTableArray>("thisMod");
if (component.Instructions == null)
continue;

// Deserialize each TomlTable into a Component object
foreach (Nett.TomlTable tomlComponent in componentTables)
sb.AppendLine();
sb.AppendLine("**Installation Instructions:");
foreach (var instruction in component.Instructions)
{
// Action
string action = tomlComponent.Get<string>("Action");
sb.AppendLine($"### **Action**: {action}");
// Source
List<string> source = tomlComponent.Get<List<string>>("Source");
string sourceFormatted = FormatSourcePaths(source); // Make sure FormatSourcePaths is defined and accessible
sb.AppendLine($"**To run this mod, execute**: {sourceFormatted}");
// Overwrite
string overwrite = tomlComponent.Get<string>("Overwrite");
sb.AppendLine($"**Overwrite**: {overwrite}");
sb.AppendLine();
if (instruction.Action == "extract")
continue;

sb.AppendLine($"**Action**: {instruction.Action}");
if (instruction.Action == "move")
sb.AppendLine($"**Overwrite existing files?**: {((bool)instruction.Overwrite ? "NO" : "YES")}");
string thisLine;
if (instruction.Source != null)
{
thisLine = $"Source: [{Environment.NewLine}{string.Join($",{Environment.NewLine}", instruction.Source.Select(item => $"{indentation}{item}"))}{Environment.NewLine}]";
if (instruction.Action != "move")
{
thisLine = thisLine.Replace("Source: ", "");
}
sb.AppendLine(thisLine);
}
if (instruction.Destination != null && instruction.Action == "move")
sb.AppendLine($"Destination: {instruction.Destination}");
}
}
return sb.ToString();
}*/
}


public static string SerializeComponent(Component component)
Expand Down Expand Up @@ -450,7 +436,11 @@ public static List<Component> ReadComponentsFromFile(string filePath)
Component component = new Component();
component.DeserializeComponent(tomlComponent);
components.Add(component);

if (component.Instructions == null)
{
Logger.Log($"{component.Name} is missing instructions");
continue;
}
foreach (Instruction instruction in component.Instructions)
{
instruction.ParentComponent = component;
Expand Down
137 changes: 91 additions & 46 deletions KOTORModSync.Core/installer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,22 @@ public class Instruction
[[thisMod.instructions]]
action = ""delete""
paths = [
source = [
""<<modDirectory>>\\path\\to\\mod\\file1.tpc"",
""<<modDirectory>>\\path\\to\\mod\\file2.tpc"",
""<<modDirectory>>\\path\\to\\mod\\file3.tpc""
]
dependencies = ""{C5418549-6B7E-4A8C-8B8E-4AA1BC63C732}""
overwrite = false
[[thisMod.instructions]]
action = ""move""
source = ""<<modDirectory>>\\path\\to\\mod\\file\\to\\move""
destination = ""C:\\Users\\****\\path\\to\\kotor2\\Override""
source = [
""<<modDirectory>>\\path\\to\\mod\\file1.tpc"",
""<<modDirectory>>\\path\\to\\mod\\file2.tpc"",
""<<modDirectory>>\\path\\to\\mod\\file3.tpc""
]
destination = ""<<kotorDirectory>>\\Override""
overwrite = ""True""
restrictions = ""{C5418549-6B7E-4A8C-8B8E-4AA1BC63C732}""
[[thisMod.instructions]]
Expand All @@ -72,7 +76,7 @@ public class Instruction
[[thisMod.instructions]]
action = ""tslpatcher""
source = [""<<modDirectory>>\\path\\to\\mod\\TSLPatcher.exe""]
source = ""<<modDirectory>>\\path\\to\\mod\\TSLPatcher.exe""
arguments = ""any command line arguments to pass (none available in TSLPatcher)""
";

Expand Down Expand Up @@ -348,65 +352,109 @@ public async Task<bool> ExecuteProgramAsync()
{
try
{
(List<string> sourcePaths, DirectoryInfo _) = await ParsePathsAsync();
bool isSuccess = false; // Track the success status
for (int i = 0; i < sourcePaths.Count; i++)
(List<string> sourcePaths, _) = await ParsePathsAsync();
bool isSuccess = true; // Track the success status

foreach (string sourcePath in sourcePaths)
{
var thisProgram = new FileInfo(sourcePaths[i]);
if (Action == "TSLPatcher")
{
FileHandler.ReplaceLookupGameFolder(new DirectoryInfo(Path.GetDirectoryName(sourcePath)));
}

var thisProgram = new FileInfo(sourcePath);
if (!thisProgram.Exists)
{
throw new FileNotFoundException($"The file {sourcePaths[i]} could not be located on the disk");
throw new FileNotFoundException($"The file {sourcePath} could not be located on the disk");
}
var cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(3600)); // cancel if running longer than 30 minutes.
var startInfo = new ProcessStartInfo
try
{
FileName = thisProgram.FullName,
Arguments = Arguments,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
var process = new Process
if (!await ExecuteProcessAsync(thisProgram))
{
isSuccess = false;
break;
}
}
catch(Exception ex)
{
StartInfo = startInfo
};
_ = process.Start();
Logger.LogException(ex);
return false;
}
}

Task<string> outputTask = process.StandardOutput.ReadToEndAsync();
return isSuccess;
}
catch (Exception ex)
{
Logger.LogException(ex);
return false;
}
}

while (!process.HasExited && !cancellationTokenSource.IsCancellationRequested)
private async Task<bool> ExecuteProcessAsync(FileInfo programFile)
{
using (var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3600)))
{
using (var process = new Process())
{
var startInfo = process.StartInfo;
startInfo.FileName = programFile.FullName;
startInfo.Arguments = Arguments;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;

try
{
await Task.Delay(100);
if (!process.Start())
{
throw new InvalidOperationException("Failed to start the process.");
}
}
catch (System.ComponentModel.Win32Exception)
{
startInfo.UseShellExecute = true;
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardError = false;

if (!process.Start())
{
throw new InvalidOperationException("Failed to start the process.");
}
}

await Task.Run(() => process.WaitForExit(), cancellationTokenSource.Token);

if (!process.HasExited)
{
process.Kill();
throw new TimeoutException("Process timed out after 30 minutes.");
}

string output = await outputTask;
string output = null;
string error = null;
if (startInfo.RedirectStandardOutput)
{
output = await process.StandardOutput.ReadToEndAsync();
error = await process.StandardError.ReadToEndAsync();
}

if (process.ExitCode != 0)
{
Logger.Log($"Process failed with exit code {process.ExitCode}. Output:\n{output}");
isSuccess = false;
}
else
{
isSuccess = true;
return false;
}

Logger.Log($"Output: {output}\n Error: {error}\n");
return true;
}
return isSuccess;
}
catch (Exception ex)
{
Logger.LogException(ex);
return false;
}
}




public async Task<bool> VerifyInstallAsync()
{
bool errors = false;
Expand Down Expand Up @@ -810,11 +858,8 @@ List<Component> componentsList
break;
case "patch":
case "tslpatcher":
for (int i = 0; i < instruction.Source.Count; i++)
{
FileHandler.ReplaceLookupGameFolder(new DirectoryInfo(Path.GetDirectoryName(instruction.Source[i])));
}
success = await instruction.ExecuteTSLPatcherAsync();
//success = await instruction.ExecuteTSLPatcherAsync();
success = await instruction.ExecuteProgramAsync();
//success = success && await instruction.VerifyInstallAsync();
break;
case "execute":
Expand Down Expand Up @@ -875,11 +920,11 @@ List<Component> componentsList
}
}*/
}
return (true, new Dictionary<FileInfo, System.Security.Cryptography.SHA1>());
return (true, new Dictionary<FileInfo, SHA1>());
}

Task<(bool, Dictionary<FileInfo, System.Security.Cryptography.SHA1>)> result = ProcessComponentAsync(this);
if (!result.Result.Item1)
(bool, Dictionary<FileInfo, SHA1>) result = await ProcessComponentAsync(this);
if (!result.Item1)
{
Logger.LogException(new Exception($"Component {this.Name} failed to install the mod correctly with {result}"));
return (false, null);
Expand Down
Loading

0 comments on commit 0e9c8e3

Please sign in to comment.