Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


no way to make lua print the function / call stackon error ?

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
peddroelm
Advanced Cheater
Reputation: 0

Joined: 03 Oct 2014
Posts: 84

PostPosted: Sun Jan 22, 2023 6:07 am    Post subject: no way to make lua print the function / call stackon error ? Reply with quote

Code:
Error:[string "local syntaxcheck,memrec=...
..."]:10: attempt to perform arithmetic on a nil value (local 'val')
Error:[string "local syntaxcheck,memrec=...
..."]:10: attempt to perform arithmetic on a nil value (local 'val')
Error:[string "local syntaxcheck,memrec=...
..."]:413: attempt to perform arithmetic on a nil value
Error:[string "local syntaxcheck,memrec=...
..."]:413: attempt to perform arithmetic on a nil value


in a big table with 40+ scripts .. go hunting it down when I suppose would've very easy for lua to help out with some basic information past .. "shit's broken bro .."

Oher than taking error managing to heart (healthy guide line as that might be) how does one 'debug' cheat engine lua issues ?

should I make all my lua functions log their name when debug flip (global variable) is flipped ?

(happy case here gives a local variable name I only have in a script .. but other error messages offer next to no information Sad )

Is there an extra lua error log file somewhere ?


Code:

 *** readIntegerSigned  **** at addr[8dff97b1]
 
Error:[string "local syntaxcheck,memrec=...
..."]:17: attempt to perform arithmetic on a nil value (local 'val')


readIntegersigned tries to read from memory location ?? ?? ?? ?? ?? (protected ? )

but which of the 20 functions that could be calling readIntegersigned is it ?
I need to make the all dump function name on entry ... ?

Code:
function readIntegerSigned(addr)

if (Gobal_Log_Function_Calls ~= nil) then
  if Gobal_Log_Function_Calls then
    print(string.format("\n *** readIntegerSigned  **** at addr[%x] \n", addr ))
                              end
                                  end
...


repeat this step for all functions (that can call readIntegersigned) .. all of them for future .. 'events' ?

Called unexpectedly from different place in code / different game activity
*** logCrewCbt_ROLL_turn_INITIATIVE **** [69] [a3e091]




is this a good Valid Character struct checker ? Time will tell .. seems to work for now ..

Code:
function isValidCharacter(addr)

if (Gobal_Log_Function_Calls ~= nil) then
  if Gobal_Log_Function_Calls then
    print(string.format("\n *** isValidCharacter  **** CharAddr[%x] \n", addr ))
                              end
                                  end


if ( readInteger(addr) == nil)                           then return false end
if ( readInteger(readInteger(addr)) == nil)              then return false end
if ( readByte(readInteger(readInteger(addr))  ) ~= 0x33) then return false end
if ( readByte(readInteger(readInteger(addr))+1) ~= 0xC0) then return false end
if ( readByte(readInteger(readInteger(addr))+2) ~= 0xC2) then return false end

return true
end
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Sun Jan 22, 2023 12:39 pm    Post subject: Reply with quote

It tells you the line number in the error message. "10:", "413:", "17:"

Indenting your code might help you track down errors.

peddroelm wrote:
Code:
readInteger(readInteger(addr))
This is bad. readInteger only reads 4 bytes. If you want to read a pointer, use readPointer.

This works fine:
Code:
function isValidCharacter(addr)
  local b1, b2, b3 = readBytes(readPointer(readPointer(addr)), 3, false)
  return b1 == 0x33 and b2 == 0xC0 and b3 == 0xC2
end


Best advice is to experiment. Do you know what happens when readBytes or readPointer get passed an invalid integer address? What about nil, or an invalid symbol (string)? Does it generate an error, return nil, or do nothing (basically nil)?

Make assumptions about how things work and you'll screw up every time you get a small detail wrong.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
peddroelm
Advanced Cheater
Reputation: 0

Joined: 03 Oct 2014
Posts: 84

PostPosted: Sun Jan 22, 2023 10:31 pm    Post subject: Reply with quote

Thank you for the many times I've read helpful bits of info from your posts on these forums over the years ParkourPenguin !

> " It tells you the line number in the error message. "10:", "413:", "17:" "

Don't know what 'Im doing wrong (comments / empty lines) by in my experience the line number it provides never matches the line in the code editor .. If its a syntax error I copy/paste the function into an online lua compiler like https://www.tutorialspoint.com/execute_lua_online.php and that will put the finger on the right error line .. Can't do that for runtime errors ..


> "this is bad !"
readInteger(readInteger(addr))

readPointer ... (as per Wiki) uses readInteger for x32 application which this is .
What is the advantage ? Code readability ?

Is it capable of handing multiple level pointers without need to manually check for nil at ever offset ? Will just gracefully provide nil at the end which one can check for once at the end ?

What about something like this :
return
Code:
readInteger('[[[[[[["StarTradersFrontiersMods.exe"+0085467C]+18]+1C]+8]+A8]+A8]+184]+0x4c')-35


(should check for nil ) but should this also be re written using readpointer(readpointer .. ) ?


> local b1, b2, b3 = readBytes(readPointer(readPointer(addr)), 3, false)

What weird / un expected behavior Smile What is this called (what does one google to understand why that works ? )

I remember using in the past something like
local bytetable = readBytes(readPointer(readPointer(addr)), 3, false) // without the readpointer s of course which I've never used before and then ..

then check for bytetable[1] vs 0x33 (is it 0 based ? 1 based ) bytetable [2] ....
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Mon Jan 23, 2023 12:01 am    Post subject: This post has 1 review(s) Reply with quote

peddroelm wrote:
What is the advantage ? Code readability ?
Yes. If you want to read the value of a pointer, use readPointer. It's self-documenting.

peddroelm wrote:
Is it capable of handing multiple level pointers without need to manually check for nil at ever offset ? Will just gracefully provide nil at the end which one can check for once at the end ?
This is what I was talking about when I said you should experiment and figure out the small details yourself.

Open the Lua engine (Memory viewer -> Tools -> Lua Engine) and start writing stuff.
Code:
-- return things to examine them: e.g. first value returned is 7, second value is true
return 7,true
-- 1:7
-- 2:true

-- returns nothing
return readPointer(nil)

-- nothing is often similar to nil
return readPointer(nil) == nil
-- 1:true

-- passing nothing to readPointer also results in nothing
return readPointer()

-- since readPointer returns nothing on failure and accepts nothing without error,
-- nesting calls to readPointer also won't result in an error:
return readPointer(readPointer())

peddroelm wrote:
> local b1, b2, b3 = readBytes(readPointer(readPointer(addr)), 3, false)

What weird / un expected behavior Smile What is this called (what does one google to understand why that works ? )
Why? What did you expect to happen?
Lua functions can return multiple values. Is that the confusing part?
This link is a chapter of a book on Lua 5.0. Even though Lua 5.0 is an old version, this part remains relevant for CE Lua 5.3:
https://www.lua.org/pil/5.1.html

peddroelm wrote:
I remember using in the past something like
local bytetable = readBytes(readPointer(readPointer(addr)), 3, false) // without the readpointer s of course which I've never used before and then ..

then check for bytetable[1] vs 0x33 (is it 0 based ? 1 based ) bytetable [2] ....
See the third parameter to readBytes. celua.txt:
Quote:
readBytes(address,bytecount, ReturnAsTable ) : returns the bytes at the given address. If ReturnAsTable is true it will return a table instead of multiple bytes

Regarding 0 vs 1 index-based arrays... it's complicated. Lua arrays start at 1, but pretty much every other programming language starts at 0, including internal APIs CE uses. This means some of CE's Lua API starts indexing at 0 (e.g. GUI-related stuff: memory records, address list...), while other parts of CE''s Lua API use Lua conventions and start arrays at 1 (e.g. `readBytes(addr, num, true)`, `dwordToByteTable` et al.). The only way to know is to experiment.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
peddroelm
Advanced Cheater
Reputation: 0

Joined: 03 Oct 2014
Posts: 84

PostPosted: Mon Jan 23, 2023 11:02 pm    Post subject: Reply with quote

Code:

...
local INITQueueADDR = getAddress("INITQueue")
local Attacker_ADDR = readPointer(readPointer(readPointer(INITQueueADDR))+0x6C)

if not Attacker_ADDR  then return end
..


readPointer still errors out

Error:[string "local syntaxcheck,memrec=...
..."]:21: attempt to perform arithmetic on a nil value Sad

Context: I set/update the value in INITQueue symbol address at start of every combat round .. If I enable the script 'during' a combat round ..don't have the right value in INITQueue.. error ..


if not Attacker_ADDR then return end never gets to run .. readPointer already errored out ..

////

this line in lua engine
local Attacker_ADDR = readPointer(readPointer(readPointer())+0x6C)
errors out

//
Need to check for Nil Before EVERY + offset math

if readPointer(readPointer()) then
local Attacker_ADDR = readPointer(readPointer(readPointer())+0x6C)
else
return " caught it ! "
end
return Attacker_ADDR

1: caught it !


so for the moment:

Code:

local Attacker_ADDR

if readPointer(readPointer(INITQueueADDR)) then
     Attacker_ADDR = readPointer(readPointer(readPointer(INITQueueADDR))+0x6C)
                                           else
     return
end

if not Attacker_ADDR then return end
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Tue Jan 24, 2023 12:27 am    Post subject: Reply with quote

You can't add an integer to nil.

Offsets are a problem. I think I'd make my own function to handle that gracefully:

Code:
-- Basically readPointer but explicit base address and offsets
-- readPointer'foo'   == readPointerPath'foo'
-- readPointer'[foo]' == readPointerPath('foo', 0)
-- readPointer'[[foo+1C]+8]+20'  == readPointerPath('foo+1C', 8, 0x20)
-- offsets can also be a Lua array: readPointerPath(base, {1, 2, ...})
function readPointerPath(base, ...)
  local offsets = {...}
  if #offsets == 1 and type(offsets[1]) == 'table' then
    offsets = offsets[1]
  end

  local node = readPointer(base)
  if not node then
    return nil,'Invalid base address: ' .. tostring(base)
  end

  for i,offs in ipairs(offsets) do
    if type(offs) ~= 'number' then
      return nil,('Invalid offset #%d: type = %s'):format(i, type(offs))
    end
    local pval = readPointer(node + math.floor(offs))
    if not pval then
      return nil,('Bad read at node #%d: addr = %08X'):format(i, node)
    end
    node = pval
  end

  return node
end


Code:
-- instead of this:
-- readPointer(readPointer(readPointer(INITQueueADDR))+0x6C)

-- use this:
readPointerPath(INITQueueADDR, 0, 0x6C)


Returning nil and some string works well with assert.
Code:
-- error: Invalid base address: nil
assert(readPointerPath())

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
peddroelm
Advanced Cheater
Reputation: 0

Joined: 03 Oct 2014
Posts: 84

PostPosted: Tue Jan 24, 2023 3:53 am    Post subject: Reply with quote

So for non critical errors I might want just silently return

check for readPointerPath( ..) for nil

In the cases we need to crash the script .. assert seems like a good call but the extra strings you return aren't helping (by themselves)

Hey an Assert( readPointerPath( ..) )
failed .. I'm only calling it from a bazillion places..

The assert error text must have function name and assert index in that function ..

This , right here officer , .. the 4th assert in the "blabla" function brought us down !

local var = readPointerPath (base + offset list )
assert(var, " Script name(would be nice if lua had a function for it otherwise type by hand every time) + again by hand index of assert in function xx ")


error :: Log_EmpircalTell_DiceRoll 5


debug.getinfo might gimme function name ?


The following function illustrates the use of debug.getinfo. It prints a primitive traceback of the active stack:

https://www.lua.org/pil/23.1.html

function traceback ()
local level = 1
while true do
local info = debug.getinfo(level, "Sl")
if not info then break end
if info.what == "C" then -- is a C function?
print(level, "C function")
else -- a Lua function
print(string.format("[%s]:%d",
info.short_src, info.currentline))
end
level = level + 1
end
end
It is not difficult to improve this function, including more data from getinfo. Actually, the debug library offers such an improved version, debug.traceback. Unlike our version, debug.traceback does not print its result; instead, it returns a string.


Ha

Code:

UI HUMAN Targeting CTC Enabled:

stack traceback:
   [string "local syntaxcheck,memrec=...
..."]:23: in function 'UI_NameSTR_HUMANS'
   [string "function _luaservercall10636(parameter)
..."]:2: in function '_luaservercall10636'
   (...tail calls...)

 


yup debug.traceback() should be in that assert error message + assert index since I don't/can't trust the line error numbers ..

Actually I could do the syntax trick copy paste function source code trick after the error since now I have the function name .. Still quicker if it straight tells which of the N asserts in that function was tripped ...


"debug.getinfo and debug.traceback get their info from various sources, some of them hacky. For instance, the function name is generally extracted from the source code of the calling function: whatever name the code used to look up the thing it called, that's what gets used as the name. (That's why your second code snippet didn't give you the name: pcall doesn't have Lua bytecode backing it up, so it can't tell you "test" unless there's a function in the middle to call it "test".) Lua functions do not have inherent names, any more than Lua integers do; a function is just another kind of value, which can be automatically assigned to a variable via some syntactic sugar."

Code:
Attacker_ADDR = nil
assert(Attacker_ADDR, "01 " .. debug.traceback() )

Error:[string "local syntaxcheck,memrec=...
..."]:17: 01 stack traceback:
   [string "local syntaxcheck,memrec=...
..."]:17: in function 'UI_NameSTR_HUMANS'
   [string "function _luaservercall10636(parameter)
..."]:2: in function '_luaservercall10636'
   (...tail calls...)



Don't know how I'm gonna fix it yet but I know EXACTLY where to start Smile



And

Code:

return getRTTIClassName("0xcd5c168")
1:STEGameCharacterModel


seems like a much better test for is valid character
can apply it to many other struct types as well in this game

since the shared 'function' I'm having issues with doesn't do the usual
push ebp
mov ebp,esp at start, ebp-esp IS different depending on who is calling it ..
logging to make sure first but .. yes .. atm only a particular case of that delta is what is of interest to me

Code:

logCrewCbt_ROLL_turn_INITIATIVE ebp-esp = 5cc
logCrewCbt_ROLL_turn_INITIATIVE ebp-esp = 120
logCrewCbt_ROLL_turn_INITIATIVE ebp-esp = 120
logCrewCbt_ROLL_turn_INITIATIVE ebp-esp = 4c
logCrewCbt_ROLL_turn_INITIATIVE ebp-esp = 4c
logCrewCbt_ROLL_turn_INITIATIVE ebp-esp = 4c
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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 can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites