Improve performance by about 5x by not creating a new process handle for every memory read.

This commit is contained in:
wcko87 2017-05-08 06:41:14 +08:00
parent ae893f02e4
commit 9cc32bcfc5
3 changed files with 101 additions and 56 deletions

View File

@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace rabi_splitter_WPF namespace rabi_splitter_WPF
{ {
public static class MemoryHelper public class MemoryHelper : IDisposable
{ {
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
@ -18,7 +18,26 @@ namespace rabi_splitter_WPF
private const int PROCESS_WM_READ = 0x0010; private const int PROCESS_WM_READ = 0x0010;
public static T GetMemoryValue<T>(Process process, int addr,bool baseaddr=true) private readonly IntPtr processHandle;
private readonly int processHandleInt;
private readonly int baseAddress;
public MemoryHelper(Process process)
{
processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);
processHandleInt = (int)processHandle;
baseAddress = process.MainModule.BaseAddress.ToInt32();
}
/*
public static T GetMemoryValue<T>(Process process, int addr, bool baseaddr = true)
{
var memoryHelper = new MemoryHelper(process);
return memoryHelper.GetMemoryValue<T>(addr, baseaddr);
}
*/
public T GetMemoryValue<T>(int addr, bool baseaddr = true)
{ {
int datasize; int datasize;
switch (Type.GetTypeCode(typeof(T))) switch (Type.GetTypeCode(typeof(T)))
@ -30,21 +49,24 @@ namespace rabi_splitter_WPF
case TypeCode.SByte: case TypeCode.SByte:
datasize = 1; datasize = 1;
break; break;
case TypeCode.Int16: case TypeCode.Int16:
case TypeCode.UInt16: case TypeCode.UInt16:
datasize = 2; datasize = 2;
break; break;
case TypeCode.Int32:
case TypeCode.Int32:
case TypeCode.Single: case TypeCode.Single:
case TypeCode.UInt32: case TypeCode.UInt32:
datasize = 4; datasize = 4;
break; break;
case TypeCode.Double: case TypeCode.Double:
case TypeCode.Int64: case TypeCode.Int64:
case TypeCode.UInt64: case TypeCode.UInt64:
datasize = 8; datasize = 8;
break; break;
default: default:
throw new Exception("not supported"); throw new Exception("not supported");
} }
@ -52,17 +74,15 @@ namespace rabi_splitter_WPF
byte[] buffer = new byte[datasize]; byte[] buffer = new byte[datasize];
int bytesRead = 0; int bytesRead = 0;
IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);
if (baseaddr) if (baseaddr)
{ ReadProcessMemory((int) processHandle, process.MainModule.BaseAddress.ToInt32() + addr, buffer, {
datasize, ref bytesRead);} ReadProcessMemory(processHandleInt, baseAddress + addr, buffer, datasize, ref bytesRead);
}
else else
{ {
ReadProcessMemory((int)processHandle, addr, buffer, ReadProcessMemory(processHandleInt, addr, buffer, datasize, ref bytesRead);
datasize, ref bytesRead);
} }
CloseHandle(processHandle);
switch (Type.GetTypeCode(typeof(T))) switch (Type.GetTypeCode(typeof(T)))
{ {
@ -102,5 +122,27 @@ namespace rabi_splitter_WPF
} }
#region IDisposable Support
private bool disposed = false;
protected virtual void DisposeUnmanagedResources()
{
if (disposed) return;
CloseHandle(processHandle);
disposed = true;
}
~MemoryHelper() {
DisposeUnmanagedResources();
}
public void Dispose()
{
DisposeUnmanagedResources();
// GC.SuppressFinalize(this);
}
#endregion
} }
} }

View File

