diff --git a/Dakar18Trainer/Cheats/NoSpeedLimitCheat.cs b/Dakar18Trainer/Cheats/NoSpeedLimitCheat.cs
index 17aa5ae..db6df77 100644
--- a/Dakar18Trainer/Cheats/NoSpeedLimitCheat.cs
+++ b/Dakar18Trainer/Cheats/NoSpeedLimitCheat.cs
@@ -11,15 +11,13 @@ public class NoSpeedLimitCheat: BaseCheat {
private static readonly int[] SPEED_LIMIT_OFFSETS = { 0x04194850, 0x28, 0x1A0, 0x1B0, 0xA0, 0x20, 0x20, 0x830, 0x3A8 };
- public override string name { get; } = "No speed limits";
+ public override string name { get; } = "No speed limit";
public override Combination keyboardShortcut { get; } = Combination.TriggeredBy(Keys.L).Control().Alt();
- public override void applyIfNecessary(ProcessHandle processHandle, MemoryEditor memoryEditor) {
- if (!isEnabled.Value) return;
-
+ protected override void apply(ProcessHandle processHandle) {
IndirectMemoryAddress speedLimitAddress = new(processHandle, null, SPEED_LIMIT_OFFSETS);
- memoryEditor.writeToProcessMemory(processHandle, speedLimitAddress, 9999);
+ MemoryEditor.writeToProcessMemory(processHandle, speedLimitAddress, 9999);
}
}
diff --git a/Dakar18Trainer/Dakar18Trainer.csproj b/Dakar18Trainer/Dakar18Trainer.csproj
index 489fad1..c3f9019 100644
--- a/Dakar18Trainer/Dakar18Trainer.csproj
+++ b/Dakar18Trainer/Dakar18Trainer.csproj
@@ -14,6 +14,7 @@
4
true
true
+ false
AnyCPU
diff --git a/Dakar18Trainer/Properties/AssemblyInfo.cs b/Dakar18Trainer/Properties/AssemblyInfo.cs
index bb7b9c0..e76526c 100644
--- a/Dakar18Trainer/Properties/AssemblyInfo.cs
+++ b/Dakar18Trainer/Properties/AssemblyInfo.cs
@@ -5,11 +5,11 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[assembly: AssemblyTitle("Dakar 18 v.13 +1 Trainer")]
-[assembly: AssemblyDescription("Dakar 18 v.13 +1 Trainer")]
+[assembly: AssemblyTitle("Dakar 18 v.13 +1 Trainer by Ben")]
+[assembly: AssemblyDescription("Dakar 18 v.13 +1 Trainer by Ben")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Ben Hutchison")]
-[assembly: AssemblyProduct("Dakar 18 v.13 +1 Trainer")]
+[assembly: AssemblyProduct("Dakar 18 v.13 +1 Trainer by Ben")]
[assembly: AssemblyCopyright("© 2021 Ben Hutchison")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..2864872
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,38 @@
+Trainers
+===
+
+
+### Requirements
+- [.NET Framework 4.7.2 runtime](https://dotnet.microsoft.com/download/dotnet-framework) or later (included in Windows 10 version 1803 and later)
+
+### Games
+
+
+- [Dakar 18](#dakar-18)
+- [Superhot: Mind Control Delete](#superhot-mind-control-delete)
+
+
+
+
+## Dakar 18
+
+![trainer screenshot](https://i.imgur.com/ZMcCTAs.png)
+
+[💾 Download](https://github.com/Aldaviva/Trainers/releases/download/1.0.1/Dakar18Trainer.exe)
+
+- No speed limit
+ - All speed limit warnings and penalties are removed in all difficulty levels.
+ - You are still automatically limited to 30 km/h in passage control auto-driving zones.
+
+*Supports Dakar 18 v.13, released in March 2019, which contains Desafio Ruta 40 Rally and Inca Rally*
+
+
+## Superhot: Mind Control Delete
+
+![trainer screenshot](https://i.imgur.com/yH0Msy6.png)
+
+[💾 Download](https://github.com/Aldaviva/Trainers/releases/download/1.0.1/SuperhotMindControlDeleteTrainer.exe)
+
+- Infinite health
+
+*Supports `SHMCD.exe` 1.0.0, which has file version 2018.4.5.14584*
diff --git a/SuperhotMindControlDeleteTrainer/Cheats/InfiniteHealthCheat.cs b/SuperhotMindControlDeleteTrainer/Cheats/InfiniteHealthCheat.cs
index c66a8eb..79bef35 100644
--- a/SuperhotMindControlDeleteTrainer/Cheats/InfiniteHealthCheat.cs
+++ b/SuperhotMindControlDeleteTrainer/Cheats/InfiniteHealthCheat.cs
@@ -19,18 +19,16 @@ public class InfiniteHealthCheat: BaseCheat {
public override Combination keyboardShortcut { get; } = Combination.TriggeredBy(Keys.H).Alt().Control();
- public override void applyIfNecessary(ProcessHandle processHandle, MemoryEditor memoryEditor) {
- if (!isEnabled.Value) return;
-
- FixedMemoryAddress currentHeartsAddress = new(new IndirectMemoryAddress(processHandle, MODULE_NAME, CURRENT_HEARTS_OFFSETS).address);
+ protected override void apply(ProcessHandle processHandle) {
+ FixedMemoryAddress currentHeartsAddress = new(new IndirectMemoryAddress(processHandle, MODULE_NAME, CURRENT_HEARTS_OFFSETS).address); //used twice, so don't reevaluate address
IndirectMemoryAddress maxHeartsAddress = new(processHandle, MODULE_NAME, MAX_HEARTS_OFFSETS);
- int currentHearts = memoryEditor.readFromProcessMemory(processHandle, currentHeartsAddress);
- int maxHearts = memoryEditor.readFromProcessMemory(processHandle, maxHeartsAddress);
+ int currentHearts = MemoryEditor.readFromProcessMemory(processHandle, currentHeartsAddress);
+ int maxHearts = MemoryEditor.readFromProcessMemory(processHandle, maxHeartsAddress);
if (currentHearts < maxHearts) {
Trace.WriteLine($"Setting health to {maxHearts:N0}...");
- memoryEditor.writeToProcessMemory(processHandle, currentHeartsAddress, maxHearts);
+ MemoryEditor.writeToProcessMemory(processHandle, currentHeartsAddress, maxHearts);
}
}
diff --git a/SuperhotMindControlDeleteTrainer/Properties/AssemblyInfo.cs b/SuperhotMindControlDeleteTrainer/Properties/AssemblyInfo.cs
index 5e43c1f..1272367 100644
--- a/SuperhotMindControlDeleteTrainer/Properties/AssemblyInfo.cs
+++ b/SuperhotMindControlDeleteTrainer/Properties/AssemblyInfo.cs
@@ -5,11 +5,11 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[assembly: AssemblyTitle("Superhot: Mind Control Delete 1.0.0 +1 Trainer")]
-[assembly: AssemblyDescription("Superhot: Mind Control Delete 1.0.0 +1 Trainer")]
+[assembly: AssemblyTitle("Superhot: Mind Control Delete 1.0.0 +1 Trainer by Ben")]
+[assembly: AssemblyDescription("Superhot: Mind Control Delete 1.0.0 +1 Trainer by Ben")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Ben Hutchison")]
-[assembly: AssemblyProduct("Superhot: Mind Control Delete 1.0.0 +1 Trainer")]
+[assembly: AssemblyProduct("Superhot: Mind Control Delete 1.0.0 +1 Trainer by Ben")]
[assembly: AssemblyCopyright("© 2021 Ben Hutchison")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -47,5 +47,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.0.1.0")]
+[assembly: AssemblyFileVersion("1.0.1.0")]
\ No newline at end of file
diff --git a/TrainerCommon/App/CombinationConverter.cs b/TrainerCommon/App/CombinationConverter.cs
index 7db272a..168add3 100644
--- a/TrainerCommon/App/CombinationConverter.cs
+++ b/TrainerCommon/App/CombinationConverter.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
@@ -11,15 +12,23 @@ namespace TrainerCommon.App {
public class CombinationConverter: IValueConverter {
+ private static readonly IComparer HOTKEY_SORTER = new HotkeySorter();
+
+ ///
+ /// Like Gma.System.MouseKeyHook.Combination.ToString() but it prints Ctrl instead of Control like a normal menu hotkey
+ ///
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (value is Combination combination) {
- // Like Gma.System.MouseKeyHook.Combination.ToString() but it prints Ctrl instead of Control like a normal menu hotkey
- return string.Join("+", combination.Chord.Select(key => key switch {
- Keys.Control => "Ctrl",
- _ => key.ToString()
- }).Append(combination.TriggerKey.ToString()));
+ IEnumerable modifiers = combination.Chord
+ .OrderBy(key => key, HOTKEY_SORTER)
+ .Select(key => key switch {
+ Keys.Control => "Ctrl",
+ Keys.LWin or Keys.RWin => "Win",
+ _ => key.ToString()
+ });
+ return string.Join("+", modifiers.Append(combination.TriggerKey.ToString()));
} else {
- throw new ArgumentException("value is not an instance of Combination", nameof(value));
+ throw new ArgumentException($"value {value} is not an instance of Combination", nameof(value));
}
}
@@ -27,6 +36,23 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
throw new NotImplementedException();
}
+ ///
+ /// Sort Shift after Ctrl and Alt, since this is how hotkeys appear in menus in Windows.
+ ///
+ private class HotkeySorter: IComparer {
+
+ public int Compare(Keys x, Keys y) {
+ if (x is Keys.Shift && y is Keys.Alt or Keys.Control or Keys.LWin or Keys.RWin) {
+ return 1;
+ } else if (y is Keys.Shift && x is Keys.Alt or Keys.Control or Keys.LWin or Keys.RWin) {
+ return -1;
+ } else {
+ return x.CompareTo(y);
+ }
+ }
+
+ }
+
}
}
\ No newline at end of file
diff --git a/TrainerCommon/App/MainWindow.xaml b/TrainerCommon/App/MainWindow.xaml
index 6c0a51e..0c59be5 100644
--- a/TrainerCommon/App/MainWindow.xaml
+++ b/TrainerCommon/App/MainWindow.xaml
@@ -3,13 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:trainerCommon="clr-namespace:TrainerCommon"
xmlns:app="clr-namespace:TrainerCommon.App"
mc:Ignorable="d"
- d:DataContext="{d:DesignInstance Type=trainerCommon:MainWindowViewModel, IsDesignTimeCreatable=True}"
+ d:DataContext="{d:DesignInstance Type=app:MainWindowViewModel, IsDesignTimeCreatable=True}"
Title="{Binding windowTitle}"
- Height="Auto"
- Width="275"
+ Height="Auto"
+ Width="275"
ResizeMode="CanMinimize"
WindowStartupLocation="CenterScreen"
SizeToContent="Height">
@@ -29,65 +28,30 @@
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/TrainerCommon/App/MainWindowViewModel.cs b/TrainerCommon/App/MainWindowViewModel.cs
index 7acd40e..f13fa84 100644
--- a/TrainerCommon/App/MainWindowViewModel.cs
+++ b/TrainerCommon/App/MainWindowViewModel.cs
@@ -1,7 +1,6 @@
-using System.Collections.Generic;
-using System.Linq;
+using System;
+using System.Collections.Generic;
using System.Threading;
-using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using KoKo.Property;
using TrainerCommon.Cheats;
@@ -18,7 +17,7 @@ public class MainWindowViewModel {
public Game game { get; }
- public string windowTitle => $"{game.name} {game.supportedVersion} +{game.cheats.Count:N0} Trainer";
+ public string windowTitle => $"{game.name} {game.supportedVersion} +{game.cheats.Count:N0} Trainer by Ben";
// ReSharper disable once UnusedMember.Global - used by design time DataContext DesignInstance
public MainWindowViewModel(): this(new SampleGame(), new TrainerServiceImpl()) { }
@@ -26,8 +25,14 @@ public class MainWindowViewModel {
public MainWindowViewModel(Game game, TrainerService trainerService) {
this.game = game;
- statusBarAttachmentMessage = DerivedProperty.Create(trainerService.isAttachedToGame, attached =>
- attached ? "Attached to game process" : "Detached from game process");
+ statusBarAttachmentMessage = DerivedProperty.Create(trainerService.isAttachedToGame, attached => attached switch {
+ AttachmentState.TRAINER_STOPPED => "Attaching to game…",
+ AttachmentState.PROGRAM_NOT_RUNNING => "Waiting for game to start",
+ AttachmentState.MEMORY_ADDRESS_NOT_FOUND => "Attached, memory address not found",
+ AttachmentState.MEMORY_ADDRESS_COULD_NOT_BE_READ => "Attached, memory unreadable",
+ AttachmentState.ATTACHED => "Attached to game process",
+ _ => throw new ArgumentOutOfRangeException(nameof(attached), attached, null)
+ });
statusBarAttachmentMessage.EventSynchronizationContext = SynchronizationContext.Current;
foreach (Cheat cheat in game.cheats) {
@@ -35,19 +40,31 @@ public MainWindowViewModel(Game game, TrainerService trainerService) {
}
}
+ ///
+ /// For design time
+ ///
private class SampleGame: Game {
public string name { get; } = "My Game";
public string processName { get; } = "mygame.exe";
public string supportedVersion { get; } = "1.0.0";
- public IList cheats { get; } = Enumerable.Repeat(new SampleCheat(), 2).Cast().ToList();
+
+ public IList cheats { get; } = new List {
+ new SampleCheat("Infinite ammo", "Control+Alt+LWin+A"),
+ new SampleCheat("Infinite lives", "Shift+Control+Alt+L")
+ };
private class SampleCheat: Cheat {
- public string name { get; set; } = "Infinite ammo";
- public Combination keyboardShortcut { get; set; } = Combination.TriggeredBy(Keys.A).Alt().Control();
+ public string name { get; }
+ public Combination keyboardShortcut { get; }
public SettableProperty isEnabled { get; } = new StoredProperty();
- public void applyIfNecessary(ProcessHandle processHandle, MemoryEditor memoryEditor) { }
+ public void applyIfNecessary(ProcessHandle processHandle) { }
+
+ public SampleCheat(string name, string keyBoardShortcut) {
+ this.name = name;
+ keyboardShortcut = Combination.FromString(keyBoardShortcut);
+ }
}
diff --git a/TrainerCommon/Cheats/Cheat.cs b/TrainerCommon/Cheats/Cheat.cs
index 953d3ff..5ede133 100644
--- a/TrainerCommon/Cheats/Cheat.cs
+++ b/TrainerCommon/Cheats/Cheat.cs
@@ -14,7 +14,7 @@ public interface Cheat {
SettableProperty isEnabled { get; }
- void applyIfNecessary(ProcessHandle processHandle, MemoryEditor memoryEditor);
+ void applyIfNecessary(ProcessHandle processHandle);
}
@@ -22,10 +22,16 @@ public abstract class BaseCheat: Cheat {
public abstract string name { get; }
public abstract Combination keyboardShortcut { get; }
- public abstract void applyIfNecessary(ProcessHandle processHandle, MemoryEditor memoryEditor);
+ protected abstract void apply(ProcessHandle processHandle);
public SettableProperty isEnabled { get; } = new StoredProperty();
+ public void applyIfNecessary(ProcessHandle processHandle) {
+ if (isEnabled.Value) {
+ apply(processHandle);
+ }
+ }
+
}
}
\ No newline at end of file
diff --git a/TrainerCommon/Trainer/MemoryAddresses.cs b/TrainerCommon/Trainer/MemoryAddresses.cs
index e97a54e..2b7d86f 100644
--- a/TrainerCommon/Trainer/MemoryAddresses.cs
+++ b/TrainerCommon/Trainer/MemoryAddresses.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
#nullable enable
@@ -25,38 +23,43 @@ public FixedMemoryAddress(IntPtr address) {
public readonly struct IndirectMemoryAddress: MemoryAddress {
- private readonly MemoryEditor memoryEditor;
-
- private readonly ProcessHandle processHandle;
- private readonly string? moduleName;
- private readonly IEnumerable offsets;
+ private readonly ProcessHandle processHandle;
+ private readonly string? moduleName;
+ private readonly int[] pointerOffsets;
///
/// The name of the module to which the offsets are relative, such as UnityPlayer.dll, or null to use the process' main module.
- ///
- public IndirectMemoryAddress(ProcessHandle processHandle, string? moduleName, IEnumerable offsets) {
- this.processHandle = processHandle;
- this.moduleName = moduleName;
- this.offsets = offsets;
- memoryEditor = new MemoryEditorImpl();
+ ///
+ public IndirectMemoryAddress(ProcessHandle processHandle, string? moduleName, int[] pointerOffsets) {
+ this.processHandle = processHandle;
+ this.moduleName = moduleName;
+ this.pointerOffsets = pointerOffsets;
}
public IntPtr address {
get {
- IntPtr moduleBaseAddress = memoryEditor.getModuleBaseAddressByName(processHandle, moduleName) ??
+ /*
+ * Is the game 32-bit or 64-bit?
+ * Note that the trainer must be compiled as 64-bit in order to read memory from 64-bit games.
+ */
+ int targetProcessWordLengthBytes = Win32.isProcess64Bit(processHandle.process) ? Marshal.SizeOf() : Marshal.SizeOf();
+
+ IntPtr memoryAddress = MemoryEditor.getModuleBaseAddressByName(processHandle, moduleName) ??
throw new ArgumentException($"No module with name {moduleName} found in process {processHandle.process.ProcessName}");
- int firstOffset = offsets.First();
- IntPtr memoryAddress = IntPtr.Add(moduleBaseAddress, firstOffset);
- int targetProcessWordLengthBytes = Win32.isProcess64Bit(processHandle.process) ? Marshal.SizeOf() : Marshal.SizeOf();
+ for (int offsetIndex = 0; offsetIndex < pointerOffsets.Length; offsetIndex++) {
+ int offset = pointerOffsets[offsetIndex];
- foreach (int offset in offsets.Skip(1)) {
- bool success = Win32.ReadProcessMemory(processHandle.handle, memoryAddress, out IntPtr memoryValue, targetProcessWordLengthBytes, out long _);
- if (!success) {
- throw new ApplicationException($"Could not read memory address 0x{memoryAddress.ToInt64():X}: {Marshal.GetLastWin32Error()}");
- }
+ if (offsetIndex == 0) {
+ memoryAddress = IntPtr.Add(memoryAddress, offset);
+ } else {
+ bool success = Win32.ReadProcessMemory(processHandle.handle, memoryAddress, out IntPtr memoryValue, targetProcessWordLengthBytes, out long _);
+ if (!success) {
+ throw new ApplicationException($"Could not read memory address 0x{memoryAddress.ToInt64():X}: {Marshal.GetLastWin32Error()}");
+ }
- memoryAddress = IntPtr.Add(memoryValue, offset);
+ memoryAddress = IntPtr.Add(memoryValue, offset);
+ }
}
return memoryAddress;
diff --git a/TrainerCommon/Trainer/MemoryEditor.cs b/TrainerCommon/Trainer/MemoryEditor.cs
index ba174bb..d424dee 100644
--- a/TrainerCommon/Trainer/MemoryEditor.cs
+++ b/TrainerCommon/Trainer/MemoryEditor.cs
@@ -8,21 +8,9 @@
namespace TrainerCommon.Trainer {
- public interface MemoryEditor {
+ public static class MemoryEditor {
- ProcessHandle? openProcess(Process targetProcess);
-
- public T readFromProcessMemory(ProcessHandle processHandle, MemoryAddress memoryAddress, int? bytesToRead = null);
-
- void writeToProcessMemory(ProcessHandle processHandle, MemoryAddress memoryAddress, T value);
-
- IntPtr? getModuleBaseAddressByName(ProcessHandle processHandle, string? moduleName);
-
- }
-
- public class MemoryEditorImpl: MemoryEditor {
-
- public ProcessHandle? openProcess(Process targetProcess) {
+ public static ProcessHandle? openProcess(Process targetProcess) {
IntPtr handle = Win32.OpenProcess(
Win32.ProcessAccessFlags.VIRTUAL_MEMORY_READ |
Win32.ProcessAccessFlags.VIRTUAL_MEMORY_WRITE |
@@ -31,7 +19,7 @@ public class MemoryEditorImpl: MemoryEditor {
return handle != IntPtr.Zero ? new ProcessHandle(targetProcess, handle) : null;
}
- public T readFromProcessMemory(ProcessHandle processHandle, MemoryAddress memoryAddress, int? bytesToRead = null) {
+ public static T readFromProcessMemory(ProcessHandle processHandle, MemoryAddress memoryAddress, int? bytesToRead = null) {
bytesToRead ??= Marshal.SizeOf();
byte[] buffer = new byte[(int) bytesToRead];
@@ -45,7 +33,7 @@ public T readFromProcessMemory(ProcessHandle processHandle, MemoryAddress mem
return convertBufferToType(buffer);
}
- public void writeToProcessMemory(ProcessHandle processHandle, MemoryAddress memoryAddress, T value) {
+ public static void writeToProcessMemory(ProcessHandle processHandle, MemoryAddress memoryAddress, T value) {
byte[] buffer = convertValueToBuffer(value);
bool writeSuccess = Win32.WriteProcessMemory(processHandle.handle, memoryAddress.address, buffer, buffer.Length, out IntPtr bytesWritten);
@@ -65,7 +53,7 @@ private static byte[] convertValueToBuffer(T value) {
};
}
- public IntPtr? getModuleBaseAddressByName(ProcessHandle processHandle, string? moduleName) {
+ public static IntPtr? getModuleBaseAddressByName(ProcessHandle processHandle, string? moduleName) {
return moduleName == null ? processHandle.process.MainModule?.BaseAddress : Win32.getModuleBaseAddress(new IntPtr(processHandle.process.Id), moduleName);
}
diff --git a/TrainerCommon/Trainer/TrainerService.cs b/TrainerCommon/Trainer/TrainerService.cs
index 1446b5b..c924d66 100644
--- a/TrainerCommon/Trainer/TrainerService.cs
+++ b/TrainerCommon/Trainer/TrainerService.cs
@@ -14,7 +14,7 @@ namespace TrainerCommon.Trainer {
public interface TrainerService: IDisposable {
- Property isAttachedToGame { get; }
+ Property isAttachedToGame { get; }
void attachToGame(Game game);
@@ -23,14 +23,13 @@ public interface TrainerService: IDisposable {
public class TrainerServiceImpl: TrainerService {
private readonly StoredProperty attachmentState = new();
- public Property isAttachedToGame { get; }
+ public Property isAttachedToGame { get; }
- private readonly MemoryEditor memoryEditor = new MemoryEditorImpl();
private readonly CancellationTokenSource cancellationTokenSource = new();
private Task? monitorTask;
public TrainerServiceImpl() {
- isAttachedToGame = DerivedProperty.Create(attachmentState, state => state == AttachmentState.ATTACHED);
+ isAttachedToGame = attachmentState;
attachmentState.PropertyChanged += (_, args) => Trace.WriteLine($"Trainer state: {args.NewValue}");
}
@@ -47,7 +46,7 @@ public void attachToGame(Game game) {
while (!cancellationTokenSource.IsCancellationRequested) {
await Task.Delay(attachmentState.Value switch {
AttachmentState.TRAINER_STOPPED => 0,
- AttachmentState.ATTACHED => 250,
+ AttachmentState.ATTACHED => 200,
AttachmentState.MEMORY_ADDRESS_NOT_FOUND => 2000,
AttachmentState.MEMORY_ADDRESS_COULD_NOT_BE_READ => 2000,
AttachmentState.PROGRAM_NOT_RUNNING => 10000,
@@ -64,7 +63,7 @@ public void attachToGame(Game game) {
continue;
}
- gameProcessHandle ??= memoryEditor.openProcess(gameProcess);
+ gameProcessHandle ??= MemoryEditor.openProcess(gameProcess);
if (gameProcessHandle == null) {
attachmentState.Value = AttachmentState.PROGRAM_NOT_RUNNING;
continue;
@@ -72,7 +71,7 @@ public void attachToGame(Game game) {
try {
foreach (Cheat cheat in game.cheats) {
- cheat.applyIfNecessary(gameProcessHandle, memoryEditor);
+ cheat.applyIfNecessary(gameProcessHandle);
}
attachmentState.Value = AttachmentState.ATTACHED;
@@ -85,6 +84,9 @@ public void attachToGame(Game game) {
if (e.NativeErrorCode != 299) {
Console.WriteLine(e);
}
+
+ Trace.WriteLine("Memory address could not be read");
+ Trace.WriteLine(e);
}
}
@@ -96,19 +98,24 @@ public void attachToGame(Game game) {
public void Dispose() {
cancellationTokenSource.Cancel();
- monitorTask?.GetAwaiter().GetResult();
+ try {
+ monitorTask?.GetAwaiter().GetResult();
+ } catch (TaskCanceledException) {
+ //cancellation is how this task normally ends
+ }
+
attachmentState.Value = AttachmentState.TRAINER_STOPPED;
}
- private enum AttachmentState {
+ }
- TRAINER_STOPPED,
- PROGRAM_NOT_RUNNING,
- MEMORY_ADDRESS_NOT_FOUND,
- MEMORY_ADDRESS_COULD_NOT_BE_READ,
- ATTACHED
+ public enum AttachmentState {
- }
+ TRAINER_STOPPED,
+ PROGRAM_NOT_RUNNING,
+ MEMORY_ADDRESS_NOT_FOUND,
+ MEMORY_ADDRESS_COULD_NOT_BE_READ,
+ ATTACHED
}
diff --git a/TrainerCommon/TrainerCommon.csproj b/TrainerCommon/TrainerCommon.csproj
index 50e7a2d..ec073a7 100644
--- a/TrainerCommon/TrainerCommon.csproj
+++ b/TrainerCommon/TrainerCommon.csproj
@@ -22,6 +22,7 @@
prompt
4
latest
+ IDE0055
pdbonly