Memory address value to GUI for flightsim gauge

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Memory address value to GUI for flightsim gauge

10 Mar 2019, 10:57

Hello everyone,
I'd like to build a gui as gauge on top of my flight simulator of choice (let's call it MySim.exe). Think head-up display.

As proof of concept I'd do a turn indicator:

The source value
- I've hunted down the value of interest using Cheat Engine
- The value is stored as "double value" in the first two "??" of following array of byte (AoB): ?? ?? ?? ?? ?? ?? ?? ?? ?? 31 BD 41 3A 3A C1 3F 28 F3 7B 62 4A 22 D5 BF
- I don't have a pointer, just the AoB shown above
- The value is <0 when turning left and >0 when turning right

What the script should do:
- Grab the value 10-30 times per second
- Convert the value to decimal format
- Round the value to 2 decimals
- Feed the value into one or two gui(s) that display(s) a bar. If the value is 0.00 +/- a tolerance interval of 0.1 no bar should be visible. If the value is positive, the bar should "grow" to the right depending on the value (cutoff at +10.00). If the value is negative, a bar should grow to the left (cutoff value at -10.00)

Any help with this would be greatly appreciated. The AoB part gives me the greatest headache, since I've never used AHK to read memory values.
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

11 Mar 2019, 15:28

I've found a basic script to search for the AoB first and gave it a try. It includes RHCPs classMemory script found here: https://github.com/Kalamity/classMemory/blob/master/classMemory.ahk

It gives me following error: The program isn't running (not found) or you passed an incorrect program identifier parameter.

Here's the script I tried:
======================================================================================================================================
#include classMemory.ahk

if (_ClassMemory.__Class != "_ClassMemory")
{
msgbox class memory not correctly installed.
ExitApp
}

WinGet, PID, PID, Chara1

mem := new _ClassMemory("ahk_pid " PID, "", hProcess) ; note tha quotes and space around AHK_Pid

if !IsObject(mem)
{
if (hProcess = "")
msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. Consult A_LastError for more information.
else msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter.
ExitApp
}

; I just put the pattern in an array so that it's a bit neater with 2 function calls
aPattern := ["?", "?", "?", "?", "?", "?", "?", "?", "?", 0xA6, 0x7E, 0x0B, 0x97, 0x75, 0xC2, 0x3F, 0x1E, 0x08, 0x33, 0x64, 0x2D, 0xA2, 0xD8, 0xBF]
address := mem.processPatternScan(,, aPattern*)
if address > 0
msgbox % "Found Pattern at: " address
else msgbox Pattern not found or error: %address%

address := mem.modulePatternScan(, aPattern*) ; assume its in the main process module. This will probably be quicker.
if address > 0
msgbox % "Found Pattern at: " address
else msgbox Pattern not found or error: %address%


return
======================================================================================================================================
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Memory address value to GUI for flightsim gauge

11 Mar 2019, 15:43

Try using " _ClassMemory.setSeDebugPrivilege()" before calling new.

E.g

Code: Select all

#include classMemory.ahk

if !A_IsAdmin
{
	Run *RunAs "%A_ScriptFullPath%"
	ExitApp
}

if (_ClassMemory.__Class != "_ClassMemory")
{
	msgbox class memory not correctly installed.
	ExitApp
}

 _ClassMemory.setSeDebugPrivilege()

WinGet, PID, PID, Chara1
if !PID
{
	msgbox winget failed to find pid 
	ExitApp
}


mem := new _ClassMemory("ahk_pid " PID, "", hProcess) 
if !IsObject(mem)
{
	if (hProcess = "")
		msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. Consult A_LastError for more information.
	else msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter.

	msgbox A_LastError %A_LastError%
	ExitApp
}

msgbox successful
return
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

11 Mar 2019, 15:59

I had the wrong process. I've SetTitleMatchMode to 2 and now it finds the process and the AoB.

The next step is to extract numeric data from the first 8 "?" if the AoB... And feed it into a gui.

Does anyone have an idea how to best achieve this?
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

12 Mar 2019, 15:25

I placed evan's ReadMemory.ahk library in C:\Program Files\AutoHotkey\lib (https://autohotkey.com/board/topic/33888-readmemory-function/)
===============================
ReadMemory(MADDRESS,PROGRAM)
{
winget, pid, PID, %PROGRAM%

VarSetCapacity(MVALUE,4,0)
ProcessHandle := DllCall("OpenProcess", "Int", 24, "Char", 0, "UInt", pid, "UInt")
DllCall("ReadProcessMemory","UInt",ProcessHandle,"UInt",MADDRESS,"Str",MVALUE,"UInt",4,"UInt *",0)

Loop 4
result += *(&MVALUE + A_Index-1) << 8*(A_Index-1)

return, result
}
===============================
Next, I tried to read the value using following script:
************************************************
SetFormat, IntegerFast, Hex

