diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index aaafcec2..7606e9e8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,10 +18,13 @@ jobs:
name: Build
runs-on: windows-latest
env:
- RID: "win-x86"
- TFM: "net5.0-windows"
+ TFM: "net6.0-windows"
ASSEMBLYNAME: "HXE"
PROJPATH: "./src/HXE.csproj"
+ strategy:
+ fail-fast: false
+ matrix:
+ RID: [ "win-x86", "win-x64" ]
steps:
################
@@ -37,15 +40,12 @@ jobs:
- run: npm install
# Dependents: Semantic Release
- # Authenticates packages to push to GPR
- uses: actions/setup-dotnet@v1
with:
- dotnet-version: "6.0.x" # SDK Version to use.
+ dotnet-version: "6.0.x"
include-prerelease: true
-
- name: Add GitHub Package Repository
run: dotnet nuget add source https://nuget.pkg.github.com/HaloSPV3/index.json -n "github" -u USERNAME -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
-
- name: Set NuGet.org Credentials
run: dotnet nuget update source "nuget.org" -u USERNAME -p ${{ secrets.NUGET_TOKEN }} --store-password-in-clear-text
@@ -53,7 +53,7 @@ jobs:
# BUILD
################
- name: dotnet-publish
- run: dotnet publish $env:CSPROJ_RELPATH -c Release --no-self-contained -p:ContinuousIntegrationBuild=true
+ run: dotnet publish ${{ env.CSPROJ_RELPATH }} -c Release -t ${{ env.TFM }} --RID ${{ matrix.RID }} -p:ContinuousIntegrationBuild=true
# required variables: TargetFramework, RuntimeIdentifier, GitVersion_FullSemVer
- name: Compress-PublishArtifacts
@@ -61,7 +61,7 @@ jobs:
$publishPath = Resolve-Path ".\bin\Release\$env:TFM\$env:RID\publish";
$archiveName = "$env:ASSEMBLYNAME.$env:TFM-$env:RID.$env:GitVersion_FullSemVer.zip";
Set-Location $publishPath;
- Compress-Archive -Path $publishPath -DestinationPath $archiveName -CompressionLevel Optimal;
+ Compress-Archive -Path $publishPath -DestinationPath ${{ github.workspace }}\bin\Release\publish\$archiveName -CompressionLevel Optimal;
################
# RELEASE
@@ -77,7 +77,7 @@ jobs:
uses: actions/upload-artifact@v2
with:
name: publish-artifacts
- path: bin/Release/${{ env.TFM }}/${{ env.RID }}/publish
+ path: bin/Release/publish
- name: Publish to GitHub Packages
working-directory: bin/Release
diff --git a/.releaserc.yaml b/.releaserc.yaml
index 2217cbd9..ed0801b5 100644
--- a/.releaserc.yaml
+++ b/.releaserc.yaml
@@ -28,7 +28,7 @@
['@semantic-release/github',
{
"assets": [
- {"path": "bin/release/win-x64/publish"}
+ {"path": "bin/release/publish"}
]
}
]
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 2e4b7d93..5a3b6411 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -15,5 +15,11 @@
"conv-pr", // Conventional Pull Request config
"commitizen",
"pull-requests" // pull requests workflow
- ]
+ ],
+ "markdownlint.config": {
+ "MD028": false,
+ "MD025": {
+ "front_matter_title": ""
+ }
+ }
}
diff --git a/README.md b/README.md
index 911f3373..6cd2940e 100644
--- a/README.md
+++ b/README.md
@@ -48,3 +48,30 @@ The USAGE document goes into detail on how to use HXE. In a nutshell:
# configure the kernel
.\hxe.exe -config
+
+# Requirements
+
+## Operating System
+
+| Minimum | Recommended
+| ---------------------------------------- | -----------
+| Windows 7 SP1 32-bit (w/ addl. software) | Windows 10 64-bit
+
+## .NET 6.0
+
+Because HXE is built on the relatively new .NET 6, you may need to download the [.NET 6.0 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) for this app to work. Hopefully, this will be distributed via Windows Updates to Windows 10 and Windows 11 sooner rather than later.
+For 64-bit PCs: [Dotnet Runtime (Desktop) 6.0.1 Windows x64 Installer](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.1-windows-x64-installer)
+For 32-bit PCs: [Dotnet Runtime (Desktop) 6.0.1 Windows x86 Installer](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.1-windows-x86-installer)
+
+### Windows 7/8.1
+
+Additional software dependencies to be installed for this .NET-based app to work on Windows 8.1 and Windows 7
+Read the [Microsoft docs](https://docs.microsoft.com/en-us/dotnet/core/install/windows?tabs=net60#additional-deps) to learn what you need and how to get it.
+
+## Note: Upgrading To Windows 10
+
+Using the [Windows Installation Media Creation Tool](https://www.microsoft.com/en-us/software-download/windows10?36261b60-2f68-4336-abe2-4b00f210b6aa=True), you can still upgrade to Windows 10 with your Windows 7/8/8.1 license.
+HOWEVER...
+
+- If your hardware distributor does not make Windows 10 drivers for your hardware, you may have a worse Windows 10 experience than expected.
+- Some drivers made for earlier Windows releases may work on Windows 10; some won't. You won't know until you try.
diff --git a/src/.msb.prebuild.ps1 b/src/.msb.prebuild.ps1
index 0f9e5f06..88434e36 100644
--- a/src/.msb.prebuild.ps1
+++ b/src/.msb.prebuild.ps1
@@ -8,59 +8,26 @@
function prebuild
{
- $minVer_isShallow = [version]'2.15.0.0';
- $minVer_unshallow = [version]'2.1.4.0';
- $gitBinVer = "";
$isShallow = $true;
- # 0. Announce
- Write-Host "0. GitVersion cannot determine the next version in shallow reposistories.`n",
- "`tWe will use Git to determine if the current repository needs to be un-shallowed.`n",
- "Checking if Git is available...";
+ # Announce
+ Write-Host "GitVersion requires unshallow repositories.`n",
+ "We will use Git to determine if the current repository needs to be un-shallowed.";
- # 1. Ensure Git is available
- try
- {
- Write-Host "1. Git was found.`n",
- "It is $(git --version) at...`n",
- (Get-Command -Name git).path
-
- $gitBinVer = [version]('{2}.{3}.{4}.{6}' -f (git --version).split(' ').split('.'))
- }
- catch
- {
- Write-Error "Git is not installed or it is not in PATH!";
- throw
- }
-
- # 2. Check if the repository is shallow
- Write-Host "2. Checking if repository is shallow..."
- if ($gitBinVer -gt $minVer_isShallow) # GitVersion >= 2.15.0.0
- {
- $isShallow = git rev-parse --is-shallow-repository
- }
- else
- {
- Write-Debug "Git Version less than 2.15.0.0"
- $isShallow = Test-Path (Join-Path $GitStatus.GitDir shallow)
- }
+ # Check if the repository is shallow
+ Write-Host "Checking if repository is shallow..."
+ $isShallow = git rev-parse --is-shallow-repository
- # 3. If the repository is shallow, then unshallow
+ # If the repository is shallow, then unshallow
if ($isShallow -eq $true)
{
- Write-Host "3. Repository is shallow. Fetching full history..."
- if ($gitBinVer -lt $minVer_unshallow) # GitVersion < 2.1.4.0 (exact version unknown)
- {
- git fetch --depth=0;
- }
- else {
- git fetch --unshallow
- }
+ Write-Warning "Repository is shallow. Fetching full history..."
+ git fetch --unshallow
Write-Host "Fetch Completed. Proceeding to Build...`n"
}
else
{
- Write-Host "3. Repository is complete. Proceeding to Build..."
+ Write-Host "Repository is complete. Proceeding to Build..."
}
}
diff --git a/src/CLI/Positions.cs b/src/CLI/Positions.cs
new file mode 100644
index 00000000..00f9848c
--- /dev/null
+++ b/src/CLI/Positions.cs
@@ -0,0 +1,157 @@
+/**
+ * Copyright (c) 2022 Noah Sherwin
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+using System;
+using System.IO;
+
+namespace HXE.CLI
+{
+ public static class Positions
+ {
+ public static void Run(string source = null, string target = null)
+ {
+ Console.Info("Read the file \"OS_Settings.User.xml\" and write its weapons positions to a .bin file.");
+ FileInfo fiSource = null;
+ FileInfo fiTarget = null;
+
+ while (fiSource == null)
+ {
+ try
+ {
+ fiSource = GetSource();
+ }
+ catch (Exception e)
+ {
+ Console.Error(e.ToString());
+ }
+ }
+
+ while (fiTarget == null)
+ {
+ try
+ {
+ fiTarget = GetTarget();
+ }
+ catch (Exception e)
+ {
+ Console.Error(e.ToString());
+ }
+ }
+
+ try
+ {
+ Save(fiSource, fiTarget);
+ }
+ catch (Exception e)
+ {
+ Console.Error(e.ToString());
+ }
+
+
+ }
+
+ private static FileInfo GetSource(string source = null)
+ {
+ FileInfo fileInfo = null;
+
+ Console.Info("Full path of OS_Settings.User.xml:");
+
+ if (source == null)
+ {
+ string input = System.Console.In.ReadLine();
+
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ throw new NullReferenceException("The supplied path was null, empty, or whitespace.");
+ }
+
+ fileInfo = new FileInfo(Path.GetFullPath(input));
+ }
+ else
+ {
+ Console.Info(source);
+ fileInfo = new FileInfo(Path.GetFullPath(source));
+ }
+
+ if (!fileInfo.Exists)
+ {
+ throw new FileNotFoundException($"The file {fileInfo.Name} was not found.");
+ }
+
+ if (fileInfo.Name != "OS_Settings.User.xml")
+ {
+ throw new ArgumentException("The provided file is not OS_Settings.User.xml.");
+ }
+
+ return fileInfo;
+ }
+
+ private static FileInfo GetTarget(string target = null)
+ {
+ FileInfo fileInfo;
+
+ Console.Info("Full path of target/output .bin file:");
+
+ if (target == null)
+ {
+ string input = System.Console.In.ReadLine();
+
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ throw new NullReferenceException("The supplied path was null, empty, or whitespace.");
+ }
+
+ fileInfo = new FileInfo(Path.GetFullPath(input));
+ }
+ else
+ {
+ Console.Info(target);
+ fileInfo = new FileInfo(Path.GetFullPath(target));
+ }
+
+ if (!fileInfo.Exists)
+ {
+ throw new FileNotFoundException($"The file {fileInfo.Name} was not found.");
+ }
+
+ if (!fileInfo.Extension.EndsWith("bin"))
+ {
+ throw new ArgumentException("The provided file lacks the .bin extension.");
+ }
+
+ return fileInfo;
+
+ }
+
+ private static void Save(FileInfo source, FileInfo target)
+ {
+ Console.Info("Saving weapon positions...");
+
+ var openSauce = (OpenSauce) source.FullName;
+
+ openSauce.Load();
+ openSauce.Objects.Weapon.Save(target.FullName);
+ openSauce.Objects.Weapon.Load(target.FullName);
+
+ foreach (var position in openSauce.Objects.Weapon.Positions)
+ Console.Debug($"Weapon: {position.Name} | I/J/K: {position.Position.I}/{position.Position.J}/{position.Position.K}");
+ }
+ }
+}
diff --git a/src/Common/ExtProcess.cs b/src/Common/ExtProcess.cs
index 017a785b..8a1a13b8 100644
--- a/src/Common/ExtProcess.cs
+++ b/src/Common/ExtProcess.cs
@@ -1,4 +1,4 @@
-/**
+/**
* Copyright (c) 2019 Emilian Roman
* Copyright (c) 2021 Noah Sherwin
*
@@ -31,4 +31,4 @@ public static bool RunningAsAdmin()
return Principle.IsInRole(WindowsBuiltInRole.Administrator);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/HCE/Executable.cs b/src/HCE/Executable.cs
index f897d812..eb1902fa 100644
--- a/src/HCE/Executable.cs
+++ b/src/HCE/Executable.cs
@@ -1,4 +1,4 @@
-/**
+/**
* Copyright (c) 2019 Emilian Roman
* Copyright (c) 2021 Noah Sherwin
*
@@ -66,16 +66,16 @@ public static Executable Detect()
var log = (File) Paths.Exception;
log.AppendAllText("The inferred executable path was probably malformed or incomplete.\n Error: " + e + "\n");
- using (System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog())
+ var ofd = new Microsoft.Win32.OpenFileDialog
{
- ofd.InitialDirectory = GetFolderPath(SpecialFolder.Desktop);
- ofd.Filter = "Halo Custom Edition (haloce.exe)|haloce.exe|Halo Retail/Trial (halo.exe)|halo.exe";
- ofd.FilterIndex = 1;
- ofd.RestoreDirectory = true;
-
- if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
- fullName = GetFullPath(ofd.FileName);
- }
+ InitialDirectory = GetFolderPath(SpecialFolder.Desktop),
+ Filter = "Halo Custom Edition (haloce.exe)|haloce.exe|Halo Retail/Trial (halo.exe)|halo.exe",
+ FilterIndex = 1,
+ RestoreDirectory = true
+ };
+
+ if (ofd.ShowDialog() == true)
+ fullName = GetFullPath(ofd.FileName);
}
if (System.IO.File.Exists(fullName))
@@ -238,4 +238,4 @@ public class MiscellaneousOptions
public bool NoVideo { get; set; }
}
}
-}
\ No newline at end of file
+}
diff --git a/src/HXE.csproj b/src/HXE.csproj
index c09650e2..029ae7bf 100644
--- a/src/HXE.csproj
+++ b/src/HXE.csproj
@@ -6,8 +6,8 @@
AnyCPU
false
Exe
- net5.0-windows
- net5.0-windows;net6.0-windows
+ net462
+ net462;net480;net5.0-windows;net6.0-windows
HXE.Program
HXE
HXE
@@ -34,11 +34,11 @@
https://github.com/HaloSPV3/HXE
snupkg
-
+ true
- true
- win-x86
-
+ false
+ win-x86
+ true
{ACAA5D9F-B23D-43E1-B2DF-8C03230975A1}
Properties
@@ -47,13 +47,16 @@
true
hxe
true
- true
+ en-US
+ true
+ $([MSBuild]::VersionGreaterThanOrEquals($(NETCoreSdkVersion), '6.0.300'))
+ $(Win7SF)
-
+
x64
false
-
+
x86
true
@@ -61,15 +64,21 @@
DEBUG;TRACE
+ false
TRACE
+
+ true
+ true
+ true
+
.root\%(Filename)%(Extension)
Never
- .root\.github\%(RecursiveDir)%(Filename)%(Extension)
+ .root\.github\%(RecursiveDir)%(Filename)%(Extension)
.docs\%(RecursiveDir)%(Filename)%(Extension)
@@ -117,7 +126,10 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
+
+
+
diff --git a/src/Installer.cs b/src/Installer.cs
index 52a1447c..651ed81d 100644
--- a/src/Installer.cs
+++ b/src/Installer.cs
@@ -22,7 +22,6 @@
using System;
using System.IO;
using System.IO.Compression;
-using System.Management;
using System.Threading;
using System.Threading.Tasks;
using HXE.Properties;
@@ -70,18 +69,20 @@ public static void Install(string source, string target, IProgress progr
if (!Directory.Exists(target))
Directory.CreateDirectory(target);
- if (enableLZNT1)
+ if (enableLZNT1) /// TODO: refactor to new Method for use from other Classes.
{
- var dirInfo = new DirectoryInfo(target);
- if ((dirInfo.Attributes & FileAttributes.Compressed) != FileAttributes.Compressed)
+ string[] directories = Directory.GetDirectories(target);
+ string[] files = Directory.GetFiles(target);
+ foreach (string directoryPath in directories)
{
- var objPath = $"Win32_Directory.Name='{target}'";
- using (var dir = new ManagementObject(objPath))
- {
- var outParams = dir.InvokeMethod("Compress", null, null);
- uint ret = (uint) outParams.Properties["ReturnValue"].Value;
- }
+ new DirectoryInfo(directoryPath).Attributes |= FileAttributes.Compressed;
}
+ foreach (string filePath in files)
+ {
+ new FileInfo(filePath).Attributes |= FileAttributes.Compressed;
+ }
+
+ /// TODO: Introduce and display progress of changes using Events
}
Info("Gracefully created target directory");
diff --git a/src/Kernel.cs b/src/Kernel.cs
index d4b18744..d8b4ddc7 100644
--- a/src/Kernel.cs
+++ b/src/Kernel.cs
@@ -1,4 +1,4 @@
-/**
+/**
* Copyright (c) 2019 Emilian Roman
* Copyright (c) 2021 Noah Sherwin
*
@@ -31,7 +31,6 @@
using static System.IO.Directory;
using static System.IO.Path;
using static System.Text.Encoding;
-using static System.Windows.Forms.Screen;
using static HXE.Console;
using static HXE.HCE.Profile.ProfileAudio;
using static HXE.HCE.Profile.ProfileVideo;
@@ -436,19 +435,22 @@ void Video()
{
if (!configuration.Video.ResolutionEnabled)
{
+ var w = System.Windows.SystemParameters.PrimaryScreenWidth;
+ var h = System.Windows.SystemParameters.PrimaryScreenHeight;
+
// infer from resolution if Native Resoluton preferred.
if (executable.Video.Width == 0 || executable.Video.Height == 0)
{
- executable.Video.Width = (ushort) PrimaryScreen.Bounds.Width;
- executable.Video.Height = (ushort) PrimaryScreen.Bounds.Height;
+ executable.Video.Width = (ushort) System.Windows.SystemParameters.PrimaryScreenWidth;
+ executable.Video.Height = (ushort) System.Windows.SystemParameters.PrimaryScreenHeight;
Core("BLAM.VIDEO.RESOLUTION: No resolution provided. Applied native resolution to executable.");
}
- else if (executable.Video.Width > (ushort) PrimaryScreen.Bounds.Width ||
- executable.Video.Height > (ushort) PrimaryScreen.Bounds.Height)
+ else if (executable.Video.Width > (ushort) System.Windows.SystemParameters.PrimaryScreenWidth ||
+ executable.Video.Height > (ushort) System.Windows.SystemParameters.PrimaryScreenHeight)
{
- executable.Video.Width = (ushort) PrimaryScreen.Bounds.Width;
- executable.Video.Height = (ushort) PrimaryScreen.Bounds.Height;
+ executable.Video.Width = (ushort) System.Windows.SystemParameters.PrimaryScreenWidth;
+ executable.Video.Height = (ushort) System.Windows.SystemParameters.PrimaryScreenHeight;
Core("BLAM.VIDEO.RESOLUTION: Resolution out of bounds. Applied native resolution to executable.");
}
@@ -1076,7 +1078,7 @@ public class ConfigurationMain
public class ConfigurationVideo
{
- public bool ResolutionEnabled { get; set; } = false; /* custom resolution */
+ public bool ResolutionEnabled { get; set; } = false; /* auto resolution */
public bool Uncap { get; set; } = true; /* unlock framerate */
public bool Quality { get; set; } /* set to false by default for optimisation */
public bool GammaOn { get; set; } = false; /* enable hce gamma */
@@ -1107,4 +1109,4 @@ public class ConfigurationTweaks
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/MCC/Halo1.cs b/src/MCC/Halo1.cs
index 12dc24e3..9f7e264b 100644
--- a/src/MCC/Halo1.cs
+++ b/src/MCC/Halo1.cs
@@ -114,7 +114,7 @@ public static bool Halo1DLLIsCertified()
try
{
var response = Client.GetAsync(uri).Result;
- MemoryStream ms = (MemoryStream) response.Content.ReadAsStream();
+ var ms = (MemoryStream) response.Content.ReadAsStreamAsync().Result;
byte[] msArray = ms.ToArray();
remoteCert = new X509Certificate(msArray);
}
diff --git a/src/Positions.xaml.cs b/src/Positions.xaml.cs
index 47175737..fdb44202 100644
--- a/src/Positions.xaml.cs
+++ b/src/Positions.xaml.cs
@@ -19,7 +19,7 @@
*/
using System.Windows;
-using System.Windows.Forms;
+using Microsoft.Win32;
using static HXE.Console;
using MessageBox = System.Windows.MessageBox;
@@ -28,7 +28,7 @@ namespace HXE
///
/// Interaction logic for Positions.xaml
///
- public partial class Positions
+ public partial class Positions : Window
{
private string _source;
private string _target;
@@ -67,16 +67,17 @@ private void Cancel(object sender, RoutedEventArgs e)
private void BrowseSource(object sender, RoutedEventArgs e)
{
- using (var dialog = new OpenFileDialog())
- {
- dialog.DefaultExt = ".xml";
- dialog.Filter = "XML files (*.xml)|*.xml";
+ var dialog = new OpenFileDialog
+ {
+ DefaultExt = ".xml",
+ Filter = "XML files (*.xml)|*.xml"
+ };
- if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
+ if (dialog.ShowDialog() != true) return;
_source = dialog.FileName;
SourceTextBox.Text = _source;
- }
+
}
private void BrowseTarget(object sender, RoutedEventArgs e)
@@ -87,7 +88,7 @@ private void BrowseTarget(object sender, RoutedEventArgs e)
Filter = "BIN files (*.bin)|*.bin"
};
- if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
+ if (dialog.ShowDialog() != true) return;
_target = dialog.FileName;
TargetTextBox.Text = _target;
diff --git a/src/Process.cs b/src/Process.cs
index fe911839..2c9334d8 100644
--- a/src/Process.cs
+++ b/src/Process.cs
@@ -1,4 +1,4 @@
-/**
+/**
* Copyright (c) 2021 Emilian Roman
*
* This software is provided 'as-is', without any express or implied
@@ -25,8 +25,9 @@
namespace HXE
{
- public class Process
+ public static class Process
{
+ private const string ExceptionHeader = " -- Process Inference failed";
public enum Type
{
Unknown,
@@ -38,105 +39,179 @@ public enum Type
}
public static IEnumerable Candidates { get; } = new List
- {
- new Candidate { Type = Type.Retail, Name = "halo" },
- new Candidate { Type = Type.HCE, Name = "haloce" },
- new Candidate { Type = Type.Steam, Name = "MCC-Win64-Shipping" },
- new Candidate { Type = Type.StoreOld, Name = "MCC-Win64-Shipping-WinStore" },
- new Candidate { Type = Type.Store, Name = "MCCWinStore-Win64-Shipping" }
- };
+ {
+ new Candidate { Type = Type.Retail, Name = "halo" },
+ new Candidate { Type = Type.HCE, Name = "haloce" },
+ new Candidate { Type = Type.Steam, Name = "MCC-Win64-Shipping" },
+ new Candidate { Type = Type.StoreOld, Name = "MCC-Win64-Shipping-WinStore" },
+ new Candidate { Type = Type.Store, Name = "MCCWinStore-Win64-Shipping" }
+ };
+
+ public static Result LastResult { get; internal set; }
///
- /// Infers the running Halo executable, with support for HCE, HCE and MCC (Steam & Windows Store).
+ /// An informative alternative to Infer()
+ /// Infers the running Halo executable, with support for Halo Retail, Halo Custom Edition, and MCC (Steam & Windows Store)
+ ///
+ /// , a static instance of that was updated by Infer() and its called method(s)
+ public static Result InferResult()
+ {
+ _ = Infer();
+ return LastResult;
+ }
+
+ ///
+ /// Infers the running Halo executable, with support for Halo Retail, Halo Custom Edition, and MCC (Steam & Windows Store).
///
/// Type of Platform
public static Type Infer()
{
- var processCandidate = new Candidate();
+ Candidate processCandidate = null;
+ List processList = GetProcesses().ToList();
try
{
- processCandidate = Candidates
- .FirstOrDefault(x => DeeperCheck(GetProcesses()
- .FirstOrDefault(Processname => Processname.ProcessName == x.Name), x.Name));
+ processCandidate = Candidates.First(x => DeeperCheck(x, processList));
}
catch (System.Exception e)
{
- var msg = $" -- Process Inference failed{NewLine}Error: { e }{NewLine}";
- var log = (File) Paths.Exception;
- log.AppendAllText(msg);
- Console.Info(msg);
- throw;
+ ErrorOutput(e, "");
+ LastResult.Success = false;
+ LastResult.Type = Type.Unknown;
+ LastResult.Message = "An unhandled exception occurred" + NewLine + e.ToString();
}
- return processCandidate?.Type ?? Type.Unknown;
+ if (processCandidate?.Type == null)
+ {
+ LastResult.Success = false;
+ LastResult.Type = Type.Unknown;
+ LastResult.Message =
+ "No running processes matched the following criteria:" + NewLine +
+ "halo.exe v1.0.10.621" + NewLine +
+ "haloce.exe v1.0.10.621" + NewLine +
+ "MCC-Win64-Shipping.exe with CEA DLC" + NewLine +
+ "MCC-Win64-Shipping-WinStore.exe with CEA DLC" + NewLine +
+ "MCCWinStore-Win64-Shipping.exe with CEA DLC";
+ return Type.Unknown;
+ }
+ else
+ {
+ /// LastResult has already been set by DeeperCheck()
+ return processCandidate.Type;
+ }
}
- private static bool DeeperCheck(System.Diagnostics.Process process, string candidateName)
+ private static bool DeeperCheck(Candidate candidate, List processList)
{
- /** Check for NullReferenceException (no processes match current candidate) */
+ System.Diagnostics.Process process;
try
{
- bool check = process.ProcessName == candidateName;
+ process = processList.First(p => p.ProcessName == candidate.Name);
}
- catch (System.NullReferenceException)
+ catch (System.InvalidOperationException)
{
- return false;
+ return false; /// No processes match current candidate
}
+ /// Each case sets assigns Success, Type, and Message to LastResult.
+ /// If a valid process is found...
+ /// ...LastResult.Success is set to true (else, false)
+ /// ...LastResult.Type is set to the matching Type (else, unknown)
+ /// ...LastResult.Message is set to an informative string (else, still informative)
+ /// ...DeeperCheck returns a bool representing whether the current Candidate is a match
switch (process.ProcessName)
{
case "halo":
+ LastResult.Success = InspectHPC();
+ LastResult.Type = Type.Retail;
+ return LastResult.Success;
case "haloce":
- {
- try
- {
- return process.MainModule.FileVersionInfo.FileVersion == "01.00.10.0621";
- }
- catch (System.Exception e)
- {
- ErrorOutput(e, "Failed to assess Halo/HaloCE process.");
- return false;
- }
- }
+ LastResult.Success = InspectHPC();
+ LastResult.Type = Type.HCE;
+ return LastResult.Success;
case string a when a.Contains("MCC") && a.Contains("WinStore"): // redundant, but good practice
case "MCC-Win64-Shipping-WinStore":
case "MCCWinStore-Win64-Shipping":
+ LastResult.Success = InspectMCC();
+ LastResult.Type = Type.Store;
+ return LastResult.Success;
case "MCC-Win64-Shipping":
- {
- try
- {
- return process.Modules
- .Cast()
- .Any(module => module.ModuleName == Paths.MCC.H1dll);
- }
- catch (System.Exception e)
- {
- var msg2 = string.Empty;
- msg2 += Is64BitProcess ? "Current process is 64-bit." : "Current process is not 32-bit.";
- msg2 += NewLine;
- msg2 += Is64BitOperatingSystem ? "Operating system is 64-bit." : "Operating system is NOT 64-bit.";
- ErrorOutput(e, msg2);
- return false;
- }
- }
+ LastResult.Success = InspectMCC();
+ LastResult.Type = Type.Steam;
+ return LastResult.Success;
default:
return false;
}
- void ErrorOutput(System.Exception e, string msg2)
+
+ bool InspectHPC()
+ {
+ try
+ {
+ bool isValid = process.MainModule.FileVersionInfo.FileVersion == "01.00.10.0621";
+ LastResult.Message = isValid ?
+ "Valid Halo/HaloCE process found" :
+ "Discovered a Halo/HaloCE process, but its version does not match 01.00.10.0621";
+ return isValid;
+ }
+ catch (System.Exception e)
+ {
+ const string msg = "Failed to assess Halo/HaloCE process";
+ LastResult.Message = msg;
+ ErrorOutput(e, msg);
+ return false;
+ }
+ }
+
+ bool InspectMCC()
{
- var msg = $" -- Process Inference failed{NewLine}{msg2}{NewLine}Error: { e }{NewLine}";
- var log = (File) Paths.Exception;
- log.AppendAllText(msg);
- Console.Error(msg); ;
+ try
+ {
+ bool isValid = process.Modules
+ .Cast()
+ .Any(module => module.ModuleName == Paths.MCC.H1dll);
+ LastResult.Message = "Found MCC process with halo1.dll loaded";
+ return isValid;
+ }
+ catch (System.ComponentModel.Win32Exception e)
+ {
+ string msg = "MCC process found, but cannot inspect its modules because 32-bit processes cannot inspect 64-bit processes" + NewLine
+ + (Is64BitProcess ? "Current process is 64-bit." : "Current process NOT 64-bit.") + NewLine
+ + (Is64BitOperatingSystem ? "Operating system is 64-bit." : "Operating system is NOT 64-bit.");
+ LastResult.Message = msg;
+ ErrorOutput(e, msg);
+ return false;
+ }
+ catch (System.Exception e)
+ {
+ const string msg = "MCC process found, but failed to inspect loaded modules for halo1.dll for an unknown reason";
+ LastResult.Message = msg;
+ ErrorOutput(e, msg);
+ return false;
+ }
}
}
+ private static void ErrorOutput(System.Exception e, string msg2)
+ {
+ string msg = ExceptionHeader + NewLine
+ + msg2 + NewLine
+ + "Error: " + e.ToString();
+ ((File)Paths.Exception).AppendAllText(msg + NewLine);
+ Console.Error(msg);
+ }
+
public class Candidate
{
public Type Type { get; set; }
public string Name { get; set; }
}
+
+ public class Result
+ {
+ public bool Success { get; set; }
+ public Type Type { get; set; }
+ public string Message { get; set; }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Program.cs b/src/Program.cs
index 7fa167ae..bb40a6ca 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -22,7 +22,7 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Reflection;
+using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using HXE.HCE;
@@ -60,6 +60,7 @@ public static void Main(string[] args)
/// --test Start a dry run of HXE to self-test
/// --config Opens configuration GUI
/// --positions Opens first-person model positions GUI
+ /// --cli Opens CLI instead of GUI where available
/// --install=VALUE Installs HCE/SPV3 to destination
/// --compile=VALUE Compiles HCE/SPV3 to destination
/// --update=VALUE Updates directory with specified manifest
@@ -76,6 +77,7 @@ public static void Main(string[] args)
/// --vidmode=VALUE Loads HCE with custom res. and Hz
/// --refresh=VALUE Loads HCE with custom refresh rate
///
+ /// TODO: implement --silent to run CLI without user prompts;
private static void InvokeProgram(string[] args)
{
Directory.CreateDirectory(Paths.Directory);
@@ -84,6 +86,7 @@ private static void InvokeProgram(string[] args)
var test = false; /* Start a dry run of HXE to self-test */
var config = false; /* Opens configuration GUI */
var positions = false; /* Opens positions GUI */
+ var cli = false; /* Opens CLI instead of GUI where available */
var install = string.Empty; /* Installs HCE/SPV3 to destination */
var compile = string.Empty; /* Compiles HCE/SPV3 to destination */
var update = string.Empty; /* Updates directory using manifest */
@@ -105,6 +108,7 @@ private static void InvokeProgram(string[] args)
.Add("test", "Start a dry run of HXE to self-test", s => test =s != null) /* hxe command */
.Add("config", "Opens configuration GUI", s => config = s != null) /* hxe command */
.Add("positions", "Opens positions GUI", s => positions = s != null) /* hxe command */
+ .Add("cli", "Enable CLI of Positions or Config", s => cli = s != null) /* hxe parameter */
.Add("install=", "Installs HCE/SPV3 to destination", s => install = s) /* hxe parameter */
.Add("compile=", "Compiles HCE/SPV3 to destination", s => compile = s) /* hxe parameter */
.Add("update=", "Updates directory using manifest", s => update = s) /* hxe parameter */
@@ -131,7 +135,7 @@ private static void InvokeProgram(string[] args)
if (help)
{
options.WriteOptionDescriptions(Out);
- Exit(0);
+ WithCode(Code.Success);
}
if (test)
@@ -151,6 +155,7 @@ private static void InvokeProgram(string[] args)
catch (Exception e)
{
Error("Settings window threw an exception!" + NewLine + e.ToString());
+ throw;
}
try
@@ -160,24 +165,36 @@ private static void InvokeProgram(string[] args)
app = new Application();
_ = app.Run(test_positions);
app.Shutdown();
+ //string target = Path.Combine(CurrentDirectory, "positions.bin");
+ //Positions.Run(source, target);
+ Logs("TODO: Positions test requires an OpenSauce.User.xml file.");
Logs("Positions Test: Succeeded");
}
catch (Exception e)
{
Error("Positions window threw an exception!" + NewLine + e.ToString());
+ throw;
}
+ WithCode(Code.Success);
}
if (config)
{
_ = new Application().Run(new Settings());
- Exit(0);
+ WithCode(Code.Success);
}
if (positions)
{
- _ = new Application().Run(new Positions());
- Exit(0);
+ if (cli)
+ {
+ CLI.Positions.Run();
+ }
+ else
+ {
+ _ = new Application().Run(new Positions());
+ }
+ WithCode(Code.Success);
}
if (infer)
@@ -193,9 +210,9 @@ private static void InvokeProgram(string[] args)
};
Info($"Inferred the following Halo process: {descriptions[Process.Infer()]}");
- Info("Press any key to exit.");
+ Info("Press Enter to exit");
_ = ReadLine();
- Exit(0);
+ WithCode(Code.Success);
}
if (!string.IsNullOrWhiteSpace(install))
@@ -253,9 +270,9 @@ private static void InvokeProgram(string[] args)
" -- Looked in working directory, Program Files, and Registry." + NewLine +
" -- The working directory is " + CurrentDirectory + NewLine +
" -- Error: " + NewLine +
- e.ToString() + NewLine;
+ e.ToString();
var log = (File) Paths.Exception;
- log.AppendAllText(msg);
+ log.AppendAllText(msg + NewLine);
Error(msg);
}
@@ -369,7 +386,7 @@ internal static int GetLongestStringLength(string[] strings)
{
foreach (string line in s.Split('\n'))
{
- lines.AddRange(line.Split('\r', StringSplitOptions.RemoveEmptyEntries));
+ lines.AddRange(line.Split('\r').Where(l => !string.IsNullOrWhiteSpace(l)));
}
}
diff --git a/src/Properties/PublishProfiles/Release_net462_fdd.pubxml b/src/Properties/PublishProfiles/Release_net462_fdd.pubxml
new file mode 100644
index 00000000..23931aea
--- /dev/null
+++ b/src/Properties/PublishProfiles/Release_net462_fdd.pubxml
@@ -0,0 +1,14 @@
+
+
+
+
+ Release
+ Any CPU
+ false
+ ..\bin\Release\net462\publish\
+ FileSystem
+ net462
+
+
diff --git a/src/Properties/PublishProfiles/Release_net6.0-windows_fdd.pubxml b/src/Properties/PublishProfiles/Release_net6.0-windows_fdd.pubxml
new file mode 100644
index 00000000..2b1bae69
--- /dev/null
+++ b/src/Properties/PublishProfiles/Release_net6.0-windows_fdd.pubxml
@@ -0,0 +1,16 @@
+
+
+
+
+ Release
+ Any CPU
+ ..\bin\Release\net6.0-windows\publish\
+ FileSystem
+ net6.0-windows
+ false
+ true
+ true
+
+
diff --git a/src/Properties/PublishProfiles/Release_net6.0-windows_win-x64.pubxml b/src/Properties/PublishProfiles/Release_net6.0-windows_win-x64.pubxml
new file mode 100644
index 00000000..7dd060fb
--- /dev/null
+++ b/src/Properties/PublishProfiles/Release_net6.0-windows_win-x64.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ Release
+ Any CPU
+ ..\bin\Release\net6.0-windows\win-x64\publish\
+ FileSystem
+ net6.0-windows
+ true
+ true
+ true
+ win-x64
+ False
+
+
diff --git a/src/Properties/PublishProfiles/Release_net6.0-windows_win-x86.pubxml b/src/Properties/PublishProfiles/Release_net6.0-windows_win-x86.pubxml
new file mode 100644
index 00000000..bf2b3263
--- /dev/null
+++ b/src/Properties/PublishProfiles/Release_net6.0-windows_win-x86.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ Release
+ Any CPU
+ ..\bin\Release\net6.0-windows\win-x64\publish\
+ FileSystem
+ net6.0-windows
+ true
+ true
+ true
+ win-x86
+ False
+
+
diff --git a/src/Properties/PublishProfiles/Release_net6.0-windows_win7-x86.pubxml b/src/Properties/PublishProfiles/Release_net6.0-windows_win7-x86.pubxml
new file mode 100644
index 00000000..7d553ca3
--- /dev/null
+++ b/src/Properties/PublishProfiles/Release_net6.0-windows_win7-x86.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ Release
+ Any CPU
+ ..\bin\Release\net6.0-windows\win7-x86\publish\
+ FileSystem
+ net6.0-windows
+ win7-x86
+ true
+ false
+ $('$(Win7SF)' == 'true')
+
+
diff --git a/src/SFX.cs b/src/SFX.cs
index f2ce4e93..82b0b2ba 100644
--- a/src/SFX.cs
+++ b/src/SFX.cs
@@ -30,7 +30,6 @@
using static System.IO.FileMode;
using static System.IO.Path;
using static System.IO.SeekOrigin;
-using static System.Reflection.Assembly;
using static System.Text.Encoding;
using static HXE.Console;
@@ -366,7 +365,7 @@ public class Configuration
public string Filter { get; set; } = "*";
public FileInfo Executable { get; set; } = new FileInfo(System.AppContext.BaseDirectory
- ?? throw new InvalidOperationException());
+ ?? throw new InvalidOperationException());
}
}
}
diff --git a/src/Settings.xaml b/src/Settings.xaml
index 04ee2f27..2bc84434 100644
--- a/src/Settings.xaml
+++ b/src/Settings.xaml
@@ -1,4 +1,4 @@
-