 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
AylinCE Grandmaster Cheater Supreme
Reputation: 37
Joined: 16 Feb 2017 Posts: 1543
|
Posted: Wed Jan 14, 2026 4:06 pm Post subject: [Lua Tool] Pointer Path Parser and Address List Insertion V3 |
|
|
Overview: This Lua-based utility for Cheat Engine simplifies the process of handling complex pointer paths.
It allows users to parse string-representation pointers (e.g., [[base+offset]+offset]) or resolve existing entries from the Address List into a clean, editable format.
Key Features:
Smart Parsing: Automatically extracts base addresses and offsets from standard pointer notation.
Address List Integration: Accepts an Index number from your current Address List to reverse-engineer and display its pointer path.
One-Click Creator: Quickly adds the parsed result back to the Address List with a custom description.
High-DPI Support: Fully scaled UI using getScreenDPI to ensure clarity on 4K and high-resolution monitors.
Live Value Watcher: Real-time monitoring of the resolved address, displaying 4-Byte, Float, and Hexadecimal values simultaneously to help identify data types.
Workflow Optimized: Includes custom hotkeys (e.g., CTRL for instant clipboard paste and ENTER for parsing) and a frameless, draggable modern UI.
How to Use:
Paste your pointer path or enter the Index of an address list entry into the Input box.
Click PARSE (or press Enter).
Review the live value in the watcher panel to verify the pointer is valid.
Click ADD TO ADDRESS LIST to save it permanently.
Major Update: Smart Interaction & Workflow!
Context-Aware Shortcuts:
Since the form is transparent, I've mapped shortcuts directly to the Input fields.
Use CTRL+S to Save New and CTRL+U to Update an existing record.
Status Bar: The Value label now doubles as a status display, letting you know when a record is successfully updated or added.
Manual Update: If you click UPDATE without parsing an index first, the tool will now intelligently ask you which Index # you'd like to overwrite.
Clean UI: No more accidental clipboard spamming! Standard Windows keys (CTRL+V, CTRL+A) are back to normal.
------------------------- V3 ---------------------------
What's New in V2 to V3 Update?
In this version, we have moved from simple string manipulation to a "Validation-First" architecture, ensuring that the Address List remains clean and stable even with complex or manual inputs.
Heuristic Base Address Resolution:
Implemented a logic that treats 'Module + First Offset' as a single Base unit when a module extension (.exe/.dll) is detected, solving the ambiguity in plain text strings.
Real-time Output Synchronization:
The Add and Edit buttons now prioritize the OutputEdit field. This allows users to manually refine the pointer path before committing it to the Address List.
Hex Integrity Validation: Added a strict verification step using Regex patterns to ensure only valid Hexadecimal characters (0-9, A-F) are processed.
Process Abort on Error:
If an invalid character (like 'S' instead of '5') is detected within an offset, the script now aborts the operation and notifies the user via a MessageDialog, preventing "Ghost 0" or empty offsets in your table.
Enhanced Stability for Plain Text:
Fixed the "Double Bracket" bug in the Parse logic, ensuring that plain strings like base+off1+off2 are correctly wrapped into nested [[base]+off1]+off2 formats.
Full English Documentation:
All core logic and internal functions are now documented with English comments for better community support and clarity.
--------------------------------------------------------------------------
Optional Parse Format:
From this:
[[[executable.exe+00A1B2C3]+10D25C]+20]+30
To this:
executable.exe+00A1B2C3+10D25C+20+30
Or from this:
executable.exe+00A1B2C3+10D25C+20+30
To this:
[[[executable.exe+00A1B2C3]+10D25C]+20]+30
--------------------------------------------------------------------------
| Code: | if parserForm then parserForm.Destroy() parserForm=nil end
DP1=getScreenDPI()/96
parserForm=createForm()
parserForm.height=290*DP1 parserForm.width=420*DP1
parserForm.PopupMode=0 parserForm.caption="Pointer Parser & Creator"
parserForm.Position="poDesktopCenter" parserForm.ShowInTaskBar="stAlways"
parserForm.BorderStyle="bsNone" parserForm.Font.Size=12*DP1
parserForm.setLayeredAttributes(0x000100, 255, LWA_COLORKEY | LWA_ALPHA )
parserForm.Color=0x000100 parserForm.Font.Style="fsBold"
-------------------------
local prs = {}
----------------------- prs.prsTitle -----
prs.prsTitle=createPanel(parserForm)
prs.prsTitle.AutoSize=false
prs.prsTitle.height=40*DP1 prs.prsTitle.width=400*DP1 prs.prsTitle.left=10*DP1 prs.prsTitle.top=5*DP1
prs.prsTitle.caption="Pointer Parser & Creator V3" prs.prsTitle.BevelWidth=4
prs.prsTitle.Color=0x878787 prs.prsTitle.Font.Size=14*DP1
prs.prsTitle.OnMouseDown=function() parserForm.DragNow() end
-----------------------
----------------------- prs.prsPnl1 -----
prs.prsPnl1=createPanel(parserForm)
prs.prsPnl1.AutoSize=false
prs.prsPnl1.height=235*DP1 prs.prsPnl1.width=400*DP1 prs.prsPnl1.left=10*DP1 prs.prsPnl1.top=48*DP1
prs.prsPnl1.caption="" prs.prsPnl1.Color=0x878787 prs.prsPnl1.BevelWidth=4
-----------------------
----------------------- prs.lblInput -----
prs.lblInput=createLabel(prs.prsPnl1)
prs.lblInput.AutoSize=false
prs.lblInput.height=21*DP1 prs.lblInput.width=380*DP1 prs.lblInput.left=10*DP1 prs.lblInput.top=5*DP1
prs.lblInput.caption="Input (Pointer Path or Address List Index):"
prs.lblInput.alignment="taCenter" prs.lblInput.Font.Color=0xFDFDFD
-----------------------
----------------------- prs.inputEdit -----
prs.inputEdit=createEdit(prs.prsPnl1)
prs.inputEdit.AutoSize=false
prs.inputEdit.height=27*DP1 prs.inputEdit.width=380*DP1 prs.inputEdit.left=10*DP1 prs.inputEdit.top=30*DP1
prs.inputEdit.text="" prs.inputEdit.Color=0xBDBDBD
-----------------------
----------------------- prs.btnParse -----
prs.btnParse=createButton(prs.prsPnl1)
prs.btnParse.AutoSize=false
prs.btnParse.height=27*DP1 prs.btnParse.width=380*DP1 prs.btnParse.left=10*DP1 prs.btnParse.top=62*DP1
prs.btnParse.caption="PARSE" prs.btnParse.Font.Size=12*DP1
-----------------------
----------------------- prs.lblOutput -----
prs.lblOutput=createLabel(prs.prsPnl1)
prs.lblOutput.AutoSize=false
prs.lblOutput.height=21*DP1 prs.lblOutput.width=380*DP1 prs.lblOutput.left=10*DP1 prs.lblOutput.top=85*DP1
prs.lblOutput.caption="Formatted Output (Address+Offsets):"
prs.lblOutput.alignment="taCenter" prs.lblOutput.Font.Color=0xFDFDFD
-----------------------
----------------------- prs.outputEdit -----
prs.outputEdit=createEdit(prs.prsPnl1)
prs.outputEdit.AutoSize=false
prs.outputEdit.height=27*DP1 prs.outputEdit.width=380*DP1 prs.outputEdit.left=10*DP1 prs.outputEdit.top=107*DP1
prs.outputEdit.text="" prs.outputEdit.Color=0xBDBDBD
-----------------------
----------------------- prs.btnAdd -----
prs.btnAdd=createButton(prs.prsPnl1)
prs.btnAdd.AutoSize=false
prs.btnAdd.height=27*DP1 prs.btnAdd.width=185*DP1 prs.btnAdd.left=10*DP1 prs.btnAdd.top=137*DP1
prs.btnAdd.caption="ADD NEW ADDRESS" prs.btnAdd.Font.Size=10*DP1
-----------------------
----------------------- prs.btnAdd -----
prs.btnEdt=createButton(prs.prsPnl1)
prs.btnEdt.AutoSize=false
prs.btnEdt.height=27*DP1 prs.btnEdt.width=185*DP1 prs.btnEdt.left=205*DP1 prs.btnEdt.top=137*DP1
prs.btnEdt.caption="UPDATE" prs.btnEdt.Font.Size=10*DP1
-----------------------
----------------------- prs.lblOutput -----
prs.lblValue=createLabel(prs.prsPnl1)
prs.lblValue.AutoSize=false
prs.lblValue.height=70*DP1 prs.lblValue.width=380*DP1 prs.lblValue.left=10*DP1 prs.lblValue.top=165*DP1
prs.lblValue.Font.Size=12 prs.lblValue.OptimalFill=true prs.lblValue.Caption = "\nReady...\n"
prs.lblValue.Font.Color=0xFDFDFD
-----------------------
----------------------- prs.btnAdd -----
prs.btnCls=createButton(prs.prsTitle)
prs.btnCls.AutoSize=false
prs.btnCls.height=26*DP1 prs.btnCls.width=30*DP1
prs.btnCls.left, prs.btnCls.top= prs.prsTitle.Width - 40*DP1, 7*DP1
prs.btnCls.caption="X" prs.btnCls.Font.Size=14*DP1
-----------------------
prs.btnCls.OnClick=function() parserForm.Close() end
--############################################################################--
-- Global variables for state tracking
local editingIndex = nil
local originalDesc = ""
local parts = {} -- Shared table for all buttons
-- #################### CORE LOGIC FUNCTIONS #################### --
--- Splits the input string into a Base Address and a list of Offsets.
-- Handles both bracketed [base+off]+off and plain base+off+off formats.
function getSmartParts(text)
parts = {} -- Reset global table to prevent data accumulation
local input = text:gsub("%s+", "") -- Remove all spaces
-- CASE 1: Input contains brackets (e.g., [[base+off]+off])
-- We extract the innermost content as the Base Address.
if input:find("%[") and input:find("%]") then
local innerBase = input:match("%[+([^%]]+)%]")
if innerBase then
table.insert(parts, innerBase)
-- Collect remaining offsets outside the last bracket
local remainder = input:match("%](.+)$")
if remainder then
for off in remainder:gmatch("%+([%x%d%a]+)") do
table.insert(parts, off)
end
end
end
else
-- CASE 2: Plain text (e.g., executable.exe+00A1B2C3+10D2SC+20+30)
-- This is the "Ambiguity" DarkByte mentioned. We use our logic to solve it.
local temp = {}
input = text:gsub("%]+", ""):gsub("%[+", "")
for p in input:gmatch("[^%+]+") do table.insert(temp, p) end
if #temp > 0 then
-- LOGIC: If the 1st part is a module (.exe) or the 2nd part is a long Hex,
-- we marry them as a single Base Address.
if #temp >= 2 and (temp[1]:find("%.") or #temp[2] > 5) then
table.insert(parts, temp[1] .. "+" .. temp[2]) -- The "Static Base"
for i = 3, #temp do table.insert(parts, temp[i]) end -- The rest are Offsets
else
-- If no module is detected, only the 1st part is the Base
table.insert(parts, temp[1])
for i = 2, #temp do table.insert(temp, p) table.insert(parts, temp[i]) end
end
end
end
return parts
end
-- Logic: Parse Action (Converts between Plain, Bracketed, and Address List Index)
prs.btnParse.onClick = function()
local input = prs.inputEdit.Text:gsub("%s+", "")
if input == "" then return end
parts = {}
local baseAddr = ""
local offsets = {}
-- NEW: Check if input is a numeric Index (Address List Reference)
local index = tonumber(input)
if index then
local al = getAddressList()
local memRec = al[index]
if memRec then
baseAddr = memRec.Address
for i=0, memRec.OffsetCount-1 do
table.insert(offsets, string.format("%X", memRec.Offset[i]))
end
-- Reverse offsets back to standard notation
local revOffsets = {}
for i=#offsets, 1, -1 do table.insert(revOffsets, offsets[i]) end
offsets = revOffsets
--end -- Join Address and Offsets
local result = baseAddr
for _, off in ipairs(offsets) do
result = result .. "+" .. off
end
prs.outputEdit.Text = result
getSmartParts(input)
prs.lblValue.Caption = "Fetched from Index #" .. index
else
showMessage("Index #" .. indexInput .. " not found in Address List!")
return
end
else
getSmartParts(input)
-- REVERSE MODE: Convert plain text -> [[base]+off]
if not input:find("%[") and not input:find("%]") and input:find("%+") then
local res = parts[1]
for i = 2, #parts do
res = "[" .. res .. "]+" .. parts[i]
end
prs.outputEdit.Text = res
else
-- STANDARD MODE: Convert bracketed -> plain text (base+off+off)
local res = parts[1]
for i = 2, #parts do res = res .. "+" .. parts[i] end
prs.outputEdit.Text = res
end
prs.outputEdit.SetFocus()
prs.lblValue.Caption = "Parsed successfully."
end
end
-- Global logic: Validate hex strings before applying
function isValidHex(s)
return s:match("^[0-9A-Fa-f]+$") ~= nil
end
-- Logic: ADD NEW RECORD (with full validation)
prs.btnAdd.onClick = function()
local currentText = prs.outputEdit.Text:gsub("%s+", "")
if currentText == "" then
showMessage("Output is empty! Please parse an address first.")
return
end
-- Re-parse to ensure the latest manual edits are captured
local currentParts = getSmartParts(currentText)
-- VALIDATION STEP
if #currentParts > 1 then
for i = 2, #currentParts do
if not isValidHex(currentParts[i]) then
showMessage("Error: Invalid Offset found: '" .. currentParts[i] .. "'\nPlease correct it before adding.")
return -- Stop the process!
end
end
end
-- Process creation only if validated
local moduleName = currentParts[1]:match("^([^%+%.]+)") or "Ptr"
local autoName = "Ptr_" .. moduleName .. "_" .. (currentParts[#currentParts] or "base")
local desc = inputQuery("New Record", "Description:", autoName)
if not desc or desc == "" then desc = autoName end
local al = getAddressList()
local mr = al.createMemoryRecord()
mr.Description = desc
mr.Address = currentParts[1]
if #currentParts > 1 then
mr.OffsetCount = #currentParts - 1
for i = 0, mr.OffsetCount - 1 do
mr.Offset[i] = tonumber(currentParts[#currentParts - i], 16)
end
end
prs.lblValue.Caption = "Successfully added: " .. desc
end
-- Logic: UPDATE RECORD (with full validation)
prs.btnEdt.onClick = function()
local currentText = prs.outputEdit.Text:gsub("%s+", "")
if currentText == "" then return end
local currentParts = getSmartParts(currentText)
-- VALIDATION STEP
if #currentParts > 1 then
for i = 2, #currentParts do
if not isValidHex(currentParts[i]) then
showMessage("Error: Invalid Offset: '" .. currentParts[i] .. "'\nUpdate cancelled.")
return -- Abort!
end
end
end
local al = getAddressList()
local targetIndex = editingIndex or tonumber(inputQuery("Update", "Index #:", ""))
if targetIndex and al[targetIndex] then
local mr = al[targetIndex]
mr.Address = currentParts[1]
if #currentParts > 1 then
mr.OffsetCount = #currentParts - 1
for i = 0, mr.OffsetCount - 1 do
mr.Offset[i] = tonumber(currentParts[#currentParts - i], 16)
end
else
mr.OffsetCount = 0
end
prs.lblValue.Caption = "Record #" .. targetIndex .. " updated successfully."
else
showMessage("Invalid Index or record not found!")
end
end
-- Helper: UI Reset on Input Clear
prs.inputEdit.OnChange = function()
if prs.inputEdit.Text == "" then
prs.outputEdit.Text = ""
prs.lblValue.Caption = "\nReady...\n"
end
end
-- Live Value Watcher Logic
prs.outputEdit.OnChange = function()
local addrText = prs.outputEdit.Text
if addrText == "" or addrText:find("Unknown") then
prs.lblValue.Caption = "\nValue: ???\n"
return
end
local actualAddr = getAddressSafe(addrText)
if actualAddr and actualAddr ~= 0 then
local v4b = readInteger(actualAddr) or 0
local vfl = readFloat(actualAddr) or 0
prs.lblValue.Caption = string.format("4-Byte: %d ... Float: %.2f \nHex: %X", v4b, vfl, v4b)
else
prs.lblValue.Caption = "Value: ???\n"
end
end
-- Keyboard Shortcut Management
RealOnKeyDown = function(sender, key)
local ctrl = isKeyPressed(VK_CONTROL)
if ctrl and key == VK_S then prs.btnAdd.doClick() return 1 end
if ctrl and key == VK_U then prs.btnEdt.doClick() return 1 end
if key == VK_ESCAPE then parserForm.close() end
end
prs.inputEdit.OnKeyDown = function(sender, key)
if key == 13 and not isKeyPressed(VK_CONTROL) then prs.btnParse.doClick()
else RealOnKeyDown(sender, key) end
end
prs.outputEdit.OnKeyDown = RealOnKeyDown
|
Enjoy it!
_________________
Last edited by AylinCE on Thu Jan 15, 2026 8:38 pm; edited 4 times in total |
|
| Back to top |
|
 |
cancandodo Advanced Cheater
Reputation: 0
Joined: 09 Mar 2012 Posts: 75
|
Posted: Wed Jan 14, 2026 6:40 pm Post subject: |
|
|
tks,it work correct
bug just trans one address one time
and need to type desciption manual
may be i should ues autohotkey
|
|
| Back to top |
|
 |
AylinCE Grandmaster Cheater Supreme
Reputation: 37
Joined: 16 Feb 2017 Posts: 1543
|
Posted: Wed Jan 14, 2026 8:54 pm Post subject: |
|
|
Thanks for the great feedback! I've updated the tool to make the workflow even faster and more intuitive based on your suggestions.
What's New:
Smart Update Mode: If you enter an Index number, the tool now detects it as an 'Update' request. Click UPDATE to overwrite the existing record instead of creating a duplicate.
Quick Shortcuts:
ENTER: Instant Parse.
CTRL+S: Add New Record.
CTRL+U: Update Record.
ESC: Quick Close.
Auto-Naming: The tool now suggests a default name based on the pointer path, so you don't have to type descriptions manually.
Status Bar: The value display now provides real-time feedback for your actions (Added, Updated, or Invalid Index).
Fix: Standard Windows hotkeys (CTRL+V, CTRL+A) are now fully functional and stable.
Enjoy the high-speed parsing!
_________________
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|