@ -55,44 +55,44 @@ namespace rabi_splitter_WPF
public readonly int minimapPosition; public readonly int minimapPosition;
public MemorySnapshot(Process process, int veridx) public MemorySnapshot(MemoryHelper memoryHelper, int veridx)
{ {
t_playtime = MemoryHelper.GetMemoryValue<int>(process, StaticData.IGTAddr[veridx]); t_playtime = memoryHelper.GetMemoryValue<int>(StaticData.IGTAddr[veridx]);
playtime = MemoryHelper.GetMemoryValue<int>(process, StaticData.PlaytimeAddr[veridx]); playtime = memoryHelper.GetMemoryValue<int>(StaticData.PlaytimeAddr[veridx]);
blackness = MemoryHelper.GetMemoryValue<int>(process, StaticData.BlacknessAddr[veridx]); blackness = memoryHelper.GetMemoryValue<int>(StaticData.BlacknessAddr[veridx]);
mapid = MemoryHelper.GetMemoryValue<int>(process, StaticData.MapAddress[veridx]); mapid = memoryHelper.GetMemoryValue<int>(StaticData.MapAddress[veridx]);
musicid = MemoryHelper.GetMemoryValue<int>(process, StaticData.MusicAddr[veridx]); musicid = memoryHelper.GetMemoryValue<int>(StaticData.MusicAddr[veridx]);
money = MemoryHelper.GetMemoryValue<int>(process, StaticData.MoneyAddress[veridx]); money = memoryHelper.GetMemoryValue<int>(StaticData.MoneyAddress[veridx]);
carrotXp = MemoryHelper.GetMemoryValue<int>(process, 0xD654BC); carrotXp = memoryHelper.GetMemoryValue<int>(0xD654BC);
hammerXp = MemoryHelper.GetMemoryValue<int>(process, 0xD654B4); hammerXp = memoryHelper.GetMemoryValue<int>(0xD654B4);
ribbonXp = MemoryHelper.GetMemoryValue<int>(process, 0xD654B8); ribbonXp = memoryHelper.GetMemoryValue<int>(0xD654B8);
itemPercent = MemoryHelper.GetMemoryValue<float>(process, 0xA730E8); itemPercent = memoryHelper.GetMemoryValue<float>(0xA730E8);
minimapPosition = MemoryHelper.GetMemoryValue<int>(process, 0xA72E08); minimapPosition = memoryHelper.GetMemoryValue<int>(0xA72E08);
nAttackUps = countItems(process, 0xD6352C, 0xD63628); nAttackUps = countItems(memoryHelper, 0xD6352C, 0xD63628);
nHpUps = countItems(process, 0xD6342C, 0xD63528); nHpUps = countItems(memoryHelper, 0xD6342C, 0xD63528);
nManaUps = countItems(process, 0xD6362C, 0xD63728); nManaUps = countItems(memoryHelper, 0xD6362C, 0xD63728);
nPackUps = countItems(process, 0xD6382C, 0xD63928); nPackUps = countItems(memoryHelper, 0xD6382C, 0xD63928);
nRegenUps = countItems(process, 0xD6372C, 0xD63828); nRegenUps = countItems(memoryHelper, 0xD6372C, 0xD63828);
entityArrayPtr = MemoryHelper.GetMemoryValue<int>(process, StaticData.EnenyPtrAddr[veridx]); entityArrayPtr = memoryHelper.GetMemoryValue<int>(StaticData.EnenyPtrAddr[veridx]);
hp = MemoryHelper.GetMemoryValue<int>(process, entityArrayPtr + 0x4D8, false); hp = memoryHelper.GetMemoryValue<int>(entityArrayPtr + 0x4D8, false);
maxhp = MemoryHelper.GetMemoryValue<int>(process, entityArrayPtr + 0x4E8, false); maxhp = memoryHelper.GetMemoryValue<int>(entityArrayPtr + 0x4E8, false);
currentSprite = MemoryHelper.GetMemoryValue<int>(process, entityArrayPtr + 0x654, false); currentSprite = memoryHelper.GetMemoryValue<int>(entityArrayPtr + 0x654, false);
actionFrame = MemoryHelper.GetMemoryValue<int>(process, entityArrayPtr + 0x660, false); actionFrame = memoryHelper.GetMemoryValue<int>(entityArrayPtr + 0x660, false);
amulet = MemoryHelper.GetMemoryValue<float>(process, entityArrayPtr + 0x52C, false); amulet = memoryHelper.GetMemoryValue<float>(entityArrayPtr + 0x52C, false);
boost = MemoryHelper.GetMemoryValue<int>(process, entityArrayPtr + 0x5DC, false); boost = memoryHelper.GetMemoryValue<int>(entityArrayPtr + 0x5DC, false);
mana = MemoryHelper.GetMemoryValue<float>(process, entityArrayPtr + 0x6B8, false); mana = memoryHelper.GetMemoryValue<float>(entityArrayPtr + 0x6B8, false);
stamina = MemoryHelper.GetMemoryValue<int>(process, entityArrayPtr + 0x5B4, false); stamina = memoryHelper.GetMemoryValue<int>(entityArrayPtr + 0x5B4, false);
px = MemoryHelper.GetMemoryValue<float>(process, entityArrayPtr + 0xC, false); px = memoryHelper.GetMemoryValue<float>(entityArrayPtr + 0xC, false);
py = MemoryHelper.GetMemoryValue<float>(process, entityArrayPtr + 0x10, false); py = memoryHelper.GetMemoryValue<float>(entityArrayPtr + 0x10, false);
// Read Entity Array and Search for boss data // Read Entity Array and Search for boss data
@ -103,16 +103,16 @@ namespace rabi_splitter_WPF
int currArrayPtr = entityArrayPtr + entitySize * 4; int currArrayPtr = entityArrayPtr + entitySize * 4;
for (int i=0; i<500; ++i) { for (int i=0; i<500; ++i) {
// (Hard limit of reading 500 entries) // (Hard limit of reading 500 entries)
int entityId = MemoryHelper.GetMemoryValue<int>(process, int entityId = memoryHelper.GetMemoryValue<int>(
currArrayPtr + StaticData.EnenyEnitiyIDOffset[veridx], false); currArrayPtr + StaticData.EnenyEnitiyIDOffset[veridx], false);
int entityMaxHp = MemoryHelper.GetMemoryValue<int>(process, int entityMaxHp = memoryHelper.GetMemoryValue<int>(
currArrayPtr + StaticData.EnenyEnitiyMaxHPOffset[veridx], false); currArrayPtr + StaticData.EnenyEnitiyMaxHPOffset[veridx], false);
if (entityId == 0 && entityMaxHp == 0) break; if (entityId == 0 && entityMaxHp == 0) break;
int activeFlag = MemoryHelper.GetMemoryValue<int>(process, int activeFlag = memoryHelper.GetMemoryValue<int>(
currArrayPtr + StaticData.EnenyEnitiyIsActiveOffset[veridx], false); currArrayPtr + StaticData.EnenyEnitiyIsActiveOffset[veridx], false);
int animationState = MemoryHelper.GetMemoryValue<int>(process, int animationState = memoryHelper.GetMemoryValue<int>(
currArrayPtr + StaticData.EnenyEnitiyAnimationOffset[veridx], false); currArrayPtr + StaticData.EnenyEnitiyAnimationOffset[veridx], false);
bool isAlive = activeFlag == 1 && animationState >= 0; bool isAlive = activeFlag == 1 && animationState >= 0;
@ -122,7 +122,7 @@ namespace rabi_splitter_WPF
BossStats boss; BossStats boss;
boss.entityArrayIndex = entityArraySize; boss.entityArrayIndex = entityArraySize;
boss.id = entityId; boss.id = entityId;
boss.hp = MemoryHelper.GetMemoryValue<int>(process, currArrayPtr + StaticData.EnenyEnitiyHPOffset[veridx], false); boss.hp = memoryHelper.GetMemoryValue<int>(currArrayPtr + StaticData.EnenyEnitiyHPOffset[veridx], false);
boss.type = StaticData.GetBoss(entityId).Value; boss.type = StaticData.GetBoss(entityId).Value;
boss.maxHp = entityMaxHp; boss.maxHp = entityMaxHp;
@ -136,12 +136,12 @@ namespace rabi_splitter_WPF
} }
} }
private int countItems(Process process, int addrFirst, int addrLast) private int countItems(MemoryHelper memoryHelper, int addrFirst, int addrLast)
{ {
int count = 0; int count = 0;
for (int addr = addrFirst; addr <= addrLast; ++addr) for (int addr = addrFirst; addr <= addrLast; ++addr)
{ {
count += MemoryHelper.GetMemoryValue<int>(process, addr) == 1 ? 1 : 0; count += memoryHelper.GetMemoryValue<int>(addr) == 1 ? 1 : 0;
} }
return count; return count;
} }

