| 
			
				|  | Cheat Engine The Official Site of Cheat Engine
 
 
 |  
 
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Sun Jun 09, 2024 1:56 pm    Post subject: |   |  
				| 
 |  
				| 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
   
 Thank you!
 |  |  
		| Back to top |  |  
		|  |  
		| AylinCE Grandmaster Cheater Supreme
 
  Reputation: 37 
 Joined: 16 Feb 2017
 Posts: 1528
 
 
 | 
			
				|  Posted: Mon Jun 10, 2024 8:00 am    Post subject: |   |  
				| 
 |  
				| 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
 | 
 _________________
 
 |  |  
		| Back to top |  |  
		|  |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Mon Jun 10, 2024 2:57 pm    Post subject: |   |  
				| 
 |  
				| Erm, thanks?   
 I understand the bottom part, but that function specialcrt(str) on top looks like chinese to me
   
 
  	  | 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 |  |  
		|  |  
		| AylinCE Grandmaster Cheater Supreme
 
  Reputation: 37 
 Joined: 16 Feb 2017
 Posts: 1528
 
 
 | 
			
				|  Posted: Mon Jun 10, 2024 6:30 pm    Post subject: |   |  
				| 
 |  
				| 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.
   ( 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))
 | 
 _________________
 
 
 Last edited by AylinCE on Mon Jun 10, 2024 10:18 pm; edited 1 time in total
 |  |  
		| Back to top |  |  
		|  |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Mon Jun 10, 2024 8:22 pm    Post subject: |   |  
				| 
 |  
				| Fucking hell. Please edit that post and just leave an ellipsis after a bit. i.e. `[[]]):gsub("u0100","Ā"):gsub("u0101","ā"):gsub("u0102","Ă"):gsub("u0103","ă")...` 	  | AylinCE wrote: |  	  |  	  | Code: |  	  | <single line of 6538 characters> | 
 | 
 
 If you must use gsub like that, replace it with a table lookup:
 
 There are other functions in CE's Lua API. e.g. `wideStringToByteTable` 	  | Code: |  	  | local t = { u0100 = "Ā",
 u0101 = "ā",
 u0102 = "Ă",
 u0103 = "ă",
 u0104 = "Ą",
 u0105 = "ą",
 --...
 }
 
 function foo(s)
 return s:gsub('(u%d%d%d%d)', t)
 end
 
 | 
 _________________
 
 I don't know where I'm going, but I'll figure it out when I get there. |  |  
		| Back to top |  |  
		|  |  
		| AylinCE Grandmaster Cheater Supreme
 
  Reputation: 37 
 Joined: 16 Feb 2017
 Posts: 1528
 
 
 | 
			
				|  Posted: Mon Jun 10, 2024 10:23 pm    Post subject: |   |  
				| 
 |  
				| Replaced with a different format! 
 @Csimbi, I got scolded by @Parkour, because of you!
    _________________
 
 |  |  
		| Back to top |  |  
		|  |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Wed Jun 12, 2024 7:41 am    Post subject: |   |  
				| 
 |  
				|  	  | ParkourPenguin wrote: |  	  | Fucking hell. | 
 Have not heard that one before from you
   
 
  	  | 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!    | 
 Sorry
  |  |  
		| Back to top |  |  
		|  |  
		| AylinCE Grandmaster Cheater Supreme
 
  Reputation: 37 
 Joined: 16 Feb 2017
 Posts: 1528
 
 
 | 
			
				|  Posted: Wed Jun 12, 2024 10:55 am    Post subject: |   |  
				| 
 |  
				|  	  | 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
 _________________
 
 |  |  
		| Back to top |  |  
		|  |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Wed Jun 12, 2024 11:17 am    Post subject: |   |  
				| 
 |  
				|  	  | 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 |  |  
		|  |  
		| AylinCE Grandmaster Cheater Supreme
 
  Reputation: 37 
 Joined: 16 Feb 2017
 Posts: 1528
 
 
 | 
			
				|  Posted: Wed Jun 12, 2024 12:37 pm    Post subject: |   |  
				| 
 |  
				| 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;
 
 I format it 7 bytes wide;
 
  	  | Code: |  	  | iEntryLen2 = getByteString(aa2, 7) print(iEntryLen2)
 | 
 The result it gave me was;
 E8030000010000
 _________________
 
 |  |  
		| Back to top |  |  
		|  |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Wed Jun 12, 2024 2:59 pm    Post subject: |   |  
				| 
 |  
				| This goes through a long list of conversions 	  | 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?
 | 
 
 Lua string- an array of 8-bit values (including 0). Entirely encoding-agnostic.
C string- almost the same as a Lua string, but it terminates early at 0 bytes. e.g. `print'12\x0034'` only prints "12"
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
WideString- basically UTF-16
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 |  |  
		|  |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Thu Jun 13, 2024 12:27 pm    Post subject: |   |  
				| 
 |  
				|  	  | 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 |  |  
		|  |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Thu Jun 13, 2024 1:31 pm    Post subject: |   |  
				| 
 |  
				| 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. 	  | 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.
 | 
 
  	  | 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 |  |  
		|  |  
		| AylinCE Grandmaster Cheater Supreme
 
  Reputation: 37 
 Joined: 16 Feb 2017
 Posts: 1528
 
 
 | 
			
				|  Posted: Thu Jun 13, 2024 10:38 pm    Post subject: |   |  
				| 
 |  
				| 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}
 | 
 _________________
 
 |  |  
		| Back to top |  |  
		|  |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Fri Jun 14, 2024 12:20 pm    Post subject: |   |  
				| 
 |  
				|  	  | 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 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |  |