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 


Fixing Lua String Compare
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
Csimbi
I post too much
Reputation: 97

Joined: 14 Jul 2007
Posts: 3327

PostPosted: Sun Jun 09, 2024 1:56 pm    Post subject: Reply with quote

As it happens, I also need to compare strings in LUA.
To be a bit more specific, I need to check whether a string contains a string.
These strings are wide strings (UTF-16).

This is what my code looks like for now:
Code:

    local iEntryLen = readInteger('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+10')
    if iEntryLen > 10 and iEntryLen <25 then
      -- Check if this entry is of interest.
      local sEntryName = readString('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+14', 12, true)
      if sEntryName~=nil and <contains>(sEntryName,"Rep.") then


The aim is to replace that <contains>(sEntryName,"Rep.") with a legit test in a way that comparison returns true only if "Rep." is found in sEntryName (it will be near the beginning).
I suppose it would be faster if sEntryName was not read into a local variable in the first place, so a <contains>(<pointer to sEntryName>,"Rep.") might better.
I will take either one though, speed is not a requirement Wink

Thank you!
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Mon Jun 10, 2024 8:00 am    Post subject: Reply with quote

Just an example to get you started;

It makes it easier to read and compare special characters (non-letters and numbers!)!

Code:
function specialcrt(str)
fields = ""
 for wrd in str:gmatch(".") do
  if string.find(wrd,"%p") or string.find(wrd,"%c") then
   fields = fields..(wrd:gsub(".",  "%%"..wrd))
  else
   fields = fields..wrd
  end
 end
 return fields
end

function finds(s1,s2)
 s2 = specialcrt(s2)
--print(s2)
  if string.find(s1,s2) then
    return true
  else
   return false
  end
end

sEntryName = "Compare Rep. rep1-"
search1 = "Rep."
search2 = "rep1-"

if sEntryName~="" and finds(sEntryName,search1)==true then
 print("true")
else
 print("false")
end

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Csimbi
I post too much
Reputation: 97

Joined: 14 Jul 2007
Posts: 3327

PostPosted: Mon Jun 10, 2024 2:57 pm    Post subject: Reply with quote

Erm, thanks? Very Happy

I understand the bottom part, but that function specialcrt(str) on top looks like chinese to me Very Happy

AylinCE wrote:

Code:
function specialcrt(str)
fields = ""
 for wrd in str:gmatch(".") do
  if string.find(wrd,"%p") or string.find(wrd,"%c") then
   fields = fields..(wrd:gsub(".",  "%%"..wrd))
  else
   fields = fields..wrd
  end
 end
 return fields
end


Any chance you could explain how it works?
Will this work with UTF16?

Thank you!
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Mon Jun 10, 2024 6:30 pm    Post subject: Reply with quote

This is just a function that adds a wildcard "%" character to the beginning of characters that are not letters or numbers, so that the code does not ignore them.

In some cases, lua code (find, match, gsub, etc.) may see punctuation marks as wildcard characters that it constantly uses and gives other meanings, and skips reading it.

In String.find "Rep." The string is sometimes not noticeable to the code because of the dot, but "Rep%." When you type with , the code will recognize that line and see the "period" as part of the string, not as a wildcard.

I added this function for this reason.

If you want a function for UTF16 characters, "Convert" and "search word" are exemplified below in the same function, which will both correct the entire text and scan and find the word in it.

