Skip to content

Commit

Permalink
Implemented crosshair scaling to FOV
Browse files Browse the repository at this point in the history
  • Loading branch information
hyperbx committed Jul 21, 2024
1 parent 1827062 commit e4f59f6
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 16 deletions.
3 changes: 2 additions & 1 deletion Ausar/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics;
using Ausar.Extensions;
using System.Diagnostics;
using System.IO;
using System.Windows;

Expand Down
2 changes: 1 addition & 1 deletion Ausar/Ausar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<PackageReference Include="MahApps.Metro.IconPacks.Material" Version="5.0.0" />
<PackageReference Include="ModernWpfUI" Version="0.9.6" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Process.Extensions" Version="1.0.13" />
<PackageReference Include="Process.Extensions" Version="1.0.32" />
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
<PackageReference Include="Vanara.Core" Version="4.0.2" />
<PackageReference Include="Vanara.PInvoke.Kernel32" Version="4.0.2" />
Expand Down
5 changes: 5 additions & 0 deletions Ausar/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class Configuration : INotifyPropertyChanged

public bool IsApplyCustomFOVToVehicles { get; set; } = false;

public byte CrosshairScaleMode { get; set; } = (byte)ECrosshairScaleMode.Off;

public bool IsDynamicAspectRatio { get; set; } = false;

public int ResolutionScale { get; set; } = 100;
Expand Down Expand Up @@ -120,6 +122,9 @@ public int PerformancePreset

#region Frontend Config

[JsonIgnore]
public bool IsCrosshairScaleModeAvailable { get; set; } = true;

[JsonIgnore]
public bool IsDynamicAspectRatioAvailable { get; set; } = true;

Expand Down
9 changes: 9 additions & 0 deletions Ausar/Enums/ECrosshairScaleMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Ausar.Enums
{
public enum ECrosshairScaleMode : byte
{
Off,
Scale,
ScaleSmartLink
}
}
28 changes: 28 additions & 0 deletions Ausar/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Ausar.Extensions
{
public static class StringExtensions
{
public static string Truncate(this string in_str, int in_maxLength, bool in_isEllipsis = false)
{
if (string.IsNullOrEmpty(in_str))
return in_str;

if (in_str.Length <= in_maxLength)
return in_str;

if (in_isEllipsis)
{
if (in_maxLength <= 3)
{
return in_str[..in_maxLength];
}
else
{
return in_str[..(in_maxLength - 3)] + "...";
}
}

return in_str[..in_maxLength];
}
}
}
131 changes: 121 additions & 10 deletions Ausar/Game/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ public class Memory : IDisposable
{
private const float _defaultAspectRatio = 1.777777777777778f;
private const float _defaultFOV = 78.0f;
private const float _maxCrosshairScale = 150.0f;
private const float _minCrosshairScale = 50.0f;
private const float _maxFOV = 150.0f;
private const float _minFOV = 60.0f;

private CancellationTokenSource _cancellationTokenSource = new();
private static bool _isScaleCrosshairToFOVInitialised = false;
private static bool _isDynamicAspectRatioInitialised = false;

private bool _isDynamicAspectRatioInitialised = false;
private bool _isUpdating = true;

private int[] _simPresentIntervals = [60, 30, 120];

Expand Down Expand Up @@ -72,6 +77,11 @@ public float FOV
}
}

public float FOVZoomScalar
{
get => Process.Read<float>(Process.ToASLR(0x144857858));
}