f1::
value := ReadMemory(0xA7868EDDE0, MySim.exe)
MsgBox, %value%
return
********************************************

I found the AoB, paused the game and looked at the memory address (A7868EDDE0) and it's value in Cheat Engine.
Cheat Engine info:
Address: A7868EDDE0
Value: 2D A7 4E D6 A7 68 22 40 as hex, 9.20 as double precision float.
If I convert the hex value to 40 22 68 A7 D6 4E A7 2D and feed it into a converter I get 9.204405495740128 in double precision float.

However, the script I use to read the value gives me 0x0. If I remove the SetFormat line I get a value of 0.

What am I doing wrong?
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Memory address value to GUI for flightsim gauge

12 Mar 2019, 22:02

It's because you're trying to read a double (8 bytes) and that function reads 4 bytes from memory.

Try something like:
address := mem.modulePatternScan(, aPattern*)
msgbox % value := mem.read(address, "Double")
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

13 Mar 2019, 11:44

Thanks a lot, will try that as soon as I find some time!
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

15 Mar 2019, 02:00

RHCP wrote:
12 Mar 2019, 22:02
It's because you're trying to read a double (8 bytes) and that function reads 4 bytes from memory.

Try something like:
address := mem.modulePatternScan(, aPattern*)
msgbox % value := mem.read(address, "Double")
Awesome, that worked! Many thanks!

I defined following variable
TurnInd := mem.read(address, "Double")
and placed it within a loop with 100 ms sleep and a tooltip. It updates nicely.
Now I'm reading up on how to best feed TurnInd into two progress bars: one should progress to the left, be red, and have a range of -0.25 to -10. The second bar should progress to the right, be green and have a range of 0.25 to 10. If TurnInd is between -0.25 and 0.25 no gui should be visible.
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

19 Mar 2019, 15:13

Awesome, it works just as planned! Many thanks RHCP, you da man!
I still have two questions:

1) Do you see a way to improve the script? Is there some weak spot that makes it slow or makes it use lots of CPU power?
2) The progress bar moves is steps of 1.0. Is there a way to make it reflect the true values of the variable more accurately?

Here's the current script:
==================================================================================
#include classMemory.ahk
SetTitleMatchMode, 2
SetTimer, TurnIndicator, 33

if (_ClassMemory.__Class != "_ClassMemory")
{
msgbox class memory not correctly installed.
ExitApp
}

WinGet, PID, PID, MySim

mem := new _ClassMemory("ahk_pid " PID, "", hProcess) ; note tha quotes and space around AHK_Pid

if !IsObject(mem)
{
if (hProcess = "")
msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. Consult A_LastError for more information.
else msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter.
ExitApp
}

aPattern := ["?", "?", "?", "?", "?", "?", "?", "?", "?", 0xA6, 0x7E, 0x0B, 0x97, 0x75, 0xC2, 0x3F, 0x1E, 0x08, 0x33, 0x64, 0x2D, 0xA2, 0xD8, 0xBF]
address := mem.processPatternScan(,, aPattern*)

if address > 0
{
Gui, 1: Margin, 0, 0
Gui, 1: -Caption +ToolWindow ;-- no title, no taskbar icon
Gui, 1: Add,Progress, vTurnInd x-2 y-2 w150 h30 BackgroundBlack cGreen Range0-10, 0 ;Default range is 0 to 100
Gui, 1: +alwaysOnTop
Gui, 1: Show, x1280 y1350 NoActivate ; w150 h20, TurnInd, NoActivate

Gui, 2: Margin, 0, 0
Gui, 2: -Caption +ToolWindow ;-- no title, no taskbar icon
Gui, 2: Add,Progress, vTurnInd x-2 y-2 w150 h30 BackgroundRed cBlack Range-10-0, 0 ;Default range is 0 to 100
Gui, 2: +alwaysOnTop
Gui, 2: Show, x1090 y1350 NoActivate ; w150 h20, TurnInd, NoActivate
GoSub, TurnIndicator
}
else msgbox Pattern not found or error: %address%
return

TurnIndicator:
TurnInd := mem.read(address, "Double")
ToolTip, %TurnInd%
GuiControl 1: , TurnInd, %TurnInd% ;-- Update progress bar
GuiControl 2: , TurnInd, %TurnInd% ;-- Update progress bar
return

+Enter::Reload

+Esc::ExitApp
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

26 Mar 2019, 12:40

