Improve performance by about 5x by not creating a new process handle for every memory read.
This commit is contained in:
parent
ae893f02e4
commit
9cc32bcfc5
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user