Lua:getAddressSafe

From Cheat Engine
Jump to navigation Jump to search

function getAddressSafe(AddressString, local OPTIONAL, shallow OPTIONAL) : integer

Safely resolves a symbol name to a memory address without raising exceptions. Returns nil on failure instead of throwing an error.

Note: This is the recommended function for symbol resolution when the symbol might not exist.

Function Parameters[edit]

Parameter Type Description
AddressString string or number (CEAddressString) The symbol to resolve (module name, address expression, label, pointer expression). If a number is provided, it's returned unchanged
local boolean Optional. If true, uses Cheat Engine's self symbol handler instead of the target process. Default: false
shallow boolean Optional. If true, performs a shallow (faster) symbol lookup without deep parsing. Default: false


Returns[edit]

An integer representing the resolved address on success, or nil if resolution fails.

Description[edit]

This function works identically to getAddress but returns nil on failure instead of raising an exception. It resolves:

  • Module names (e.g., "game.exe", "kernel32.dll")
  • Module + offset expressions (e.g., "game.exe+1234")
  • Symbol names from debug symbols or exports
  • Registered symbols from registerSymbol()
  • Auto-assembler labels
  • Pointer expressions


Return Behavior[edit]

  • Success: Returns the resolved address as an integer
  • Failure: Returns nil (nothing pushed to Lua stack)
  • Numeric input: Returns the number unchanged
  • Exceptions: Catches all exceptions and returns nil


Usage Examples[edit]

Basic safe resolution:

local address = getAddressSafe("game.exe+12345")
if address then
  print(string.format("Address: %X", address))
else
  print("Failed to resolve symbol")
end

Check if module exists:

local baseAddr = getAddressSafe("optionalModule.dll")
if baseAddr then
  print("Module loaded at: " .. baseAddr)
else
  print("Optional module not loaded")
end

Conditional feature detection:

local featureAddr = getAddressSafe("game.exe+NewFeatureOffset")
if featureAddr then
  -- New version with feature
  print("New version detected")
  enableNewFeature(featureAddr)
else
  -- Old version without feature
  print("Old version, feature not available")
  useOldMethod()
end

Safe symbol registration:

function tryRegisterSymbol(name, expr)
  local addr = getAddressSafe(expr)
  if addr then
    registerSymbol(name, addr)
    print(string.format("Registered %s = %X", name, addr))
    return true
  else
    print("Warning: Failed to register " .. name)
    return false
  end
end

tryRegisterSymbol("PlayerHealth", "game.exe+ABCD")

Version-dependent code:

local v1Addr = getAddressSafe("game.exe+1000")
local v2Addr = getAddressSafe("game.exe+2000")

if v2Addr and readBytes(v2Addr) == 0x48 then
  print("Using version 2 offsets")
  healthAddr = v2Addr
elseif v1Addr then
  print("Using version 1 offsets")
  healthAddr = v1Addr
else
  print("Unknown version!")
  return false
end

Numeric pass-through:

local addr = getAddressSafe(0x12345678)
-- Returns 0x12345678 unchanged
print(addr)  -- 305419896

With shallow lookup (faster):

-- Shallow lookup is faster but may miss complex expressions
local addr = getAddressSafe("game.exe", false, true)
if addr then
  print("Quick module lookup: " .. addr)
end


Shallow vs Deep Lookup[edit]

The shallow parameter controls the symbol resolution depth:

Deep lookup (shallow = false, default):

  • Performs full expression parsing
  • Handles complex pointer arithmetic
  • Resolves nested brackets and offsets
  • Slower but more comprehensive

Shallow lookup (shallow = true):

  • Quick module/symbol name lookup
  • Skips complex expression evaluation
  • Faster for simple module names
  • May fail on complex expressions

Example:

-- Deep lookup (handles complex expressions)
local addr1 = getAddressSafe("[[game.exe+100]+8]+4", false, false)

-- Shallow lookup (fast, simple names only)
local addr2 = getAddressSafe("game.exe", false, true)


Comparison: getAddress vs getAddressSafe[edit]

Feature getAddress getAddressSafe
On failure Raises exception Returns nil
Error handling Requires pcall or try/catch Simple if/then check
Use case Symbol must exist Symbol might not exist
Performance Same Slightly faster (no exception overhead on failure)
Code complexity More complex (needs pcall) Simpler (direct nil check)


Advanced Examples[edit]

Multi-version support:

local offsets = {
  v1 = "game.exe+10000",
  v2 = "game.exe+20000",
  v3 = "game.exe+30000"
}

local healthAddr = nil
for version, offset in pairs(offsets) do
  local addr = getAddressSafe(offset)
  if addr and readBytes(addr) == 0x89 then  -- Signature check
    healthAddr = addr
    print("Detected " .. version)
    break
  end
end

if not healthAddr then
  print("ERROR: No compatible version found!")
  return false
end

Graceful degradation:

function findPlayerHealth()
  -- Try primary location
  local addr = getAddressSafe("PlayerHealthPrimary")
  if addr then return addr end
  
  -- Try secondary location
  addr = getAddressSafe("game.exe+ABCD")
  if addr then return addr end
  
  -- Try pattern scan as fallback
  addr = AOBScanUnique("89 44 24 ?? 8B 45", "+X")
  if addr then
    registerSymbol("PlayerHealthPrimary", addr)
    return addr
  end
  
  return nil  -- All methods failed
end

local health = findPlayerHealth()
if health then
  print("Health found at: " .. health)
else
  print("Could not locate health!")
end

Validate before use:

function safeWriteInteger(symbol, value)
  local addr = getAddressSafe(symbol)
  if not addr then
    print("Error: Cannot resolve " .. symbol)
    return false
  end
  
  writeInteger(addr, value)
  return true
end

if safeWriteInteger("PlayerGold", 9999) then
  print("Gold updated successfully")
end


Exception Safety[edit]

getAddressSafe catches ALL exceptions during symbol resolution:

-- These all return nil instead of crashing:
local addr1 = getAddressSafe("!@#$%^&*()")  -- Invalid syntax
local addr2 = getAddressSafe(nil)           -- Nil input
local addr3 = getAddressSafe("")            -- Empty string
local addr4 = getAddressSafe("[[[[[")       -- Malformed brackets


Performance Considerations[edit]

  • Shallow lookups are faster for simple module names
  • Deep lookups required for complex expressions
  • Symbol resolution waits for symbol loading (can block)
  • Cache resolved addresses in variables for repeated use:
-- Bad: Resolves every iteration
for i = 1, 1000 do
  local addr = getAddressSafe("game.exe+1234")
  writeInteger(addr, i)
end

-- Good: Resolve once, reuse
local addr = getAddressSafe("game.exe+1234")
if addr then
  for i = 1, 1000 do
    writeInteger(addr, i)
  end
end

Common Patterns[edit]

Assert pattern (fail fast):

local addr = getAddressSafe("game.exe+1234")
assert(addr, "Failed to resolve game.exe+1234")
-- Continue with addr

Default value pattern:

local addr = getAddressSafe("game.exe+1234") or 0x400000
-- Use default if resolution fails

Chain pattern (try multiple):

local addr = getAddressSafe("NewSymbol") or 
             getAddressSafe("OldSymbol") or
             getAddressSafe("game.exe+1234")


See also[edit]

Related Functions[edit]