 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
ByTransient Expert Cheater
Reputation: 5
Joined: 05 Sep 2020 Posts: 240
|
Posted: Sat Jan 30, 2021 5:03 pm Post subject: How can we improve existing code? |
|
|
The code design below works fine for a single result.
But it doesn't work when there is more than one result with the same name.
Example; If "sAobs" finds multiple results, it concentrates on the first result and possibly gives "nil".
But if "sAobs" finds a single result, the change of that result is successful.
| Code: | function ScanAndReScan(sAob,vDouble,nLength,sOffset)
if ((type(sAob)=='string' and #sAob > 1) and type(vDouble)=='number' and type(nLength)=='number') then
local sPattern,vPattern = sAob:gsub("[^%x%?]+",""),doubleToByteTable(vDouble); -- clean AoB from any unneeded character; converts Double to bytes;
local sOffset = ((#sPattern % 2 == 0) and (type(sOffset)=='number' and sOffset or (#sPattern // 2)) or error('pattern is incorrect')); -- read bytes starting offset;
local sAobs = AOBScan(sPattern); -- yes memscan is faster, but I'm lazy.
if (sAobs) then
-- local vAobs = AOBScan(readBytes(sAobs[0]..'+'..sOffset,8)); -- New scan for the double value; thought the bytes after the aob represent double, but I see we need to format it;
local vAobs = AOBScan(unpack(doubleToByteTable(readString(tonumber(sAobs[0],16)+sOffset,nLength)))); -- converts address from base16 to base10 and adds X offset, reads nLength from given address and converts to double (returns table contains double bytes); unpack the table and scans the double bytes;
--print('sAOB found @:',sAobs[0],' - found targer double count :', (vAobs and vAobs.count or 'nil'));
showMessage('sAOB found @:',sAobs[0],'\nReplace Code Count :', (vAobs and vAobs.count or 'nil'));
if (vAobs) then
for i=0,vAobs.count-1 do -- there's might be lot's of results, including of memory areas you maybe wouldn't want to change
writeBytes(vAobs[i],vPattern); -- writes the double value given after it was converted to bytes...
--print("Modified address @:",vAobs[i]);
end
vAobs.destroy(); -- cleanup
end
sAobs.destroy();
end
end
end |
Is there a solution to search multiple results of "sAobs" (Double) and replace them all in order?
Thanks in advance for the inserts and ideas.
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4711
|
Posted: Sat Jan 30, 2021 11:39 pm Post subject: |
|
|
Iterate over sAobs the same way you do vAobs: wrap it all in a for loop and replace sAobs[0] with sAobs[loopvar].
Other stuff:
- Lua is a scripting language. It doesn't have strong typing by design. Don't try to make it yourself unless you have good reason to.
- Short circuiting and/or operators is nice one time. Start nesting it and it quickly becomes an eye sore.
- Pass a relevant protectionflags argument on both aobscans and relevant alignment arguments on the scan for the double (maybe the string too, if you can spot a pattern). Look up documentation for "AOBScan" in celua.txt.
- You don't need parenthesis around the conditional expressions in if statements or around and/or expressions.
- "AOBScan(unpack(doubleToByteTable(readString(tonumber(..." is a little dense. You might want to do some error checking here too (e.g. if readString returns a string Lua can't convert to a number).
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
ByTransient Expert Cheater
Reputation: 5
Joined: 05 Sep 2020 Posts: 240
|
Posted: Sun Jan 31, 2021 3:25 am Post subject: |
|
|
Again, you explained the situation to the finest detail.
I hope that your disciplined state doesn't tire you.
I stuck with the last point you mentioned and stopped editing the advice code above.
Below I started an incomplete and messy code.
Instead of adding "for", I added 2 "memo" to the code below.
I wanted to see what would happen one by one.
The code works, but I can't make it shorter or remove the extra statements.
For this reason, it seems that I will add the code to Trainer as it is.
| Code: | if kform then form.destroy() kform = nil end
kform = createForm()
kform.Position = poDesktopCenter
kform.Width = 310
kform.Height = 250
local km1=createMemo(kform)
km1.Height=230 km1.Width=140 km1.Left=10 km1.Top=10
km1.WordWrap=false km1.ScrollBars="ssAutoBoth"
local km2=createMemo(kform)
km2.Height=230 km2.Width=140 km2.Left=160 km2.Top=10
kmtimer=createTimer(kform) kmtimer.Interval=300 kmtimer.Enabled=false
function getByteString11(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
function string.fromhex133(str1)
str1 = str1:gsub("%s+", "")
str1 = string.gsub(str1, "%s+", "")
return (str1:gsub('..', function (cc)
return string.char(tonumber(cc, 16)) end))
end
function byteTableToAobString(t)
for k,v in ipairs(t) do
t[k] = ('%02X'):format(v)
end
return table.concat(t, ' ')
end
function doublers11(str111)
newvalue = str111
newvalue = tonumber(newvalue)
if not newvalue then return end -- if not a number we're done
newvalue = doubleToByteTable(newvalue) -- alternatively
newvalue = byteTableToAobString(newvalue)
str111=('%s'):format(newvalue, newvalue)
return str111
end
-----------------------
local cnts1=""
local repto=""
local rss3=""
local n2=0
local good=0
local n1=0
function adres11Replace()
cnts1=km2.Lines.Count
if good==cnts1 then
kmtimer.Enabled=false
showMessage("Total "..n2.." code change successful.");
else
rsd1=doublers11(km2.Lines[good])
print("rsd1 - "..rsd1)
good=good+1
kmtimer.Enabled=false
local rs3=AOBScan(rsd1)
if(rs3 == nil) then
showMessage("Double search not found!");
else
for n=0,rs3.Count-1 do
if autoAssemble(rs3[n]..":\ndb "..repto) then kmtimer.Enabled=true end end
n1=rs3.Count - 1
n2=n2 + n1
object_destroy(rs3);
end
end
end
kmtimer.OnTimer=adres11Replace
function getline()
for i = 0, km1.Lines.Count do
local caption = km1.Lines[i]
if caption then
x=km2.Lines.Text
z = caption
if string.find(x, "%f[%d]"..z.."%f[%D]") ~= nil then
else
km2.Lines.Add(caption)
if i==km1.Lines.Count then
cnt1=km2.Lines.Count
good=0 adres11Replace() end
end
end
end
end
-------------------------------
function adres11(from,cnt2,cnt3)
n2=0
good=0
local sl = AOBScan(from);
if(sl == nil) then
showMessage("No code found!");
else
j = stringlist_getCount(sl);
for i = 1, j do
rs1=getByteString11(stringlist_getString(sl,i-1), 60)
str1=string.sub(rs1, cnt2, cnt3) --print("rs2 - "..str1)
rss3=(string.fromhex133(str1))
km1.Lines.Add(rss3)
if km1.Lines.Count==j then
showMessage("Current Code Found:: "..j.."\nClick to OK - Format and Replace..");
getline()
object_destroy(sl); end
end
end
end
function onReplaceStart()
km1.Lines.Text="" km2.Lines.Text=""
adres11("73 61 6C 65 73 4C 6F 67 44 75 72 61 74 69 6F 6E 22 3A ?? ?? ?? ?? ?? ?? ?? ?? ?? ??",54,83)
repto="00 00 00 00 00 C1 82 40"
end
function onReplaceStart() |
I think it tells you what I wanted to do, this is complicated, long coding.
|
|
| Back to top |
|
 |
daspamer Grandmaster Cheater Supreme
Reputation: 54
Joined: 13 Sep 2011 Posts: 1588
|
Posted: Mon Feb 01, 2021 11:27 am Post subject: |
|
|
@ParkourPenguin, I wrote the code some time ago, its functionality is to scan for a unique aob, extract a value located at X offset, rescan for that value and replace it with additional given value.
post
Most of the compares, are simply fool-proof just to avoid errors and so..
@ByTransient, If you could elaborate a bit more, would be prefect.
Now if we look at the function
| Code: | | ScanAndReScan(sAob,vDouble,nLength,sOffset) |
We're scanning for a unique array of bytes(in this case, it seems not so unique?)
Extract a value at some offset, then scan for the value and replace it.
So are you suggesting, that the unique aob, may return several results, of each having a different value?
So for instance you have an aob like this
| Code: | | 00 01 02 03 04 05 06 07 09 ?? ?? ?? ?? ?? ?? ?? ?? |
And your offset is 10h(-> ?? ?? ?? ?? ?? ?? ?? ??)
Each scan result of the given can have a different value (e.g 10.0, 50.0, 100.0 ....)
So question is, do you plan to change all of the possible values with the very same vDouble that is supplied?
If so, you could do, goo through all results, extract value from each and re-scan and replace, better go with memscan.
| Code: | function ScanAndReScan(sAob,vDouble,nLength,sOffset)
if ((type(sAob)=='string' and #sAob > 1) and type(vDouble)=='number' and type(nLength)=='number') then
local sPattern,vPattern = sAob:gsub("[^%x%?]+",""),doubleToByteTable(vDouble); -- clean AoB from any unneeded character; converts Double to bytes;
local sOffset = ((#sPattern % 2 == 0) and (type(sOffset)=='number' and sOffset or (#sPattern // 2)) or error('pattern is incorrect')); -- read bytes starting offset;
local sAobs = AOBScan(sPattern); -- yes memscan is faster, but I'm lazy.
local vMark = {} -- store values that were already found...
if (sAobs) then
for i=0,vAobs.Count-1 do -- apply to all addresses
-- converts address from base16 to base10 and adds X offset, reads nLength from given address and converts to double (returns table contains double bytes); unpack the table and scans the double bytes;
local vStr = readString(tonumber(sAobs[i],16)+sOffset,nLength);
if (not vMark[vStr]) then -- avoid scanning for previous values
vMark[vStr] = true; -- mark...
local vAobs = AOBScan(unpack(doubleToByteTable(vStr)));
--print('sAOB found @:',sAobs[0],' - found target double count :', (vAobs and vAobs.count or 'nil'));
if (vAobs) then
for i=0,vAobs.count-1 do -- there's might be lot's of results, including of memory areas you maybe wouldn't want to change
writeBytes(vAobs[i],vPattern); -- writes the double value given after it was converted to bytes...
end
vAobs.destroy(); -- cleanup
end
end
end
sAobs.destroy();
end
end
end |
And then you can use it like you previously did,
| Code: | | ScanAndReScan("73 65 6C 65 63 74 5F 49 74 65 6D 5F 31 30 32 3A 22",15221889784,11); -- change double target to 15221889784; |
The main drawback I can see while doing so, is that you're basically changing ALL possible (extracted) values into the very same value.
A different solution for this would be, to supply a table as vDouble, for this script.
| Code: | function ScanAndReScan(sAob,vDouble,nLength,sOffset)
if ((type(sAob)=='string' and #sAob > 1) and vDouble and type(nLength)=='number') then
local sPattern,vPatternIsTable,vPattern = sAob:gsub("[^%x%?]+",""),type(vDouble)=='table';
if (vPatternIsTable) then -- convert to a table...
vPattern = {};
for key,value in pairs(vDouble) do
vPattern[tostring(key)] = doubleToByteTable(value); -- convert keys to string just in case...
end
else -- same value for all possible extracted values
vPattern = doubleToByteTable(vDouble);
end
local sOffset = ((#sPattern % 2 == 0) and (type(sOffset)=='number' and sOffset or (#sPattern // 2)) or error('pattern is incorrect')); -- read bytes starting offset;
local sAobs = AOBScan(sPattern); -- yes memscan is faster, but I'm lazy.
local vMark = {} -- store values that were already found...
if (sAobs) then
for i=0,vAobs.Count-1 do -- apply to all addresses
local vStr = readString(tonumber(sAobs[i],16)+sOffset,nLength); -- extracted so we could use it to lookup...
if (not vMark[vStr]) then -- avoid scanning for previous values
vMark[vStr] = true; -- mark...
local vAobs = AOBScan(unpack(doubleToByteTable(vStr)));
--print('sAOB found @:',sAobs[0],' - found target double count :', (vAobs and vAobs.count or 'nil'));
local vPattern = vPatternIsTable and vPattern[vStr] or vPattern; -- new local variable.. does not overrides previous one...
if (vAobs) then
if (vPattern) then -- if user has specified a replacement value
for i=0,vAobs.count-1 do -- there's might be lot's of results, including of memory areas you maybe wouldn't want to change
writeBytes(vAobs[i],vPattern); -- writes the double value given after it was converted to bytes...
end
end
vAobs.destroy(); -- cleanup
end
end
end
sAobs.destroy();
end
end
end |
This way, it will change only values that are defined in vDouble table
Usage example
| Code: |
local myValues = {
["1.5"] = 15; -- change value of 1.5 to 15...
["100"] = "1000";
["5000"] = 0
}
ScanAndReScan("73 65 6C 65 63 74 5F 49 74 65 6D 5F 31 30 32 3A 22",myValues ,11);
|
This will change any specific double values to a different ones, but doing so makes this whole script logic pointless (as why not just look for that specific value..?).
If there are any other unique identifiers (e.g unique string that can describe the value or object ...), then it may sustain the dynamic that you're requesting.
A small side note:
If for instance if one of the results has a double value of 100, and you change it to 1000.
And the next result (or any afterwards...) has the value of 1000 and you want to change it to 10000, you are going to change the previous results as well to 10000,
100 AND 1000 will turn into 10000.
The order they appear is important, a quick fix would be to not use round numbers (e.g change to 1000.1).
Avoiding this altogther would require re-writing the script logic, fetching all addresses of all (extracted) values upfront, and only then write to them.
I did not test any of the scripts.
EDIT:
Silly me, added a loop and forgot to place a clean up code outside of it.
_________________
I'm rusty and getting older, help me re-learn lua.
Last edited by daspamer on Wed Feb 03, 2021 4:29 am; edited 1 time in total |
|
| Back to top |
|
 |
ByTransient Expert Cheater
Reputation: 5
Joined: 05 Sep 2020 Posts: 240
|
Posted: Mon Feb 01, 2021 4:19 pm Post subject: |
|
|
Code and "Double value" will not encounter other codes.
Scanned "aob" will find different results.
Example;
Unit code, '"_189_190": 1553881764155,' = double replace: 1400000004155.
Or for Booster; '"powerup_mfc": 1611266787607,' = double replace: 1700000087607
Scanning and change will continue in this order when needed.
But at the end of the change, the code gives an error.
I guess I'll just ignore him.
| Code: | sAOB found @: 27FDA71A577 - found target double count : 122
Error:Access violation |
Thanks for reworking this code.
To me this is worth more than +1.
|
|
| Back to top |
|
 |
daspamer Grandmaster Cheater Supreme
Reputation: 54
Joined: 13 Sep 2011 Posts: 1588
|
Posted: Wed Feb 03, 2021 4:30 am Post subject: |
|
|
Whoops, I see why you get the access violation.
I didn't move the sAobs.destroy() outside the loop.
I've edited the post above with the fix.
It should not throw an error now.
_________________
I'm rusty and getting older, help me re-learn lua. |
|
| Back to top |
|
 |
ByTransient Expert Cheater
Reputation: 5
Joined: 05 Sep 2020 Posts: 240
|
Posted: Wed Feb 03, 2021 8:28 am Post subject: |
|
|
| Code: | if (sAobs) then
for i=0,vAobs.Count-1 do -- <<< I think there's an error here, I changed it. vAobs >> sAobs
local vStr = readString(tonumber(sAobs[i],16)+sOffset,nLength); -- extracted so we could use it to lookup...
if (not vMark[vStr]) then -- avoid scanning for previous values
vMark[vStr] = true; -- mark...
local vAobs = AOBScan(unpack(doubleToByteTable(vStr))); --<<< "vAobs" is defined here. |
I see that you understand the general rationale for what I want to do.
But before I used your code, I did "Double" scans and listed them in CE.
I ran your code and when the scan was complete, I saw that some of the "Double" values I listed in CE had changed.
Let me explain below what I want to do with the code I've collected;
1) Numbers will be taken by string code.
2) The relevant value will be extracted from the string code and listed (km1).
3) The list will be compared and the same numbers will be transferred to the other section as a single result (km2)
4) Each digit in km2 will be searched for in "Double" (Note; each digit makes 2-10 results) and changed.
5) The km2 list will repeat the cycle in item 4, respectively.
The code below accomplishes this with a lot of unnecessary functions.
Your code also accomplishes some of it, but it only does it right for a scanned code.
Example; When I activate a different code with the second button it gives a "nil" result.
Everyone's coding logic is based on their own knowledge, I have insufficient knowledge of editing your code.
Here is the code I used before;
| Code: | ------------------------------------------
if kform then kform.destroy() kform = nil end
kform = createForm()
kform.Position = poDesktopCenter
kform.Width = 310
kform.Height = 250
local km1=createMemo(kform)
km1.Height=230 km1.Width=140 km1.Left=10 km1.Top=10
km1.WordWrap=false km1.ScrollBars="ssAutoBoth"
local km2=createMemo(kform)
km2.Height=230 km2.Width=140 km2.Left=160 km2.Top=10
kmtimer=createTimer(kform) kmtimer.Interval=300 kmtimer.Enabled=false
------------------------- Controls; --------
function getByteString1133(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
function string.fromhex1133(str1)
str1 = str1:gsub("%s+", "")
str1 = string.gsub(str1, "%s+", "")
return (str1:gsub('..', function (cc)
return string.char(tonumber(cc, 16)) end))
end
function byteTableToAobString(t)
for k,v in ipairs(t) do
t[k] = ('%02X'):format(v)
end
return table.concat(t, ' ')
end
function doublers1133(str111)
newvalue = str111
newvalue = tonumber(newvalue)
if not newvalue then return end -- if not a number we're done
newvalue = doubleToByteTable(newvalue) -- alternatively
newvalue = byteTableToAobString(newvalue)
str111=('%s'):format(newvalue, newvalue)
return str111
end
-------------------------------- code -------
-----------------------
local cnts1133=0
local repto1133=""
local rss1133=""
local n3311=0
local n3322=0
local n3333=0
local good1122=0
function adres1133Replace()
if good1122==cnts1133 then
kmtimer1.Enabled=false
showMessage("Total "..n3333.." code change successful.");
else
kmtimer1.Enabled=false
rsd1=doublers1133(km2.Lines[good1122])
kmtimer1.Enabled=false
good1122=good1122+1
--if good1122 then
--UDF1.CELabel1.caption=("Change: "..n3311.." / "..n3322.." - Change Total: "..n3333.." - Found Code:("..good1122.." / "..cnts1133..") ");
--end
local rs3=AOBScan(rsd1)
if rs3==nil then
kmtimer1.Enabled=true
--UDF1.CELabel1.caption=("Change: "..n3311.." / "..n3322.." - Change Total: "..n3333.." - Found Code:("..good1122.." / "..cnts1133..") ");
else
n3322=rs3.Count - 1
n3311=n3322
n3333=n3322 + n3333
--UDF1.CELabel1.caption=("Change: "..n3311.." / "..n3322.." - Change Total: "..n3333.." - Found Code:("..good1122.." / "..cnts1133..") ");
for n=0,rs3.Count-1 do
if autoAssemble(rs3[n]..":\ndb "..repto1133) then kmtimer1.Enabled=true
n3311=n3311 - n
--UDF1.CELabel1.caption=("Change: "..n3311.." / "..n3322.." - Change Total: "..n3333.." - Found Code:("..good1122.." / "..cnts1133..") ");
end
end
end
object_destroy(rs3);
end
end
kmtimer1.OnTimer=adres1133Replace
function getline1133()
for i = 0, km1.Lines.Count do
local caption = km1.Lines[i]
if caption then
x=km2.Lines.Text
z = caption
if string.find(x, "%f[%d]"..z.."%f[%D]") ~= nil then
else
km2.Lines.Add(caption)
good1122=0
cnts1133=km2.Lines.Count - 1
--UDF1.CELabel1.caption=("Change: "..n3311.." / "..n3322.." - Change Total: "..n3333.." - Found Code:("..good1122.." / "..cnts1133..") ");
if i==km1.Lines.Count then
adres1133Replace()
end
end
end
end
end
-------------------------------
function adres1133(from,t01133,cnt2,cnt3)
n3311=0
good1122=0
n3333=0
n3322=0
repto1133=doublers1133(tonumber(t01133))
local sl = AOBScan(from);
if(sl == nil) then
showMessage("No code found!");
else
j = stringlist_getCount(sl);
for i = 1, j do
rs1=getByteString1133(stringlist_getString(sl,i-1), 60)
str1=string.sub(rs1, cnt2, cnt3) --print("rs2 - "..str1)
rss1133=(string.fromhex1133(str1))
km1.Lines.Add(rss1133)
if km1.Lines.Count==j then
getline1133() end
end
end
object_destroy(sl);
end
-----------------------------------------------------------
--Note: The scanning code is provided as an example.
adres1133("22 5F 65 78 70 69 72 65 73 22 3A ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??",1500000504489,33,71)
--str1=string.sub(rs1, 33, 71) = ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? |
adres1133() , Result (25); (km1.Lines.Text)
1640714990000
1640714990000
1609265279101
1610388567000
1609265390000
1610388590000
1640714990000
1609265279000
1640713762000
1612017752000
1612620813000
1612102413000
1614607952000
1643551952000
1643552013000
1643552013000
1614607952000
1612102413000
1643552149000
1612102352000
1643551952000
1612019613000
1612102353000
1643552013000
1643552013000
(Filtering to avoid redialing the same code;)
getline1133(), Result (17); (km2.Lines.Text)
1640714990000
1609265279101
1610388567000
1609265390000
1610388590000
1609265279000
1640713762000
1612017752000
1612620813000
1612102413000
1614607952000
1643551952000
1643552013000
1643552149000
1612102352000
1612019613000
1612102353000
"Adres1133Replace ()" will search for all codes in the "km2" list by formatting them as "Double", replacing them in order and then switching to the next code.
I hope I could explain what I wanted to do.
Your code does this the first time, but ("type") gives the other button and "nil" in another code.
Why such a coding request?
Some items in the game have a time limit (hour or day) assigned against their own code (String), when I extract these codes with text scan and scan them with Double (4-10 results if active, 2-4 results if passive) 2-10 I find results between, and I reduce or increase these time frames as required.
I hope you didn't get confused.
Thanks for your follow up.
|
|
| 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
|
|