// Research from H5Tweak, ported from game version 1.114.4592.2
public float AspectRatio
{
Expand Down Expand Up @@ -187,7 +197,7 @@ public Memory(Process in_process)

private void Update()
{
while (!_cancellationTokenSource.IsCancellationRequested)
while (_isUpdating)
{
InstallPatches();

Expand Down Expand Up @@ -263,6 +273,107 @@ private void PatchApplyCustomFOVToVehicles(bool in_isEnabled)
}
}

private unsafe void PatchCrosshairScaleMode(ECrosshairScaleMode in_mode)
{
/* HACK: The mid-ASM hook is written in a function that is run
so frequently in-game that it can cause a crash if the
code is jumped to whilst still being written. */
if (Map.Contains("mainmenu"))
{
App.Settings.IsCrosshairScaleModeAvailable = true;
}
else
{
App.Settings.IsCrosshairScaleModeAvailable = false;
return;
}

var crosshairMatrixHookAddr = Process.ToASLR(0x1417147C7);
var crosshairScaleModeAddr = Process.Alloc("CrosshairScaleMode", 1);

if (in_mode != ECrosshairScaleMode.Off)
{
Process.Write(crosshairScaleModeAddr, App.Settings.CrosshairScaleMode);

if (!_isScaleCrosshairToFOVInitialised)
{
// Hook matrix code for crosshair.
_isScaleCrosshairToFOVInitialised = Process.TryWriteAsmHook
(
$@"
mov r11d, 0x42700000 ; Store minimum FOV value (60.0f) in R11D.
movd xmm0, r11d ; Copy R11D to XMM0.
mov r11d, 0x43160000 ; Store maximum FOV value (150.0f) in R11D.
movd xmm1, r11d ; Copy R11D to XMM1.
mov r11, {(long)Process.ToASLR(0x14590E210)} ; Store address to FOV value in R11.
movss xmm2, dword ptr [r11] ; Copy FOV value to XMM2.
mov r11, {(long)Process.ToASLR(0x144857858)} ; Store address to FOV zoom scalar value in R11.
movss xmm3, dword ptr [r11] ; Copy FOV zoom scalar value to XMM3.
mov r11, {(long)crosshairScaleModeAddr} ; Store address to crosshair scale mode in R11.
cmp byte ptr [r11], 2 ; Compare crosshair scale mode with 2 (ECrosshairScaleMode.ScaleSmartLink).
jne ignoreZoom ; Jump if not 2; otherwise, apply FOV zoom scalar value.
divss xmm2, xmm3 ; XMM2 = FOV / FOVZoomScalar
ignoreZoom:
subss xmm2, xmm0 ; XMM2 -= _minFOV
subss xmm1, xmm0 ; XMM1 = _maxFOV - _minFOV
divss xmm2, xmm1 ; XMM2 /= XMM1
mov r11d, 0x42480000 ; Store minimum crosshair scale value (50.0f) in R11D.
movd xmm3, r11d ; Copy R11D to XMM3.
mov r11d, 0x43160000 ; Store maximum crosshair scale value (150.0f) in R11D.
movd xmm4, r11d ; Copy R11D to XMM4.
; Linear interpolation routine.
subss xmm4, xmm3 ; XMM4 = _maxCrosshairScale - _minCrosshairScale
mulss xmm2, xmm4 ; XMM2 *= XMM4
addss xmm2, xmm3 ; XMM2 += _minCrosshairScale
mov r11d, 0x41F00000 ; Store crosshair scale remainder value (30.0f) in R11D.
movd xmm5, r11d ; Copy R11D to XMM5.
addss xmm2, xmm5 ; XMM2 += 30.0f
; Clamp routine.
comiss xmm2, xmm3 ; Compare result with _minCrosshairScale.
jae checkMax ; Jump if result is greater than minimum.
movaps xmm2, xmm3 ; XMM2 = _minCrosshairScale
checkMax:
mov r11d, 0x43160000 ; Store maximum crosshair scale value (150.0f) in R11D.
movd xmm4, r11d ; Copy R11D to XMM4.
comiss xmm2, xmm4 ; Compare result with _maxCrosshairScale.
jbe end ; Jump if result is less than maximum.
movaps xmm2, xmm4 ; XMM2 = _maxCrosshairScale
end:
mov r11d, 0x42C80000 ; Store percentage max value (100.0f) in R11D.
movd xmm3, r11d ; Copy R11D to XMM3.
divss xmm2, xmm3 ; XMM2 /= 100.0f
mov r11d, 0x43B40000 ; Store radius max value (360.0f) in R11D.
movd xmm4, r11d ; Copy R11D to XMM4.
mulss xmm2, xmm4 ; XMM2 *= 360.0f
movss dword ptr [rax + 0x30], xmm2 ; Copy XMM2 to matrix at scale offset.
; Restore original code.
movups xmm0, xmmword ptr [rax]
lea r11, qword ptr [rsp + 0xC0]
movups xmm1, xmmword ptr [rax + 0x10]
",

crosshairMatrixHookAddr
);
}
}
else
{
Process.RemoveAsmHook(crosshairMatrixHookAddr);
Process.Free(crosshairScaleModeAddr);

_isScaleCrosshairToFOVInitialised = false;
}
}

private void PatchDynamicAspectRatio(bool in_isEnabled)
{
var smartLinkAspectRatioHookAddr = Process.ToASLR(0x14162D4BC);
Expand All @@ -272,12 +383,12 @@ private void PatchDynamicAspectRatio(bool in_isEnabled)
if (!_isDynamicAspectRatioInitialised)
{
// Hook aspect ratio code for Smart Link.
Process.WriteAsmHook
_isDynamicAspectRatioInitialised = Process.TryWriteAsmHook
(
$@"
mov r8, {Process.ToASLR(0x14333E458)} ; Store pointer to real aspect ratio in R8.
movss xmm6, dword ptr [r8] ; Store real aspect ratio in XMM6.
mov r9d, 0x3FE38E39 ; Store 1.777777777777778f in R9D.
mov r9d, 0x3FE38E39 ; Store default aspect ratio (1.777777777777778f) in R9D.
movd xmm7, r9d ; Copy R9D to XMM7.
divss xmm6, xmm7 ; Divide real aspect ratio (XMM6) by default aspect ratio (XMM7).
mulss xmm0, xmm6 ; Multiply Smart Link aspect ratio (XMM0) by our divided value (XMM6).
Expand All @@ -291,13 +402,11 @@ private void PatchDynamicAspectRatio(bool in_isEnabled)

smartLinkAspectRatioHookAddr
);

_isDynamicAspectRatioInitialised = true;
}
}
else
{
Process.RestoreMemory(smartLinkAspectRatioHookAddr);
Process.RemoveAsmHook(smartLinkAspectRatioHookAddr);

_isDynamicAspectRatioInitialised = false;
}
Expand Down Expand Up @@ -458,6 +567,7 @@ public void InstallPatches()
return;

PatchApplyCustomFOVToVehicles(App.Settings.IsApplyCustomFOVToVehicles);
PatchCrosshairScaleMode((ECrosshairScaleMode)App.Settings.CrosshairScaleMode);
PatchDynamicAspectRatio(App.Settings.IsDynamicAspectRatio);
PatchNetworkIntegrity(FPS > 60);
PatchToggleFrontend(App.Settings.IsToggleFrontend);
Expand Down Expand Up @@ -491,9 +601,10 @@ public void UninstallPatches()
{
/* FIXME: this will only work once, not a big
deal for its current use case though. */
_cancellationTokenSource.Cancel();
_isUpdating = false;

PatchApplyCustomFOVToVehicles(false);
PatchCrosshairScaleMode(ECrosshairScaleMode.Off);
PatchDynamicAspectRatio(false);
PatchNetworkIntegrity(false);
PatchToggleFrontend(true);
Expand Down Expand Up @@ -523,7 +634,7 @@ public void UninstallPatches()

public void Dispose()
{
_cancellationTokenSource.Cancel();
_isUpdating = false;
}
}
}
10 changes: 10 additions & 0 deletions Ausar/Helpers/MathHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Ausar.Helpers
{
internal class MathHelper
{
public static float Lerp(float in_start, float in_end, float in_time)
{
return in_start + (in_end - in_start) * in_time;
}
}
}
21 changes: 17 additions & 4 deletions Ausar/UI/Trainer.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,23 @@

