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

rabi_display
wcko87 8 years ago
parent ae893f02e4
commit 9cc32bcfc5
  1. 66
      rabi_splitter_WPF/MemoryHelper.cs
  2. 70
      rabi_splitter_WPF/MemorySnapshot.cs
  3. 21
      rabi_splitter_WPF/RabiRibiDisplay.cs

@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace rabi_splitter_WPF
{
public static class MemoryHelper
public class MemoryHelper : IDisposable
{
[DllImport("kernel32.dll")]
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;
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;
switch (Type.GetTypeCode(typeof(T)))
@ -30,39 +49,40 @@ namespace rabi_splitter_WPF
case TypeCode.SByte:
datasize = 1;
break;
case TypeCode.Int16:
case TypeCode.UInt16:
datasize = 2;
break;
case TypeCode.Int32:
case TypeCode.Int32:
case TypeCode.Single:
case TypeCode.UInt32:
datasize = 4;
break;
case TypeCode.Double:
case TypeCode.Int64:
case TypeCode.UInt64:
datasize = 8;
break;
default:
throw new Exception("not supported");
}
byte[] buffer = new byte[datasize];
int bytesRead = 0;
IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);
if (baseaddr)
{ ReadProcessMemory((int) processHandle, process.MainModule.BaseAddress.ToInt32() + addr, buffer,
datasize, ref bytesRead);}
{
ReadProcessMemory(processHandleInt, baseAddress + addr, buffer, datasize, ref bytesRead);
}
else
{
ReadProcessMemory((int)processHandle, addr, buffer,
datasize, ref bytesRead);
ReadProcessMemory(processHandleInt, addr, buffer, datasize, ref bytesRead);
}
CloseHandle(processHandle);
switch (Type.GetTypeCode(typeof(T)))
{
@ -98,9 +118,31 @@ namespace rabi_splitter_WPF
default:
throw new Exception("not supported");
}
}
#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
}
}

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

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

Loading…
Cancel
Save