I found no way to make the bars progress in steps of 0.01 instead of 1, so I multiplied the TurnInd variable with 100 and adapted the progress bar range:

TurnIndicator:
TurnInd := (mem.read(address, "Double")*100)
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

27 Mar 2019, 04:43

I'm now working on a g meter that shows an overlay with numeric data rounded to one decimal just like in fighterplanes (e.g. 7.3 g). AoBs are inconvenient for this one, because they are very long and the address changes with every flight. Luckily I have good pointers:
gIndPointers.jpg
(51.93 KiB) Downloaded 39 times
I merged RHCPs base address script (https://autohotkey.com/board/topic/148210-need-help-to-read-multi-lvl-pointers/) with my Gui overlay script in AHK 1.1.27.00 64bit.

I only get the correct value when directing the mem.read to the currently valid dynamic address. Both msgbox % "base address methods seem to display the wrong base. The issues are marked in red in the following script.
As always, any help is much appreciated!

********************************************************************************************************
#include classMemory.ahk ; includes classMemory library found under ahk/libs
SetTitleMatchMode, 2
SetTimer, Update_gIndicator, 33 ; Gui updater

; Gui colors ==========================================================
Custom_C = EEAA99 ; Can be any RGB color.
Custom_W = 300
Custom_H = 20

; Read base address ===================================================
if (_ClassMemory.__Class != "_ClassMemory")
{
msgbox class memory not correctly installed.
ExitApp
}

WinGet, PID, PID, MySim

mem := new _ClassMemory("ahk_pid " PID, "", hProcess) ; note tha quotes and space around AHK_Pid

if !IsObject(mem)
{
if (hProcess = "")
msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. Consult A_LastError for more information.
else msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter.
ExitApp
}

; the mem object can now be used to read/write data
msgbox % "base address: " mem.BaseAddress
. "`nBase address method2: " mem.getModuleBaseAddress() ; both methods return 140697963397120 as base address, which I think equals 7FF6CC210000 in hex. CE shows 0004F318 as base.


; Gui specs ==========================================================
Gui, +LastFound +AlwaysOnTop -Caption +ToolWindow
Gui, Color, %Custom_C%
Gui, Font, s16 ; Set a large font size (12-point).
Gui, Add, Text, vgInd cLime, xxxxxxxxxxxxxxxxx, y ; xs and ys serve to autosize window
WinSet, TransColor, %Custom_C% 200 ; Make Custom_C color invisible & Text translucent (150)

Gosub, Update_gIndicator ; Run first update immediately instead of waiting for the timer
Gui, Show, x800 y600 NoActivate

; Gui upadter ========================================================
Update_gIndicator:
;gInd := mem.read(0x1F1F4884180, "Double") ; Debugging; this is the final dynamic address; feeds the rounded correct value into the Gui
gInd := mem.read(mem.BaseAddress + 0x0004F318, "Double", 0x8, 0x630, 0x7D8, 0x18, 0x688) ; These are the base address and offsets as displayed in CE. Displays the wrong value (0).

GuiControl 1: , gInd, %gInd% ;-- Updates Gui
return

+Enter::Reload

+Esc::ExitApp
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Memory address value to GUI for flightsim gauge

27 Mar 2019, 06:43

You need to find the address of "sceneman.dll", not the process for that pointer i.e.

Code: Select all

msgbox % "base address: " mem.BaseAddress
. "`nModleaddress: " mem.getModuleBaseAddress("sceneman.dll") 
gInd := mem.read(mem.getModuleBaseAddress("sceneman.dll")  + 0x0004F318, "Double", 0x8, 0x630, 0x7D8, 0x18, 0x688)
Trisolaris
Posts: 79
Joined: 10 Mar 2019, 10:28

Re: Memory address value to GUI for flightsim gauge

27 Mar 2019, 17:38

RHCP wrote:
27 Mar 2019, 06:43
You need to find the address of "sceneman.dll", not the process for that pointer i.e.

Code: Select all

msgbox % "base address: " mem.BaseAddress
. "`nModleaddress: " mem.getModuleBaseAddress("sceneman.dll") 
gInd := mem.read(mem.getModuleBaseAddress("sceneman.dll")  + 0x0004F318, "Double", 0x8, 0x630, 0x7D8, 0x18, 0x688)
I just tried it and it works like a charm! Thanks! :dance:
Let's see:
sideslip indicator....check!
g meter...............check!

This is so much fun I think I'll try an angle of attack (AoA) indicator next. With a g meter and an AoA indicator in place I'd be able to perform very informative flight tests, e.g. to determine the turn rate vs. angle of attack and find the sweet spot for turn performance.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Billykid and 211 guests