You can test the sample and give your opinion. Wink
( All UTF16 characters list;
https://www.fileformat.info/info/charset/UTF-16/list.htm )

--Unicode to text --

Code:
function utf8Char (decimal)
    if decimal < 128 then
        return string.char(decimal)
    elseif decimal < 2048 then
        local byte2 = (128 + (decimal % 64))
        local byte1 = (192 + math.floor(decimal / 64))
        return string.char(byte1, byte2)
    elseif decimal < 65536 then
        local byte3 = (128 + (decimal % 64))
        decimal = math.floor(decimal / 64)
        local byte2 = (128 + (decimal % 64))
        local byte1 = (224 + math.floor(decimal / 64))
        return string.char(byte1, byte2, byte3)
    elseif decimal < 1114112 then
        local byte4 = (128 + (decimal % 64))
        decimal = math.floor(decimal / 64)
        local byte3 = (128 + (decimal % 64))
        decimal = math.floor(decimal / 64)
        local byte2 = (128 + (decimal % 64))
        local byte1 = (240 + math.floor(decimal / 64))
        return string.char(byte1, byte2, byte3, byte4)
    else
        return nil
    end
end

function specialcrt(str)
fnt = {}
local i = 0
local res = ""
 for wrd in str:gmatch("u....") or str:gmatch("u.....") do
  aa1 = wrd:gsub("u","")
  i=tonumber(i) + 1
  fnt[i] = aa1
 end
 for l,k in pairs(fnt) do
  aa2 = tonumber(k,16)
 print(aa2)
  str = str:gsub("u"..k, utf8Char(tonumber(aa2)))
  res = str
 end
 return res
end

rst="Citau00e7u00e3o: Vocu00ea u00e9 a  minha razu00e3o de viver. u1d4ac"
res = specialcrt(rst)
print(rst)
print(res)

 if string.find(res,"razão") then
   print("true")
 else
   print("false")
 end

 res = tonumber("00e9",16)
 print(utf8Char(res))

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past


Last edited by AylinCE on Mon Jun 10, 2024 10:18 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Mon Jun 10, 2024 8:22 pm    Post subject: Reply with quote

AylinCE wrote:
Code:
<single line of 6538 characters>
Fucking hell. Please edit that post and just leave an ellipsis after a bit. i.e. `[[]]):gsub("u0100","Ā"):gsub("u0101","ā"):gsub("u0102","Ă"):gsub("u0103","ă")...`

If you must use gsub like that, replace it with a table lookup:
Code:
local t = {
  u0100 = "Ā",
  u0101 = "ā",
  u0102 = "Ă",
  u0103 = "ă",
  u0104 = "Ą",
  u0105 = "ą",
--...
}

function foo(s)
  return s:gsub('(u%d%d%d%d)', t)
end
There are other functions in CE's Lua API. e.g. `wideStringToByteTable`
_________________
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
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Mon Jun 10, 2024 10:23 pm    Post subject: Reply with quote

Replaced with a different format!

@Csimbi, I got scolded by @Parkour, because of you! Shocked Smile

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Csimbi
I post too much
Reputation: 97

Joined: 14 Jul 2007
Posts: 3327

PostPosted: Wed Jun 12, 2024 7:41 am    Post subject: Reply with quote

ParkourPenguin wrote:
Fucking hell.

Have not heard that one before from you Very Happy

ParkourPenguin wrote:
There are other functions in CE's Lua API. e.g. `wideStringToByteTable`

Thanks for that!
Code:
wideStringToByteTable(string): {}    - Converts a string to a widestring and converts that to a bytetable

Is the idea to convert the ASCII string to UTF16 and that to a bytetable, which I can directly compare to the UTF16 string?
If so, how does one do that comparison?

AylinCE wrote:
@Csimbi, I got scolded by @Parkour, because of you! Shocked Smile

Sorry Very Happy
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Wed Jun 12, 2024 10:55 am    Post subject: Reply with quote

Csimbi wrote:

Is the idea to convert the ASCII string to UTF16 and that to a bytetable, which I can directly compare to the UTF16 string?
If so, how does one do that comparison?


Is it possible to send here a text, sentence or paragraph you come across? (ASCII or UTF16)

An example of Wide String format;

Code:
function byteTableToAobString(t)
  for k,v in ipairs(t) do
    t[k] = ('%02X'):format(v)
  end
  return table.concat(t, ' ')
end

function formatWideStringToAobs1(text1)
  newvalue = text1
  --newvalue = tonumber(newvalue)
  if not newvalue then return end
 newvalue = wideStringToByteTable(newvalue)
  newvalue = byteTableToAobString(newvalue)
  res1=('%s '):format(newvalue, newvalue)
 return res1
end


function utf8Char(decimal)
    if decimal < 128 then
        return string.char(decimal)
    elseif decimal < 2048 then
        local byte2 = (128 + (decimal % 64))
        local byte1 = (192 + math.floor(decimal / 64))
        return string.char(byte1, byte2)
    elseif decimal < 65536 then
        local byte3 = (128 + (decimal % 64))
        decimal = math.floor(decimal / 64)
        local byte2 = (128 + (decimal % 64))
        local byte1 = (224 + math.floor(decimal / 64))
        return string.char(byte1, byte2, byte3)
    elseif decimal < 1114112 then
        local byte4 = (128 + (decimal % 64))
        decimal = math.floor(decimal / 64)
        local byte3 = (128 + (decimal % 64))
        decimal = math.floor(decimal / 64)
        local byte2 = (128 + (decimal % 64))
        local byte1 = (240 + math.floor(decimal / 64))
        return string.char(byte1, byte2, byte3, byte4)
    else
        return nil
    end
end

text = "razão"

print("Text:\n"..text)

fmtaobs = formatWideStringToAobs1(text)

print("\nFormat WideString aobs:\n"..fmtaobs)


----------------------------------------------
fmttext = ""
fmtaobs2 = fmtaobs:gsub("00","")


 for wrd in fmtaobs2:gmatch("%x%x") do
   --print(wrd)
   chrdec = tonumber(wrd,16)
   print("\nFormat byte:\n"..wrd.." to "..chrdec)

   fmttext = fmttext..utf8Char(tonumber(chrdec))
 end


print("\nFormat aobs to text:\n"..fmttext)


result:
Text:
razão

Format WideString aobs:
72 00 61 00 7A 00 E3 00 6F 00

Format byte:
72 to 114

Format byte:
61 to 97

Format byte:
7A to 122

Format byte:
E3 to 227

Format byte:
6F to 111

Format aobs to text:
razão

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Csimbi
I post too much
Reputation: 97

Joined: 14 Jul 2007
Posts: 3327

PostPosted: Wed Jun 12, 2024 11:17 am    Post subject: Reply with quote

AylinCE wrote:

Is it possible to send here a text, sentence or paragraph you come across?

Certainly.
I have a tuple array that I iterate through.
Each tuple is a pair of UTF-16 strings and a 4-byte value.
A string may, or may not contain "Reputation.xxx" - for example: "Reputation.Pirates".
So, my aim is to iterate through the array and check each string as fast as possible, to see if it contains "Reputation." and if it's found, then add a pointer to a new memrec.
I have the code working - except the string comparison for UTF-16 strings.
Here's the full code. Problem is, it checks only the beginning of the string only using a qword so it won't find entries where "Repu" is not at the beginning and there might be false positives, too.

Code:
[ENABLE]
{$lua}
if syntaxcheck then return end

for i=memrec.Count-1,0,-1 do
  memrec.Child[i].delete()
end

local pStatsAddress=readPointer("pStats")
local count
if pStatsAddress~=nil and pStatsAddress~=0 then
  print(string.format("pStats: %X", pStatsAddress))
  count = readInteger('[[pStats]+18]+40')
  if count~=nil then print(string.format("Count: %d", count)) end
end

if count==nil then ShowMessage('Invalid pointer; refresh pointer and try again!')
elseif count <=0 then ShowMessage('No items found.')
elseif count >1000 then ShowMessage('Too many items; wrong pointer? Refresh pointer and try again!')
else
  AddressList.List.beginUpdate()
  for i=0, count do
    local iEntryLen = readInteger('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+10')
    if iEntryLen~=nil and iEntryLen > 11 and iEntryLen <35 and readQword('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+14')==0x75007000650052 then
      local mr = AddressList.createMemoryRecord()
      mr.description = 'Stats['..(i)..']'
      mr.Type = vtString
      mr.String.Size = 64
      mr.String.Unicode = true
      mr.Address = '[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+14'
      mr.Color = 0x0000FF
      mr.appendToEntry(memrec)

      local mrchild = AddressList.createMemoryRecord()
      mrchild.description = 'iRelationshipValue'
      mrchild.Type = vtDword --vtSingle
      mrchild.ShowAsSigned = true
      mrchild.Address = '[[[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+30]+18]+20]+10'
      mrchild.Color = 0xFF0000
      mrchild.appendToEntry(mr)
    end
  end
  AddressList.List.endUpdate()
end
{$asm}

[DISABLE]
{$lua}
if syntaxcheck then return end
AddressList.List.beginUpdate()
for i=memrec.Count-1,0,-1 do
  memrec.Child[i].delete()
end
AddressList.List.endUpdate()
{$asm}


This script is part of my BattleTech table posted on fearless, if you'd like to try it. You'll need the game though and some work to setup the required mods.
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Wed Jun 12, 2024 12:37 pm    Post subject: Reply with quote

In your case "75007000650052" returns "upeR" and shows "Repu" in reverse.

Here's a different method for reading:
Is it possible to get iEntryLen as just the address?
So you can print it as aob and compare it.

The code below allows you to print the address to the aob output in the length you specify.
So it's easier to test it with just the aob (hex) output rather than any string.


Code:
function getByteString(address, bytecount)
 local bytes = readBytes(address, bytecount, true)
 if bytes then
 local result = ""
 for i = 1, #bytes do
 if #result > 0 then result = result .. "" end
 result = result .. string.format("%02X", bytes[i]) end
 return result end
end


  --for i=0, count do
    --local iEntryLen = readInteger('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+10')
    local iEntryLen1 = '[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+10'
    --if iEntryLen~=nil and iEntryLen > 11 and iEntryLen <35 and readQword('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+14')==0x75007000650052 then

iEntryLen2 = getByteString(iEntryLen1, 7) -- 75+00+70+00+65+00+52 = 7 byte

--75706552 = upeR
--52657075 = Repu

if iEntryLen2~=nil and iEntryLen2=="75007000650052" then

I try the code like this.

I am looking for "E8 03 00 00" in "arrayofbyte" in CE via Chrome process.

I get the address of the result;
Code:
aa2 = "28061758"

I format it 7 bytes wide;
Code:
iEntryLen2 = getByteString(aa2, 7)
print(iEntryLen2)

The result it gave me was;
E8030000010000

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Wed Jun 12, 2024 2:59 pm    Post subject: Reply with quote

Csimbi wrote:
Code:
wideStringToByteTable(string): {}    - Converts a string to a widestring and converts that to a bytetable

Is the idea to convert the ASCII string to UTF16 and that to a bytetable, which I can directly compare to the UTF16 string?
This goes through a long list of conversions
  1. Lua string- an array of 8-bit values (including 0). Entirely encoding-agnostic.
  2. C string- almost the same as a Lua string, but it terminates early at 0 bytes. e.g. `print'12\x0034'` only prints "12"
  3. Pascal String- aliased to some other type (AnsiString?). Probably the same as a C string, just with its own memory. I think CE assumes this is a UTF-8 encoding
  4. WideString- basically UTF-16
  5. raw bytes- the way the widestring is stored in memory as bytes

As for comparing them, comparing the Lua strings should be fine:
Code:
local s1 = readString(addr, 256, true)  -- read wide string
print(s1 == 'whatever')

_________________
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
Csimbi
I post too much
Reputation: 97

Joined: 14 Jul 2007
Posts: 3327

PostPosted: Thu Jun 13, 2024 12:27 pm    Post subject: Reply with quote

AylinCE wrote:
Here's a different method for reading:
Is it possible to get iEntryLen as just the address?
So you can print it as aob and compare it.

I am sure how that would that help me. All strings have different lengths.
I already check for min. length (can't possibly contain the substring) and max. length (I have not found any string that's longer and contains the substring).
Please clarify.

Note: iEntryLen here means the number of printable character, not the size of the memory the UTF16 array occupies.

ParkourPenguin wrote:

Code:
local s1 = readString(addr, 256, true)  -- read wide string
print(s1 == 'whatever')

Do I need to read the widestring into s1 the first place? (is there a direct widescreen comparison?)

Code:
local s1 = readString(addr, iEntryLen*3, true)  -- Min 2 bytes, max 4, so 3 on average :D
print(s1 == 'Reputation.')


Is the string 'Reputation.' automatically treated as a widestring in the comparison?
Looks like a UTF8/ascii string.
I know in a C++ compiler the "low precision operand" is converted up to the match the "high precision operand".
I.e. in a float vs. double comparison the float is converted to a double automatically before the comparison (and then two doubles are compared).
Does LUA work the same way?
Might be a lame question, sorry.

Edit
Oh, hang on, this won't when the string is not at the beginning of the other string.
I need to find a string within a string.
That's what the gsub magic is there for from AylinCE, I suspect.
I felt I had it, now I feel I lost it.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Thu Jun 13, 2024 1:31 pm    Post subject: Reply with quote

Csimbi wrote:
Do I need to read the widestring into s1 the first place? (is there a direct widescreen comparison?)

Code:
local s1 = readString(addr, iEntryLen*3, true)  -- Min 2 bytes, max 4, so 3 on average :D
print(s1 == 'Reputation.')


Is the string 'Reputation.' automatically treated as a widestring in the comparison?
Looks like a UTF8/ascii string.
In CE, all Lua strings are pretty much always treated as UTF-8. If the game is using a widestring, it's perfectly fine to convert that to UTF-8 and compare the strings normally.
Code:
local widechars = { 0x43, 0x61, 0x73, 0x68, 0x3A, 0x20, 0x20AC, 0x35, 0 }

local lpStr = createMemoryStream()
lpStr.Size = #widechars * 2

for _,w in ipairs(widechars) do
  lpStr.writeWord(w)
end

print'Bytes:'
print(readBytesLocal(lpStr.Memory, lpStr.Size, false))

print'Ansi string:'
print(readStringLocal(lpStr.Memory, lpStr.Size))

print'Wide string:'
local widestring = readStringLocal(lpStr.Memory, lpStr.Size, true)  -- this converts from UTF-16 (game string) to UTF-8 (CE Lua string)
print(widestring)

print"widestring == 'Cash: €5'"
print(tostring(widestring == 'Cash: €5'))  -- it's ok to compare like this

lpStr.destroy()


The second parameter to `readstring` is the maximum number of bytes read. Unless the string isn't zero-terminated, you can let this be larger than the actual string length and it'll be fine. However, if it's less than the string length, it'll only get part of the string. If you don't know how long the string is, set it to something slightly larger than what you expect the string length to be.

_________________
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
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Thu Jun 13, 2024 10:38 pm    Post subject: Reply with quote

Check the additions I put in lines and try this code.
Specifically, follow the results of "print(resultAobs1)" and see if it has the aob outputs you want.
If not, give "resultAobs1" a correct address containing "75007000650052".

Code:
[ENABLE]
{$lua}
if syntaxcheck then return end

for i=memrec.Count-1,0,-1 do
  memrec.Child[i].delete()
end

local pStatsAddress=readPointer("pStats")
local count
--------------------------------------------------
function getByteString(address, bytecount)
 local bytes = readBytes(address, bytecount, true)
 if bytes then
 local result = ""
 for i = 1, #bytes do
 if #result > 0 then result = result .. "" end
 result = result .. string.format("%02X", bytes[i]) end
 return result end
end
---------------------------------------------------

if pStatsAddress~=nil and pStatsAddress~=0 then
  print(string.format("pStats: %X", pStatsAddress))
  count = readInteger('[[pStats]+18]+40')
  if count~=nil then print(string.format("Count: %d", count)) end
end

if count==nil then ShowMessage('Invalid pointer; refresh pointer and try again!')
elseif count <=0 then ShowMessage('No items found.')
elseif count >1000 then ShowMessage('Too many items; wrong pointer? Refresh pointer and try again!')
else
  AddressList.List.beginUpdate()
  for i=0, count do
    local iEntryLen = readInteger('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+10')
    -------------------------------------------------------------------------------------
    local addr1 = getAddress('[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+14')
    local resultAobs1 = getByteString(addr1, 10)
    -- getByteString(addr1, 80) --> It is possible to query the word you are looking for in the longer aobs signature. Just increase the byte.
    if resultAobs1~=nil then print(resultAobs1) end -- Check out what's in the results and see if it's what you're looking for!
    -------------------------------------------------------------------------------------
    if iEntryLen~=nil and iEntryLen > 11 and iEntryLen <35 then
     ------------------------------------------------------------------------------------
     if string.find(resultAobs1,"75007000650052") or string.find(resultAobs1,"52006500700075") then -- 75007000650052 = upeR .. 52006500700075 = Repu
     ------------------------------------------------------------------------------------
      local mr = AddressList.createMemoryRecord()
      mr.description = 'Stats['..(i)..']'
      mr.Type = vtString
      mr.String.Size = 64
      mr.String.Unicode = true
      mr.Address = '[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+28]+14'
      mr.Color = 0x0000FF
      mr.appendToEntry(memrec)

      local mrchild = AddressList.createMemoryRecord()
      mrchild.description = 'iRelationshipValue'
      mrchild.Type = vtDword --vtSingle
      mrchild.ShowAsSigned = true
      mrchild.Address = '[[[[[[pStats]+18]+18]+18*'..string.format('%x',i)..'+30]+18]+20]+10'
      mrchild.Color = 0xFF0000
      mrchild.appendToEntry(mr)
     end
    end
  end
  AddressList.List.endUpdate()
end
{$asm}

[DISABLE]
{$lua}
if syntaxcheck then return end
AddressList.List.beginUpdate()
for i=memrec.Count-1,0,-1 do
  memrec.Child[i].delete()
end
AddressList.List.endUpdate()
{$asm}

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Csimbi
I post too much
Reputation: 97

Joined: 14 Jul 2007
Posts: 3327

PostPosted: Fri Jun 14, 2024 12:20 pm    Post subject: Reply with quote

ParkourPenguin wrote:

Code:
local widestring = readStringLocal(lpStr.Memory, lpStr.Size, true)  -- this converts from UTF-16 (game string) to UTF-8 (CE Lua string)


This was a key information. I did not know the UTF-16 becomes UTF-8 internally.
Thank you!

AylinCE wrote:
Check the additions I put in lines and try this code.

I just copy-pasted it 'as is'.
It dumped a bunch of hex codes and built the structure as expected.
Here is a sample:
Code:
Count: 541
4D006900730073006900
460075006E0064007300
460075006E0064007300
5400610073006B004400
54007200610076006500
54007200610076006500
55007000670072006100
4D006500630068005400
4D006500640054006500
45007800700065007200
45007800700065007200
44006900660066006900
53006800690070005400
4D006500630068004200
42006100720072006100

I got 55 entries in the table.
I have no idea how many there should be.
Thank you!
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
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
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