<Grid>
<Expander Name="FOVExpander" Margin="1,4,0,10" Template="{StaticResource RevealExpander}">
<Grid Margin="23,65,0,10">
<CheckBox Margin="1,0,0,0" Content="Apply Custom FOV to Vehicles"
<StackPanel Margin="23,65,0,10">

<StackPanel Margin="0,5,0,20">
<au:HorizontalFieldLabel Caption="Crosshair Scale Mode" Description="Determines how the crosshair will scale to this value (only accessible from main menu)."/>
<ComboBox Name="CrosshairScaleModeField" HorizontalAlignment="Stretch"
IsEnabled="{Binding Source={x:Static local:App.Settings}, Path=IsCrosshairScaleModeAvailable}"
SelectedIndex="{Binding Mode=TwoWay, Source={x:Static local:App.Settings}, Path=CrosshairScaleMode}">
<ComboBoxItem Content="Off"/>
<ComboBoxItem Content="Scale"/>
<ComboBoxItem Content="Scale + Smart Link (recommended for high FOV)"/>
</ComboBox>
</StackPanel>

<au:DescribedCheckBox Content="Apply Custom FOV to Vehicles" Description="Determines whether to use this value for the vehicle camera."
IsChecked="{Binding Mode=TwoWay, Source={x:Static local:App.Settings}, Path=IsApplyCustomFOVToVehicles}"/>
</Grid>

</StackPanel>
</Expander>

<StackPanel Margin="24,0,0,20">
Expand Down Expand Up @@ -136,7 +149,7 @@
Minimum="0" Maximum="300" SpinButtonPlacementMode="Inline" SmallChange="1"/>
</StackPanel>

<StackPanel Margin="0,0,0,25">
<StackPanel Margin="0,0,0,20">
<au:HorizontalFieldLabel Caption="Decorator Draw Distance Scalar" Description="The scalar for details like grass and debris."/>
<ui:NumberBox Value="{Binding Mode=TwoWay, Source={x:Static local:App.Settings}, Path=DecoratorDrawDistanceScalar}"
Minimum="0" Maximum="300" SpinButtonPlacementMode="Inline" SmallChange="1"/>
Expand Down
23 changes: 23 additions & 0 deletions Ausar/UI/Trainer.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Ausar.Helpers;
using Ausar.Logger.Handlers;
using ModernWpf.Controls;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
Expand Down Expand Up @@ -47,6 +48,28 @@ protected override void OnSourceInitialized(EventArgs e)
Task.Run(() => WaitForProcess(_cancellationTokenSource.Token));
}

protected override void OnClosing(CancelEventArgs e)
{
if (!App.Settings.IsCrosshairScaleModeAvailable ||
!App.Settings.IsDynamicAspectRatioAvailable)
{
var result = MessageBox.Show
(
"There are still patches installed that will not be uninstalled unless you return to the main menu first.\n\n" +
"Exiting now may lead to unexpected behaviour if Ausar is launched again with this same instance of Halo 5: Forge.\n\n" +
"Are you sure you want to quit?",
"Ausar",
MessageBoxButton.YesNo,
MessageBoxImage.Warning
);

if (result == MessageBoxResult.No)
e.Cancel = true;
}

base.OnClosing(e);
}

private void Status(string in_text, Brush in_colour = null)
{
StatusText.Text = in_text;
Expand Down

0 comments on commit e4f59f6

Please sign in to comment.