View File

@ -38,17 +38,20 @@ namespace rabi_splitter_WPF
public void ReadMemory(Process process) public void ReadMemory(Process process)
{ {
++memoryReadCount; ++memoryReadCount;
var memoryHelper = new MemoryHelper(process);
// Snapshot Game Memory // Snapshot Game Memory
snapshot = new MemorySnapshot(process, mainContext.veridx); snapshot = new MemorySnapshot(memoryHelper, mainContext.veridx);
Update(); Update();
UpdateDebugArea(process); UpdateDebugArea(memoryHelper);
UpdateEntityData(process); UpdateEntityData(memoryHelper);
UpdateFps(); UpdateFps();
if (snapshot.musicid >= 0) rabiRibiState.lastValidMusicId = snapshot.musicid; if (snapshot.musicid >= 0) rabiRibiState.lastValidMusicId = snapshot.musicid;
prevSnapshot = snapshot; prevSnapshot = snapshot;
memoryHelper.Dispose();
} }
private void UpdateFps() private void UpdateFps()
@ -284,7 +287,7 @@ namespace rabi_splitter_WPF
return MusicChanged() && snapshot.CurrentMusicIs(music); return MusicChanged() && snapshot.CurrentMusicIs(music);
} }
private void UpdateEntityData(Process process) private void UpdateEntityData(MemoryHelper memoryHelper)
{ {
// Read entire entity data for specific entity // Read entire entity data for specific entity
{ {
@ -300,15 +303,15 @@ namespace rabi_splitter_WPF
for (int i = 0; i < length; i += 4) for (int i = 0; i < length; i += 4)
{ {
int index = i / 4; int index = i / 4;
int value_int = MemoryHelper.GetMemoryValue<int>(process, baseArrayPtr + i, false); int value_int = memoryHelper.GetMemoryValue<int>(baseArrayPtr + i, false);
float value_float = MemoryHelper.GetMemoryValue<float>(process, baseArrayPtr + i, false); float value_float = memoryHelper.GetMemoryValue<float>(baseArrayPtr + i, false);
entityStatsList[index].IntVal = value_int; entityStatsList[index].IntVal = value_int;
entityStatsList[index].FloatVal = value_float; entityStatsList[index].FloatVal = value_float;
} }
} }
} }
private void UpdateDebugArea(Process process) private void UpdateDebugArea(MemoryHelper memoryHelper)
{ {
int ptr = snapshot.entityArrayPtr; int ptr = snapshot.entityArrayPtr;
// List<int> bosses = new List<int>(); // List<int> bosses = new List<int>();
@ -317,9 +320,9 @@ namespace rabi_splitter_WPF
// ptr += StaticData.EnenyEntitySize[mainContext.veridx] * 3; // ptr += StaticData.EnenyEntitySize[mainContext.veridx] * 3;
for (var i = 0; i < 50; i++) for (var i = 0; i < 50; i++)
{ {
debugContext.BossList[i].BossID = MemoryHelper.GetMemoryValue<int>(process, debugContext.BossList[i].BossID = memoryHelper.GetMemoryValue<int>(
ptr + StaticData.EnenyEnitiyIDOffset[mainContext.veridx], false); ptr + StaticData.EnenyEnitiyIDOffset[mainContext.veridx], false);
debugContext.BossList[i].BossHP = MemoryHelper.GetMemoryValue<int>(process, debugContext.BossList[i].BossHP = memoryHelper.GetMemoryValue<int>(
ptr + StaticData.EnenyEnitiyHPOffset[mainContext.veridx], false); ptr + StaticData.EnenyEnitiyHPOffset[mainContext.veridx], false);
ptr += StaticData.EnenyEntitySize[mainContext.veridx]; ptr += StaticData.EnenyEntitySize[mainContext.veridx];
} }