-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
569c12b
commit ef82aa7
Showing
15 changed files
with
845 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.30011.22 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SRTPluginProviderRER2", "SRTPluginProviderRER2\SRTPluginProviderRER2.csproj", "{FB803174-8A74-4CC0-8645-B1D6C4F53288}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SRTPluginBase", "..\..\Squirrelies\SRTHost\SRTPluginBase\SRTPluginBase.csproj", "{431972BA-04CE-4D4B-8ECE-80D351B02868}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessMemory", "..\..\Squirrelies\ProcessMemory\ProcessMemory\ProcessMemory.csproj", "{C43019D3-C173-4C82-B8A0-6927CE5FCA38}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|x86 = Debug|x86 | ||
Release|x86 = Release|x86 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{FB803174-8A74-4CC0-8645-B1D6C4F53288}.Debug|x86.ActiveCfg = Debug|x86 | ||
{FB803174-8A74-4CC0-8645-B1D6C4F53288}.Debug|x86.Build.0 = Debug|x86 | ||
{FB803174-8A74-4CC0-8645-B1D6C4F53288}.Release|x86.ActiveCfg = Release|x86 | ||
{FB803174-8A74-4CC0-8645-B1D6C4F53288}.Release|x86.Build.0 = Release|x86 | ||
{431972BA-04CE-4D4B-8ECE-80D351B02868}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
{431972BA-04CE-4D4B-8ECE-80D351B02868}.Debug|x86.Build.0 = Debug|Any CPU | ||
{431972BA-04CE-4D4B-8ECE-80D351B02868}.Release|x86.ActiveCfg = Release|Any CPU | ||
{431972BA-04CE-4D4B-8ECE-80D351B02868}.Release|x86.Build.0 = Release|Any CPU | ||
{C43019D3-C173-4C82-B8A0-6927CE5FCA38}.Debug|x86.ActiveCfg = Debug|x86 | ||
{C43019D3-C173-4C82-B8A0-6927CE5FCA38}.Debug|x86.Build.0 = Debug|x86 | ||
{C43019D3-C173-4C82-B8A0-6927CE5FCA38}.Release|x86.ActiveCfg = Release|x86 | ||
{C43019D3-C173-4C82-B8A0-6927CE5FCA38}.Release|x86.Build.0 = Release|x86 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {9F1CA3A3-4EED-43A9-B230-BC60B2E2ECE9} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
|
||
namespace SRTPluginProviderRER2 | ||
{ | ||
/// <summary> | ||
/// SHA256 hashes for the RE5/BIO5 game executables. | ||
/// </summary> | ||
public static class GameHashes | ||
{ | ||
private static readonly byte[] rerev2ww_20210702_1 = new byte[32] { 0x41, 0xB4, 0x16, 0x96, 0x75, 0x8C, 0x41, 0x77, 0xE9, 0x33, 0x9F, 0x27, 0xF0, 0x51, 0xAA, 0x4D, 0x72, 0x90, 0x8E, 0xD7, 0x26, 0x3A, 0x82, 0xAA, 0x63, 0xB0, 0x93, 0x3A, 0x3B, 0xCA, 0x9C, 0x77 }; | ||
public static GameVersion DetectVersion(string filePath) | ||
{ | ||
byte[] checksum; | ||
using (SHA256 hashFunc = SHA256.Create()) | ||
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) | ||
checksum = hashFunc.ComputeHash(fs); | ||
|
||
if (checksum.SequenceEqual(rerev2ww_20210702_1)) | ||
{ | ||
Console.WriteLine("Steam Version WW Detected"); | ||
return GameVersion.REREV2WW_20210702_1; | ||
} | ||
|
||
Console.WriteLine("Unknown Version"); | ||
return GameVersion.Unknown; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using SRTPluginProviderRER2.Structs.GameStructs; | ||
using System; | ||
using System.Diagnostics; | ||
using System.Globalization; | ||
using System.Reflection; | ||
|
||
namespace SRTPluginProviderRER2 | ||
{ | ||
public class GameMemoryRER2 : IGameMemoryRER2 | ||
{ | ||
private const string IGT_TIMESPAN_STRING_FORMAT = @"hh\:mm\:ss"; | ||
public string GameName => "REREV2"; | ||
|
||
// Versioninfo | ||
public string VersionInfo => FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; | ||
|
||
// BP | ||
public int BP { get => _bp; set => _bp = value; } | ||
internal int _bp; | ||
|
||
// Player 1 Stats | ||
public string PlayerName { get => _playerName; set => _playerName = value; } | ||
internal string _playerName; | ||
public GamePlayer Player { get => _player; set => _player = value; } | ||
internal GamePlayer _player; | ||
public int PlayerInventorySize { get => _playerInventorySize; set => _playerInventorySize = value; } | ||
internal int _playerInventorySize; | ||
public GameInventory[] PlayerInventory { get => _playerInventory; set => _playerInventory = value; } | ||
internal GameInventory[] _playerInventory; | ||
public GameInventory[] PlayerEquipped { get => _playerEquipped; set => _playerEquipped = value; } | ||
internal GameInventory[] _playerEquipped; | ||
|
||
// Player 2 Stats | ||
public string Player2Name { get => _player2Name; set => _player2Name = value; } | ||
internal string _player2Name; | ||
public GamePlayer Player2 { get => _player2; set => _player2 = value; } | ||
internal GamePlayer _player2; | ||
public int Player2InventorySize { get => _player2InventorySize; set => _player2InventorySize = value; } | ||
internal int _player2InventorySize; | ||
public GameInventory[] Player2Inventory { get => _player2Inventory; set => _player2Inventory = value; } | ||
internal GameInventory[] _player2Inventory; | ||
public GameInventory[] Player2Equipped { get => _player2Equipped; set => _player2Equipped = value; } | ||
internal GameInventory[] _player2Equipped; | ||
|
||
public GameEndResults EndResults { get => _endResults; set => _endResults = value; } | ||
internal GameEndResults _endResults; | ||
|
||
public int EnemyCount { get => _enemyCount; set => _enemyCount = value; } | ||
internal int _enemyCount; | ||
public GameEnemy[] EnemyHealth { get => _enemyHealth; set => _enemyHealth = value; } | ||
internal GameEnemy[] _enemyHealth; | ||
|
||
public TimeSpan IGTTimeSpan | ||
{ | ||
get | ||
{ | ||
TimeSpan timespanIGT; | ||
|
||
if (EndResults.ClearTime >= 0f) | ||
timespanIGT = TimeSpan.FromSeconds(EndResults.ClearTime); | ||
else | ||
timespanIGT = new TimeSpan(); | ||
|
||
return timespanIGT; | ||
} | ||
} | ||
|
||
public string IGTFormattedString => IGTTimeSpan.ToString(IGT_TIMESPAN_STRING_FORMAT, CultureInfo.InvariantCulture); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
using ProcessMemory; | ||
using SRTPluginProviderRER2.Structs.GameStructs; | ||
using System; | ||
using System.Diagnostics; | ||
|
||
namespace SRTPluginProviderRER2 | ||
{ | ||
internal unsafe class GameMemoryRER2Scanner : IDisposable | ||
{ | ||
private readonly int MAX_ENTITIES = 16; | ||
private readonly int MAX_ITEMS = 20; | ||
private readonly int MAX_EQUIP = 4; | ||
|
||
// Variables | ||
private ProcessMemoryHandler memoryAccess; | ||
private GameMemoryRER2 gameMemoryValues; | ||
public bool HasScanned; | ||
public bool ProcessRunning => memoryAccess != null && memoryAccess.ProcessRunning; | ||
public int ProcessExitCode => (memoryAccess != null) ? memoryAccess.ProcessExitCode : 0; | ||
|
||
// Pointer Address Variables | ||
private int pointerAddressPlayer; | ||
private int pointerAddressStats; | ||
private int pointerAddressInventory; | ||
private int pointerAddressEnemies; | ||
|
||
// Pointer Classes | ||
private IntPtr BaseAddress { get; set; } | ||
private MultilevelPointer PointerHP { get; set; } | ||
private MultilevelPointer PointerPlayerID { get; set; } | ||
private MultilevelPointer PointerHP2 { get; set; } | ||
private MultilevelPointer PointerPlayer2ID { get; set; } | ||
private MultilevelPointer PointerStats { get; set; } | ||
|
||
private MultilevelPointer PointerInventorySize { get; set; } | ||
private MultilevelPointer PointerInventorySize2 { get; set; } | ||
private MultilevelPointer[] PointerInventory { get; set; } | ||
private MultilevelPointer[] PointerInventory2 { get; set; } | ||
private MultilevelPointer[] PointerEquipped { get; set; } | ||
private MultilevelPointer[] PointerEquipped2 { get; set; } | ||
|
||
private MultilevelPointer PointerEnemyCount { get; set; } | ||
private MultilevelPointer[] PointerEnemyEntires { get; set; } | ||
|
||
internal GameMemoryRER2Scanner(Process process = null) | ||
{ | ||
gameMemoryValues = new GameMemoryRER2(); | ||
if (process != null) | ||
Initialize(process); | ||
} | ||
|
||
internal unsafe void Initialize(Process process) | ||
{ | ||
if (process == null) | ||
return; // Do not continue if this is null. | ||
|
||
GameHashes.DetectVersion(process.MainModule.FileName); | ||
SelectPointerAddresses(); | ||
|
||
int pid = GetProcessId(process).Value; | ||
memoryAccess = new ProcessMemoryHandler(pid); | ||
if (ProcessRunning) | ||
{ | ||
BaseAddress = NativeWrappers.GetProcessBaseAddress(pid, PInvoke.ListModules.LIST_MODULES_32BIT); // Bypass .NET's managed solution for getting this and attempt to get this info ourselves via PInvoke since some users are getting 299 PARTIAL COPY when they seemingly shouldn't. | ||
|
||
//POINTERS | ||
PointerHP = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressPlayer), 0x20); | ||
PointerPlayerID = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressPlayer), 0x20, 0x0, 0x10, 0x1); | ||
PointerHP2 = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressPlayer), 0x24); | ||
PointerPlayer2ID = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressPlayer), 0x24, 0x0, 0x10, 0x1); | ||
PointerStats = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressStats)); | ||
|
||
gameMemoryValues._playerInventory = new GameInventory[MAX_ITEMS]; | ||
gameMemoryValues._player2Inventory = new GameInventory[MAX_ITEMS]; | ||
PointerInventory = new MultilevelPointer[MAX_ITEMS]; | ||
PointerInventory2 = new MultilevelPointer[MAX_ITEMS]; | ||
PointerInventorySize = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressInventory), 0x30, 0x150); | ||
PointerInventorySize2 = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressInventory), 0x30, 0x154); | ||
var position = 0; | ||
for (var i = 0; i < MAX_ITEMS; i++) | ||
{ | ||
position = i * 0x4 + 0xC; | ||
gameMemoryValues._playerInventory[i] = new GameInventory(); | ||
gameMemoryValues._player2Inventory[i] = new GameInventory(); | ||
PointerInventory[i] = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressInventory), 0x30, 0x150, position); | ||
PointerInventory2[i] = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressInventory), 0x30, 0x154, position); | ||
} | ||
|
||
gameMemoryValues._playerEquipped = new GameInventory[MAX_EQUIP]; | ||
gameMemoryValues._player2Equipped = new GameInventory[MAX_EQUIP]; | ||
PointerEquipped = new MultilevelPointer[MAX_EQUIP]; | ||
PointerEquipped2 = new MultilevelPointer[MAX_EQUIP]; | ||
for (var i = 0; i < MAX_EQUIP; i++) | ||
{ | ||
position = i * 0x4 + 0x5C; | ||
gameMemoryValues._playerEquipped[i] = new GameInventory(); | ||
gameMemoryValues._player2Equipped[i] = new GameInventory(); | ||
PointerEquipped[i] = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressInventory), 0x30, 0x150, position); | ||
PointerEquipped2[i] = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressInventory), 0x30, 0x154, position); | ||
} | ||
|
||
gameMemoryValues._enemyHealth = new GameEnemy[MAX_ENTITIES]; | ||
PointerEnemyEntires = new MultilevelPointer[MAX_ENTITIES]; | ||
PointerEnemyCount = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressEnemies), 0x3C, 0x7C); | ||
for (var i = 0; i < MAX_ENTITIES; i++) | ||
{ | ||
position = i * 0x4 + 0x30; | ||
PointerEnemyEntires[i] = new MultilevelPointer(memoryAccess, IntPtr.Add(BaseAddress, pointerAddressEnemies), 0x3C, 0x7C, position); | ||
} | ||
} | ||
} | ||
|
||
private void SelectPointerAddresses() | ||
{ | ||
pointerAddressPlayer = 0x1167EAC; | ||
pointerAddressStats = 0x117D120; | ||
pointerAddressInventory = 0x117D1E8; | ||
pointerAddressEnemies = 0x1161E70; | ||
} | ||
|
||
internal void UpdatePointers() | ||
{ | ||
PointerHP.UpdatePointers(); | ||
PointerPlayerID.UpdatePointers(); | ||
PointerHP2.UpdatePointers(); | ||
PointerPlayer2ID.UpdatePointers(); | ||
PointerStats.UpdatePointers(); | ||
|
||
PointerInventorySize.UpdatePointers(); | ||
PointerInventorySize2.UpdatePointers(); | ||
|
||
// Player Inventories | ||
for (var i = 0; i < MAX_ITEMS; i++) | ||
{ | ||
PointerInventory[i].UpdatePointers(); | ||
PointerInventory2[i].UpdatePointers(); | ||
} | ||
|
||
// Player Equippment | ||
for (var i = 0; i < MAX_EQUIP; i++) | ||
{ | ||
PointerEquipped[i].UpdatePointers(); | ||
PointerEquipped2[i].UpdatePointers(); | ||
} | ||
|
||
PointerEnemyCount.UpdatePointers(); | ||
for (var i = 0; i < MAX_ENTITIES; i++) | ||
{ | ||
PointerEnemyEntires[i].UpdatePointers(); | ||
} | ||
} | ||
|
||
internal unsafe IGameMemoryRER2 Refresh() | ||
{ | ||
// | ||
gameMemoryValues._bp = PointerStats.DerefInt(0xE88); | ||
|
||
// Player 1 | ||
gameMemoryValues._player = PointerHP.Deref<GamePlayer>(0x1A00); | ||
gameMemoryValues._playerName = PointerPlayerID.Deref<GamePlayerID>(0x1C).Name; | ||
|
||
// Player 2 | ||
gameMemoryValues._player2 = PointerHP2.Deref<GamePlayer>(0x1A00); | ||
gameMemoryValues._player2Name = PointerPlayer2ID.Deref<GamePlayerID>(0x1C).Name; | ||
|
||
// Game Statistics | ||
gameMemoryValues._endResults = PointerStats.Deref<GameEndResults>(0x1403F0); | ||
|
||
// Player Inventories | ||
gameMemoryValues._playerInventorySize = PointerInventorySize.DerefInt(0x8); | ||
gameMemoryValues._player2InventorySize = PointerInventorySize2.DerefInt(0x8); | ||
|
||
for (var i = 0; i < MAX_ITEMS; i++) | ||
{ | ||
gameMemoryValues._playerInventory[i] = PointerInventory[i].Deref<GameInventory>(0x0); | ||
gameMemoryValues._player2Inventory[i] = PointerInventory2[i].Deref<GameInventory>(0x0); | ||
} | ||
|
||
// Player Equippment | ||
for (var i = 0; i < MAX_EQUIP; i++) | ||
{ | ||
gameMemoryValues._playerEquipped[i] = PointerEquipped[i].Deref<GameInventory>(0x0); | ||
gameMemoryValues._player2Equipped[i] = PointerEquipped2[i].Deref<GameInventory>(0x0); | ||
} | ||
|
||
gameMemoryValues._enemyCount = PointerEnemyCount.DerefInt(0x2C); | ||
for (var i = 0; i < MAX_ENTITIES; i++) | ||
{ | ||
gameMemoryValues._enemyHealth[i] = PointerEnemyEntires[i].Deref<GameEnemy>(0x1A00); | ||
} | ||
|
||
HasScanned = true; | ||
return gameMemoryValues; | ||
} | ||
|
||
private int? GetProcessId(Process process) => process?.Id; | ||
|
||
#region IDisposable Support | ||
private bool disposedValue = false; // To detect redundant calls | ||
|
||
protected virtual void Dispose(bool disposing) | ||
{ | ||
if (!disposedValue) | ||
{ | ||
if (disposing) | ||
{ | ||
// TODO: dispose managed state (managed objects). | ||
if (memoryAccess != null) | ||
memoryAccess.Dispose(); | ||
} | ||
|
||
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. | ||
// TODO: set large fields to null. | ||
|
||
disposedValue = true; | ||
} | ||
} | ||
|
||
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. | ||
// ~REmake1Memory() { | ||
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above. | ||
// Dispose(false); | ||
// } | ||
|
||
// This code added to correctly implement the disposable pattern. | ||
public void Dispose() | ||
{ | ||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above. | ||
Dispose(true); | ||
// TODO: uncomment the following line if the finalizer is overridden above. | ||
// GC.SuppressFinalize(this); | ||
} | ||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace SRTPluginProviderRER2 | ||
{ | ||
public enum GameVersion : int | ||
{ | ||
Unknown, | ||
REREV2WW_20210702_1 | ||
} | ||
} |
Oops, something went wrong.