[REQUEST] Tap Ninja

Ask about cheats/tables for single player games here
User avatar
deuxdoom
Novice Cheater
Novice Cheater
Posts: 18
Joined: Mon Aug 20, 2018 2:58 am
Reputation: 2

Re: [REQUEST] Tap Ninja

Post by deuxdoom »

april 6 update, not working

User avatar
BabyGroot
Table Makers
Table Makers
Posts: 1337
Joined: Sun Mar 29, 2020 1:39 pm
Reputation: 2177

Re: [REQUEST] Tap Ninja

Post by BabyGroot »

deuxdoom wrote:
Tue Apr 12, 2022 6:47 pm
april 6 update, not working
I Test
13 April 2022
wed 09:42 AM
Tap Ninja v2.7.0
Build 8546209
CT works fine.

josh2tk89
Cheater
Cheater
Posts: 25
Joined: Fri Nov 20, 2020 5:29 am
Reputation: 2

Re: [REQUEST] Tap Ninja

Post by josh2tk89 »

Same here. Not working.

User avatar
BabyGroot
Table Makers
Table Makers
Posts: 1337
Joined: Sun Mar 29, 2020 1:39 pm
Reputation: 2177

Re: [REQUEST] Tap Ninja

Post by BabyGroot »

josh2tk89 wrote:
Wed Apr 13, 2022 5:00 am
Same here. Not working.
Is your cheat engine already setting as I wrote?

Setting CE:
1. Tab Debugger Options
2. Debugger Method Set (Use VEH Debugger)
3.OK

here for video 13/04-2022 Test Table

josh2tk89
Cheater
Cheater
Posts: 25
Joined: Fri Nov 20, 2020 5:29 am
Reputation: 2

Re: [REQUEST] Tap Ninja

Post by josh2tk89 »

ReskyAW wrote:
Wed Apr 13, 2022 7:17 am
Is your cheat engine already setting as I wrote?
Mine is already set to VEH Debugger before and running on Cheat Engine 7.4. Still no luck
viewtopic.php?f=4&t=19544
I found this one is working.

User avatar
BabyGroot
Table Makers
Table Makers
Posts: 1337
Joined: Sun Mar 29, 2020 1:39 pm
Reputation: 2177

Re: [REQUEST] Tap Ninja

Post by BabyGroot »

josh2tk89 wrote:
Wed Apr 13, 2022 8:16 am
ReskyAW wrote:
Wed Apr 13, 2022 7:17 am
Is your cheat engine already setting as I wrote?
Mine is already set to VEH Debugger before and running on Cheat Engine 7.4. Still no luck
I don't know what happened, you can see my video, it's a cheat table that I downloaded from the forum and used (without editing the cheat table). the latest version of the game at this time.

User avatar
tssj
Noobzor
Noobzor
Posts: 8
Joined: Sat Apr 16, 2022 6:07 am
Reputation: 6

Re: [REQUEST] Tap Ninja

Post by tssj »

ReskyAW wrote:
Sat Mar 19, 2022 5:10 pm

Code: Select all

Game Name : Tap Ninja - Idle Game
Game Vendor : Steam
Game Version/BuildID : v2.6.5 / 8447898
Game Last Update release : 28 March 2022
Game Process : Tap Ninja.exe
CE Version : 7.4
Game Release date : 17 Mar, 2022
CE Version : 7.4
We have not tested with all values, but we have confirmed the operation of Gold, Elixir, Amber, Key, and Star values.

Game version is v2.7.0 which was updated today
Build 8566850.
It has perfectly worked.
Amazing table!
Thanks!
Last edited by tssj on Thu Apr 21, 2022 1:09 pm, edited 1 time in total.

Glameth
What is cheating?
What is cheating?
Posts: 1
Joined: Mon Apr 18, 2022 7:58 pm
Reputation: 0

Re: [REQUEST] Tap Ninja

Post by Glameth »

Narguun wrote:
Thu Mar 24, 2022 7:06 am
Hello. Tell me what and where I need to fix to make it work ...
Spoiler
Image
Spoiler
Image
Well, or lay out an already corrected version. Thanks.
i have the same issue with player data cant find this one "UpgradeManager:Update+1c: 0F B6 80 69 04 00 00 - movzx eax,byte ptr [rax+00000469]"
v2.7.2

User avatar
BabyGroot
Table Makers
Table Makers
Posts: 1337
Joined: Sun Mar 29, 2020 1:39 pm
Reputation: 2177

Re: [REQUEST] Tap Ninja

Post by BabyGroot »


Baltus
What is cheating?
What is cheating?
Posts: 2
Joined: Wed Apr 27, 2022 4:33 pm
Reputation: 0

Re: [REQUEST] Tap Ninja

Post by Baltus »

First showing me this
//Here is full text
Spoiler
--[[--------------------------------------------------------------------------------
-- Forms - Save strings as temp files, then load using createFormFromFile()
--------------------------------------------------------------------------------]]

local stringFormMonoClass = [==========[<?xml version="1.0" encoding="utf-8"?>
<FormData>
<formMonoClass Class="TCEForm" Encoding="Ascii85">/yTK^8${c!?7msfX.9L%MdIQc2%!i#a/iSfwG[w3Ysw8Y[Kxk5cW0K{aT8zrG5QUV]XxAk]V}0BB[_{Vs2AqX#xv[:OOyz4.If^1_L48mym]Ld2VgSleeO*UPkS@:9=bb=Knd-{Fwg6!XwK_6R]WT,izTxk+!F}][G^4i7DsGpKdC!im?-UB)-%rDskPUQF)Rzc]O6B[^z_1jKxFN;3I7ftCcx#cPvI2B]=2@,6K60%kK1Inq+.g}B+HlEQo:GCJB^HvLD=hC/st1bW!#ougl#/+QCofy@d(g#(?4h)n8Fz+i)?5xP$o*@=dcxr)_y%yGnV1$nxVZO[j:r2!YoA0+:wJL^qMWa,vD*+B#@Aa^}w.+i9/DmKABOH)-/:7OY#V[,0t=5X%AnZNZI@*4P)qUochB[2IovkhHMj}pgGSwG;$,pf+DV1m(P:6eYFu^E_4i5L4sm06/=9(J7sgHB8O!u?#{an(pMPbnmp0mu^idQi:$okj^1k1uL#v47W@Fp/*YhfEm]%Ci;ljoM.XY223(DY6Rw1U16MK{7p_0/,oR*QnI[Fx^!y8#j2ckVB]M#Nx8-_c+WC%64uvTTI4@LHr!jItz$,W392+Q{fnI+0ZtCx}tJD9YPG3]{w.DidKFjDj=a(KvF(!Ybq*}ChFDvxykE{+J#tY*OFjmoR(+2mnbeOfW6L(G}VH6iWtST43*e09*7_ViOIcO=vZQlX[;]P:XP:O6M/=H[=ynj_%^B#R%zdd94B?*STJO,#0_F?tQwd/1zU0A=]i8tY!aETBz0@KQl]EvYNz8vptiL[Ikvlkeh]!QcAwJIEFM-@Dm0,of/B6lzLjd8rM.Gnrpfh[pd*BDc8ZD{3.LaY.#?7HvWhx2*km@.8k@?mT2K5-1RP/@sV)KQkKCt%8mdvjf.RWoE7?]4qdK5r791pEnq06lk%U@FE0#]DJXJVY@=G0$jxo,z).[8j,RK1M0c81DiaKt9iB)TJ^frZR-yyca?(fKZ]Vg)1UN1(9oZN*#C}cZbo/q1+}b-]OP]=bq+tqn,{9S:jv5gov0-xD/b,@6QeXDuMD?87SU{rt4Hrj)e$Es?Lbf0CIUI(nQD0J]K73r}V?b/@f8mm,,6(sDjPbLj]EI^7T4dCGHNGn{Yav,s/u:/3H}_92;K+QF?o7A!IP*hw:FG6p.l-9ssiZVrCF%)tkrZjW7EQC0;Gu5)-93DF{wtVS,.rrp]v9wuiG@k1h]dr]6f0e,)[j1cvUB)p3+ZXQR5Y+IqN*U832[*Bii9Atfj5DM^1R2i),;p7,TTWtgGpCMyR#t=?cSt+w-4Ay5^,$?%1PleRCoEy*I@UNgbZD5JU:h,R1^LE((gIpcuQ6Y!Q}nmbV9Cn%pG5/$YWLSPU?]TWVY8/d*XGbEDX9GFx_.#z,L</formMonoClass>
</FormData>
]==========]

local stringFormMonoImage = [==========[<?xml version="1.0" encoding="utf-8"?>
<FormData>
<formMonoImage Class="TCEForm" Encoding="Ascii85">#goBu):ZT+Wtl^dlQI).N^(5n(hQF{X^MQJn@1eo5fn$ZHIXe;RtGr4190F.cqtCN1hVAXjWcD*0l3*K^?z^hx4+qE0Ksbh3I+QToQw1+QkP4f?kNSb@5lX/)jLR@IiYbP=eCTy?ZA0ZI(bMlCiZ8DJe+6*v,mF+jD,(E%sth}1CLRX$vU-f(i9$XRV@:QA!q!f%hX+b6)]dyOt_prhLp]G9=zuU40V/tG9sQgs]],Y[?WW7%bqQH*RxO9*We0CaVdE@Zgdl/@M}s?b/WI$4H*R(bICOq:vG*bM5b2J?8GRcx[DbAAiUL]9lSLizG[D0JP0B(qo^2%G=}m+ra!0MJv,XL@_ZnSM_HxTV)cJhf9I9+4KLxJqx*H(z;36.k,8JMD^Qkiz#h)TZim?DT^LGY6G3@@j/pDI11cbh0/UjyJR^0G:vZE5TzyieiSvQC;a(0j_I1#Y1q]28AO^@P9DA)8H^GkPRD[5Z%y%t^HKF?{v6g?tUv!E3cP_:l]R+yV4f4v4-{wf!3Qc8fU38JaQy9#^U-{8!JCVHkhj,CSHPtPb3.lul(V3=_gdgp9Os[Rb%_?;C,WXNw,f/6f.*]R#b*wa-.kPtDstrDfs3NGb%qJ6y3fSIFkJp7HU$DGcFw09Lg7,2RjA700</formMonoImage>
</FormData>
]==========]

local stringFormMonoSearch = [==========[<?xml version="1.0" encoding="utf-8"?>
<FormData>
<formMonoSearch Class="TCEForm" Encoding="Ascii85">%}#Ei,cprUq+#;fbZc+SoAl.WE)L-l:ODn@%^B_H;xFG;($Pw03Dcw=)cVojK[8=K)V+xt2#OX6(]Y18()T9kQCj]j@g2!t@,BL!hBKq?n}$;oZUQj6IDG.}-Iu34S^z*-OOG:=#3-7}=w#W,.XJY2SC}v@!ui8=Mm%*;0k!W+AZE[22D;N{gfq9HcD41k](}+f6X}X)=S^V3[T1{XwuIh7UVDfza3G6cpegQhCL(I}P[C8Z%M(*4?n{c[tonGI]eChq(2V([du2{+:Y!liP*$[aM@)34K[A6YhYP[M4_BgZm{^s0N]eG9yPo0pQ-YgaPhlI=;L)LHR#-hX@aUDg,?MYyH*=1u/6SgYX(^.;O=qgqlY[$!j^,PGLo@_5]dHU$m5oWgFUqzgja?$}TXj.q=v2p,j0O0^25Q,=F+X4HNZt%+7;h!q8SCyQ!hb9ieqIA:yj{*G9AJ6TTSoXsm/Y{b8A#3p%0Sx;N.v/uJ5pYsb!Ui4I+!UcYHI-yZ.0toph)!jm(/d@rebD.mI^7Fm@hU@b}*t^gcI7KXfiLkhT:8F)7lQ}oCZK5t!AHL,6dKE+WDYJ3ciQssLG5QHIkRvUnd)_-KG[gY2^LD/=C8DJ-e!66Rq[QUSWF1q-LQvUJVe5aiER.rI1EAUa1W?KgS9?l+jtAI?bA6SfC,!^5Imtu*{XYpQ=pUp._T3SuABBv;0OKs}EIDV{?=FaRxKa2AVTF/=MH;c0$RNK@M]4tBgT#3p4Ce6vsF(L.Ru*?q4Ry5GjbyNh}f2zHU+u)7mRKOdwauFaTW+GlE=W,#m2Qo$Vx*7aH^JUHsnKRVYv%Ps.[153E{^;IsVN?6ZB!J#=cpwjHlWShBW+w8{$Ez7djl.5SGh-y2^Q@cj8a]vZP0k3(2Wet_S!k*?A3Zxs*4$RpwQnc54F+Em$;y7Z2zoPx/5ezhKvx[{.sVMvLPGH%9dp)DjdU{/k2U@[o@QV;Dmq.3_3k_3-9CH-j]*bPeh*!-qjr,b4Q*^;TmF)=b.jgw/,m)HG6VW?f{2q?kW3ODQiLU)Va-T!vCmfcf:X.6^!@K!?Uj8bmqB/nmTC2xJSqL$YKjcQ(G-CxgpLw}F2:Ve8_]xHgj5-[*m]4/2R8xo17o*1NjEC22YGWpMhe@g}$S,@*UdDtDXv@J0NMnxBO):3pe*VpgAcI)IaU{)ts*iR$7-pNw%A@8FO]TMem#f.w{vbR=CSlIBsOcR,?wg!YjWNUFojeRt/W^GWUZXboc^S/_^8p.2q#E#eaPBo?{^z!dYtB;(f8)iAt?:V_bT#(Pc]Yyfg=NM?H2suncbWi2z(mL*OTW@xT]sjj)%TR5.AF5UQE^A:VIAE*2O-zMaeztg.H;7UcPr.[BXO+aDs*K)4</formMonoSearch>
</FormData>
]==========]

local function saveForm(text)
local path = os.tmpname() -- get temp file name
local f, err = io.open(path, "w")
if f == nil then return nil, err end
f:write(text)
f:close()
return path
end

local function createFormFromString(text)
local path = saveForm(text)
local form = createFormFromFile(path)
pcall(os.remove, path)
return form
end


formMonoClassB = createFormFromString(stringFormMonoClass)
formMonoImage = createFormFromString(stringFormMonoImage)
formMonoSearch = createFormFromString(stringFormMonoSearch)


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/bootstrap.lua
--------------------------------------------------------------------------------]]
-- loadstring(loadTextFile('src/lua/util.lua'))()
-- loadstring(loadTextFile('../temp/notes.lua'))()
-- loadstring(loadTextFile('src/lua/mono.lua'))()


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/util.lua
--------------------------------------------------------------------------------]]
util = util or {}

util.loadTextFile = function (name, useTableFile)
if useTableFile then
local tableFile = findTableFile(name)
if not tableFile then return nil, 'Unable to open table file "'..tostring(name)..'"' end
local ss = createStringStream()
ss.Position = 0 -- recommended on wiki: [Link]
ss.CopyFrom(tableFile.Stream, 0)
local text = ss.DataString
ss.destroy()
return text
else
local path = getMainForm().openDialog1.InitialDir..name
local f, err = io.open(path, "r")
-- fall back to table file if disk file error (doesn't exist)
if f == nil then return loadTextFile(name, true) end
local text = f:read("*all")
f:close()
return text
end
end

--[[
Save a string to a text file. If useTableFile is true it will be saved as
a TableFile. The directory should be where the cheat file is, it is the
initial directory for the dialog when you are saving your cheat table.
--]]
util.saveTextFile = function(name, text, useTableFile)
if useTableFile then
local tf = findTableFile(name)
if tf ~= nil then
tf.delete()
tf = nil
end
tf = createTableFile(name)
local ss = createStringStream(text)
tf.Stream.CopyFrom(ss, 0)
ss.destroy()
return true
else
local path = getMainForm().saveDialog1.InitialDir..name
local f, err = io.open(path, "w")
if f == nil then return nil, err end
f:write(text)
f:close()
return true
end
end

--[[
For mono symbols, you have to surround them in quotes for use in AA
]]
function util.safeAddress(s)
local tbl = {}
for a in string.gmatch(s, "([^+]+)[+]?") do table.insert(tbl, a) end
local result = '"'..tbl[1]..'"'
if #tbl > 1 then result = result..'+'..tbl[2] end
return result
end

function util.split(s, separator)
local tbl = {}
for str in string.gmatch(s, "([^"..separator.."]+)") do table.insert(tbl, str) end
return tbl
end

function util.trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end

--[[
Pretty-print serialize the passed object and return the results
as a string. This does nice indenting and follows metatables. It
is not guaranteed to provide the same object back if the string is
loaded because it just replaces circular references with a string
among other things. It does try to keep tables/arrays on one line
if there is room (120 characters).
--]]
function util.pretty(value, funcs, indent, done, stack)
indent = indent or 0
funcs = funcs or {}
done = done or {}
stack = stack or { {value=value} } -- initialize with passed value, no key

-- if a 'userdata', use metatable
local l = value
if type(value) == "userdata" then
l = getmetatable(value)
end

if type(l) == "table" then
-- if we've already serialized the table, return string representation
-- to avoid self-referencing in recursion. Only the first serialization
-- will have the full serialized string
if done[l] then return tostring(l) end
done[l] = true

local list = {}

-- here we return "{", the values, and "}"
if (#l > 0) then
-- if we have a count ('#'), then it's just an array of values
for i,v in ipairs(l) do
table.insert(list, util.pretty(v, funcs, indent + 2, done, stack))
end
else
-- no count, so either empty or object with key/value
-- first we sort the keys
local keys = {}
for k,v in pairs(l) do table.insert(keys, k) end
table.sort(keys)

local last = {key = "UNKNOWN", value = "NONE"}
table.insert(stack, last)
for i,k in ipairs(keys) do
local propValue = value[k]
last.key = k
last.value = value[k]
for j,f in ipairs(funcs) do
local returnValue = f(value, k, value[k], stack, indent)
if returnValue ~= nil then
propValue = returnValue
break
end
end
table.insert(list, string.format("%s = %s", tostring(k), util.pretty(propValue, funcs, indent+2, done, stack)))
end
table.remove(stack, #stack)
end

-- now we find the total size, add 200 if there are line breaks
local size = 0
for i,v in ipairs(list) do
size = size + string.len(v) + 2
if string.find(v, "\r\n") then
size = 200
break;
end
end
-- if it's small enough, join with commas
if (size < 120) then
local result = {"{ "}
for i,v in ipairs(list) do
if i > 1 then table.insert(result, ", ") end
table.insert(result, v)
end
table.insert(result, " }")
return table.concat(result);
else
local indentString1 = string.rep(" ", indent)
local indentString2 = string.rep(" ", indent + 2)
local result = {"{\r\n"}
for i,v in ipairs(list) do
table.insert(result, indentString2)
table.insert(result, v)
if (i < #list) then table.insert(result, ",") end
table.insert(result, "\r\n")
end
-- table.insert(result, indentString)
table.insert(result, indentString1)
table.insert(result, "}")
return table.concat(result);
end
end

if type(value) == "string" then
return string.format("\"%s\"", value)
end
return tostring(value)
end



--[[
Values and functions used by util.serialize(t)
---]]

local oddvals = {[tostring(1/0)] = '1/0', [tostring(-1/0)] = '-1/0', [tostring(-(0/0))] = '-(0/0)', [tostring(0/0)] = '0/0'}

local kw = {['and'] = true, ['break'] = true, ['do'] = true, ['else'] = true,
['elseif'] = true, ['end'] = true, ['false'] = true, ['for'] = true,
['function'] = true, ['goto'] = true, ['if'] = true, ['in'] = true,
['local'] = true, ['nil'] = true, ['not'] = true, ['or'] = true,
['repeat'] = true, ['return'] = true, ['then'] = true, ['true'] = true,
['until'] = true, ['while'] = true}

local getchr = function(c)
return "\\" .. c:byte()
end

local make_safe = function(text)
return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr)
end

local write = function(t, memo, rev_memo)
local ty = type(t)
if ty == 'number' then
t = format("%.17g", t)
return oddvals[t] or t
elseif ty == 'boolean' or ty == 'nil' then
return tostring(t)
elseif ty == 'string' then
return make_safe(t)
elseif ty == 'table' or ty == 'function' then
if not memo[t] then
local index = #rev_memo + 1
memo[t] = index
rev_memo[index] = t
end
return '_[' .. memo[t] .. ']'
else
error("Trying to serialize unsupported type " .. ty)
end
end

local write_key_value_pair = function(k, v, memo, rev_memo, name)
if type(k) == 'string' and k:match '^[_%a][_%w]*$' and not kw[k] then
return (name and name .. '.' or '') .. k ..'=' .. write(v, memo, rev_memo)
else
return (name or '') .. '[' .. write(k, memo, rev_memo) .. ']=' .. write(v, memo, rev_memo)
end
end

local is_cyclic = function(memo, sub, super)
local m = memo
local p = memo
return m and p and m < p
end

local write_table_ex = function(t, memo, rev_memo, srefs, name)
if type(t) == 'function' then
return '_[' .. name .. ']=loadstring' .. make_safe(string.dump(t))
end
local m = {}
local mi = 1
for i = 1, #t do -- don't use ipairs here, we need the gaps
local v = t
if v == t or is_cyclic(memo, v, t) then
srefs[#srefs + 1] = {name, i, v}
m[mi] = 'nil'
mi = mi + 1
else
m[mi] = write(v, memo, rev_memo)
mi = mi + 1
end
end
for k,v in pairs(t) do
if type(k) ~= 'number' or math.floor(k) ~= k or k < 1 or k > #t then
if v == t or k == t or is_cyclic(memo, v, t) or is_cyclic(memo, k, t) then
srefs[#srefs + 1] = {name, k, v}
else
m[mi] = write_key_value_pair(k, v, memo, rev_memo)
mi = mi + 1
end
end
end
return '_[' .. name .. ']={' .. table.concat(m, ',') .. '}'
end


--[[
A function more appropriate for serializing objects in a reproduceable way.
--]]
function util.serialize(t)
local memo = {[t] = 0}
local rev_memo = {[0] = t}
local srefs = {}
local result = {}

-- phase 1: recursively descend the table structure
local n = 0
while rev_memo[n] do
result[n + 1] = write_table_ex(rev_memo[n], memo, rev_memo, srefs, n)
n = n + 1
end

-- phase 2: reverse order
for i = 1, n*.5 do
local j = n - i + 1
result, result[j] = result[j], result
end

-- phase 3: add all the tricky cyclic stuff
for i, v in ipairs(srefs) do
n = n + 1
result[n] = write_key_value_pair(v[2], v[3], memo, rev_memo, '_[' .. v[1] .. ']')
end

-- phase 4: add something about returning the main table
if result[n]:sub(1, 5) == '_[0]=' then
result[n] = 'return ' .. result[n]:sub(6)
else
result[n + 1] = 'return _[0]'
end

-- phase 5: just concatenate everything
result = table.concat(result, '\n')
return n > 1 and 'local _={}\n' .. result or result
end

function util.map(t, f)
local results = {}
local func = f or tostring
for i,v in ipairs(t) do
table.insert(results, func(v))
end
return results
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/temp/notes.lua
--------------------------------------------------------------------------------]]
--[[
A note has 'key' and 'text' fields, lists are sorted by key.
--]]

notes = notes or {}
notesmt = notesmt or {}

note = note or {}
notemt = notemt or {}

notemt.__index = note
notemt.__lt = function(a,b) return a.key < b.key end

function notes.new(filename, useTableFile)
local obj = {}
setmetatable(obj, {__index = notes})
obj:load(filename, useTableFile)
return obj
end

function notes:load(filename, useTableFile)
self.filename = filename
self.useTableFile = useTableFile
local s = loadTextFile(self.filename, self.useTableFile)
self.dict = {}
if s then self.dict = loadstring(s)() end
self.lastSave = os.clock()
self.lastChange = 0
end

function notes:save()
local text = util.serialize(self.dict)
saveTextFile(self.filename, text, self.useTableFile)
self.lastSave = os.clock()
end

function notes:saveAs(filename, useTableFile)
self.filename = filename
self.useTableFile = useTableFile
self:save()
end


function notes:update(key, text)
if text == nil or string.len(text) == 0 then
if self.dict[key] then self.dict[key] = nil end
else
self.dict[key] = {key = key, text = text}
end
self.lastUpdate = os.clock()
end

function notes:getList()
local keys = {}
for k,n in pairs(self.dict) do table.insert(keys, n) end
return keys
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/mono.lua
--------------------------------------------------------------------------------]]

-- moduled
mono = mono or {}

-- classes
mono.MonoClass = mono.MonoClass or {}
mono.MonoField = mono.MonoField or {}
mono.MonoMethod = mono.MonoMethod or {}
mono.MonoImage = mono.MonoImage or {}

mono.menu = mono.menu or {}

mono.popups = mono.popups or {}

mono.formSelectImage = mono.formSelectImage or {}
mono.formSearch = mono.formSearch or {}
mono.formClass = mono.formClass or {}

-- defines
mono.TYPE_NAMES = {
[0] = 'END',
[1] = 'void',
[2] = 'bool',
[3] = 'char',
[4] = 'sbyte',
[5] = 'byte',
[6] = 'short',
[7] = 'ushort',
[8]= 'int',
[9]= 'uint',
[10] = 'long',
[11] = 'ulong',
[12] = 'float',
[13] = 'double',
[14] = 'string',
[15] = 'ptr',
[16] = 'byref',
[17] = 'valuetype',
[18] = 'class',
[19] = 'var',
[20] = 'array',
[21] = 'genericinst',
[22] = 'typedbyref',
[24] = 'I',
[25] = 'U',
[0x1b] = 'FNPTR',
[0x1c] = 'object',
[0x1d] = 'szarray', -- 0-based one-dim-array
[0x1e] = 'mvar',
[0x1f] = 'CMOD_REQD', -- typedef or typeref token
[0x20] = 'CMOD_OPT', -- optional arg: typedef or typeref token
[0x21] = 'INTERNAL',
[0x40] = 'MODIFIER', -- Or with the following types
[0x41] = 'SENTINEL', -- sentinel for varargs method signature
[0x45] = 'PINNED', -- local var that points to pinned object
[0x55] = 'ENUM', -- an enumeration
}


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/mono/monofield.lua
--------------------------------------------------------------------------------]]
local MonoField = mono.MonoField
MonoField.mt = {
__index = MonoField,
__tostring = function(t)
return 'MonoField '..tostring(t.id)..' "'..tostring(t.name)..'"'
end,
__lt = function(a, b)
return a.lowerName < b.lowerName
end
}

-- class is a monoclass table, f is a table with results from
-- mono_class_enumFields
function MonoField.new(class, f)
local obj = {
class = class,
id = f.field,
name = f.name,
isStatic = f.isStatic,
isConst = f.isConst,
offset = f.offset,
monoType = f.monotype,
lowerName = string.lower(f.name),
foundTypeName = f.typeName,
typeName = mono.TYPE_NAMES[f.monotype] or 'UnknownType'..tostring(f.monotype)
}

-- should be types where we might have a 'Class'
--if f.monotype == 15 or f.monotype == 16 or f.monotype == 18 or f.monotype then
--end

obj.typeClassId = mono_type_getClass(obj.id)
if obj.typeClassId ~= nil then
-- this is the 'type' of the field
obj.typeClass = class.image.classesById[obj.typeClassId]
if obj.typeClass ~= nil then
obj.typeName = obj.typeClass.name
else
if class.image.missingNames[obj.typeClassId] then
obj.typeName = class.image.missingNames[obj.typeClassId]
else
obj.typeName = mono_class_getFullName(obj.typeClassId)
class.image.missingNames[obj.typeClassId] = obj.typeName
end
end
end

setmetatable(obj, MonoField.mt)
return obj
end

function MonoField:getFullName()
local s = ""
if self.class.namespace ~= nil and self.class.namespace:len() > 0 then s = self.class.namespace..':' end
s = s..self.class.name..'.'
s = s..self.name
return s
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/mono/monomethod.lua
--------------------------------------------------------------------------------]]
local MonoMethod = mono.MonoMethod
MonoMethod.mt = {
__index = MonoMethod,
__tostring = function(t)
return 'MonoMethod '..tostring(t.id)..' "'..tostring(t.name)..'"'
end,
__lt = function(a, b)
return a.lowerName < b.lowerName
end
}

function MonoMethod.new(class, m)
local obj = {
class = class,
id = m.method,
name = m.name,
lowerName = string.lower(m.name),
parameters = {}
}
setmetatable(obj, MonoMethod.mt)

lastmethod = obj
local types, parameternames, returntype = mono_method_getSignature(obj.id)
local typenames={}
local tn
if types ~= nil then
for tn in string.gmatch(types, '([^,]+)') do
table.insert(typenames, tn)
end
end

for i=1,#typenames do
table.insert(obj.parameters, { name = parameternames, type = typenames })
end
obj.returnType = returntype

return obj
end

--[[
Get parameters for method
--]]
function MonoMethod:fetchParms()
if self.parms ~= nil then return nil end
if self.class.image.ignoredClassesByName[self.class.name] ~= nil then return nil end
local status, parms = pcall(function()
local result = mono_method_get_parameters(self.id)
return result
end)

if status then
-- success!
self.parms = parms
else
self.class.image.ignoredClassesByName[self.class.name] = true
print('Error with class '..tostring(self.class.name)..' method '..tostring(self.name))
error('Error fetching parameters for '..tostring(self.class.name)..'.'..tostring(self.name))
end
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/mono/monoclass.lua
--------------------------------------------------------------------------------]]
local MonoClass = mono.MonoClass
MonoClass.mt = {
__index = MonoClass,
__tostring = function(t)
return 'MonoClass '..tostring(t.id)..' "'..tostring(t.name)..'"'
end,
__lt = function(a, b)
return a.lowerName < b.lowerName
end

}

local MonoField = mono.MonoField
local MonoMethod = mono.MonoMethod

--[[
Called from MonoImage:_init, 'c' is what is returned from enumerating classes.
--]]
function MonoClass.new(image, c)
local obj = {
name = c.classname,
namespace = c.namespace,
id = c.class,
lowerName = string.lower(c.classname),
image = image
}

setmetatable(obj, MonoClass.mt)
return obj
end

function MonoClass:initFields()
self.fields = {}
self.fieldsByName = {}
self.fieldsByLowerName = {}
local constFieldCount = 0

local temp = mono_class_enumFields(self.id)
for i,f in ipairs(temp) do
local field = MonoField.new(self, f)
table.insert(self.fields, field)
self.fieldsByLowerName[field.lowerName] = field;
self.fieldsByName[field.name] = field

if field.isStatic and field.isConst then
field.constValue = constFieldCount
constFieldCount = constFieldCount + 1
end
end

table.sort(self.fields)
end

function MonoClass:initMethods()
self.methods = {}
self.methodsByName = {}
self.methodsByLowerName = {}

local temp = mono_class_enumMethods(self.id)
for i,m in ipairs(temp) do
local method = MonoMethod.new(self, m)
table.insert(self.methods, method)
self.methodsByName[method.name] = method
self.methodsByLowerName[method.lowerName] = method
end

table.sort(self.methods)
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/mono/monoimage.lua
--------------------------------------------------------------------------------]]
local MonoImage = mono.MonoImage
MonoImage.mt = {
__index = MonoImage,
__tostring = function(t)
return 'MonoImage '..tostring(t.name)
end
}

local MonoClass = mono.MonoClass

--[[
List names of images, a name can be passed to MonoImage.new()
or MonoImage(name) to create a MonoImage instance.
--]]
function MonoImage.enumerate()
local names = {}
mono_enumImages(function(img)
local name = mono_image_get_name(img)
table.insert(names, name)
end)
table.sort(names)
return names
end

--[[
Constructor doesn't do much, call :init(name, progress)
--]]
function MonoImage.new()
local obj = { }
setmetatable(obj, MonoImage.mt)
return obj
end

--[[
init() takes the image name and an optional callback for reporting progress
and when it is complete. The signature for this function is:
function progress(complete, image, message, processed, total)
This callback should be executed on the main CE thread.
--]]
function MonoImage:init(name, progress)
if monopipe == nil then
print('Launching mono data collector...')
LaunchMonoDataCollector()
end

self.domains = mono_enumDomains()
self.domain = self.domains[1]

self.classes = {} -- straight list of all classes
self.classesByName = {} -- dictionary for access by name
self.classesByLowerName = {} -- for access by lower case name
self.classesById = {} -- for access by id
self.ignoredClassesByName = {} -- for ignoring classes in searches, etc.
self.progress = progress
self.name = name or 'Assembly-CSharp' -- intelligent default for unity

-- get id
self.id = nil
mono_enumImages(function(img)
local foundName = mono_image_get_name(img)
if foundName == self.name then self.id = img end
end)

if not self.id then
print('NO ID!')
print('name is', name, self.name)
self:report(false, 'Error finding image named '..tostring(name))
self.progress = nil
self.total = nil
self.count = nil
return false
end

createThread(function(thread)
self.thread = thread
self:_init(thread)
end)
end

--[[
This is the function called by init() on another thread
--]]
function MonoImage:_init(thread)
--print('MonoImage:_init thread is', thread, 'self is', tostring(self))
self.thread = thread
local temp = mono_image_enumClasses(self.id)
-- thread.synchronize(function(th)
-- print('Image '..tostring(self.id)..' has classes: '..tostring(temp))
-- end)

self.classes = {}
self.classesByName = {}
self.classesByLowerName = {}
self.classesById = {}
self.missingNames = {}

self.total = #temp
self.count = 0
self.message = "Getting classes"
self:report(false, "Getting classes")

-- populate classes without much information first so we can
-- access our definitions when filling in parents, properties, etc.
for i,c in ipairs(temp) do
local class = MonoClass.new(self, c)
if class.lowerName ~= nil then
table.insert(self.classes, class)
self.classesByName[class.name] = class
self.classesByLowerName[class.lowerName] = class
self.classesById[class.id] = class
else
--print("Nil lowername for class", c.class)
end
self.count = i
if (i % 100 == 0 or i == #temp) then
self:report(false, 'Fetching classes')
end
end
table.sort(self.classes)

for i,class in ipairs(self.classes) do
class.parentId = mono_class_getParent(class.id)
class.parent = self.classesById[class.parentId]
self.count = i
if (i % 100 == 0 or i == #temp) then
self:report(false, 'Fetching parents')
end
end

self.count = 0
for i,class in ipairs(self.classes) do
class:initFields()
class:initMethods()
self.count = i
if (i % 100 == 0 or i == #temp) then
self:report(false, 'Initializing fields and methods')
end
end

self:report(true, 'Done')
end

--[[
Report progress on the main CE thread to do gui updates
--]]
function MonoImage:report(done, message)
if self.progress ~= nil and self.thread ~= nil then
self.thread.synchronize(function(thread)
self.progress(done, self, message, self.count, self.total)
end)
end

if done then
-- do cleanup here
self.count = nil
self.total = nil
self.progress = nil
self.thread = nil
end
end


--[[ Sample code... weird

--return util.pretty(mono.MonoImage.enumerate())
mi = mono.MonoImage.new()
print('mi is "'..tostring(mi)..'"')
mi:init('Assembly-CSharp', function(c, i, m, p, t)
print(m, p, t)
end)

--LaunchMonoDataCollector()
local thread = createThread(function(th)
TESTIMAGES = {}
mono_enumImages(function(img)
th.synchronize(function() print(img) end)
end)
end)

--]]



--[[--------------------------------------------------------------------------------
-- Included File: src/lua/monomenu.lua
--------------------------------------------------------------------------------]]
function mono.menu:init()
--if self.menuSearch or self.timer then return end
self.timer = createTimer()
self.timer.Interval = 1000
self.timer.OnTimer = function(timer)
-- wait for normal mono script to create mono menu, check every 5 seconds
if not miMonoTopMenuItem then return end

self.timer.destroy()
self.timer = nil

self.menuSearch = createMenuItem(miMonoTopMenuItem)
self.menuSearch.Caption = 'Search'
self.menuSearch.Name = 'miMonoSearch'
self.menuSearch.OnClick = function(sender) self:OnSearchClick() end
miMonoTopMenuItem.add(self.menuSearch)
end
end

function mono.menu:OnSearchClick()
if mono.selectedImage then
mono.formSearch:show()
formMonoSearch:centerScreen()
else
mono.formSelectImage:show()
end
end

mono.menu:init()



--[[--------------------------------------------------------------------------------
-- Included File: src/lua/forms/formSelectImage.lua
--------------------------------------------------------------------------------]]
local DEFAULT_ASSEMBLY_NAME = "Assembly-CSharp"
local imageHasBeenSelected = false

function mono.formSelectImage:show()
LaunchMonoDataCollector()
formMonoImage.listImages.Visible = true
formMonoImage.buttonSelectImage.Visible = true
formMonoImage.progressImage.Visible = false
formMonoImage.labelMessage.Visible = false

self.imageNames = mono.MonoImage.enumerate()
table.sort(self.imageNames)
local items = formMonoImage.listImages.Items
items.Clear()

local foundIndex = 0
for i,name in ipairs(self.imageNames) do
items.add(name)
if name == DEFAULT_ASSEMBLY_NAME then foundIndex = i end
end

local handler = function(sender)
mono.formSelectImage.OnSelectImage(self)
end

formMonoImage.buttonSelectImage.OnClick = handler
formMonoImage.listImages.OnDblClick = handler

formMonoImage.show()

if foundIndex ~= 0 and imageHasBeenSelected == false then
formMonoImage.listImages.ItemIndex = foundIndex - 1
mono.formSelectImage:OnSelectImage()
end
end

function mono.formSelectImage:OnSelectImage()
imageHasBeenSelected = true
local index = formMonoImage.listImages.ItemIndex + 1
if self.imageNames == nil or index < 1 or index > #self.imageNames then return end
local imageName = self.imageNames[index]

formMonoImage.listImages.Visible = false
formMonoImage.buttonSelectImage.Visible = false
formMonoImage.progressImage.Visible = true
formMonoImage.labelMessage.Visible = true
formMonoImage.labelMessage.Caption = 'Finding classes...'

local image = mono.MonoImage.new()

formMonoImage.progressImage.Min = 0
local progressHandler = function(done, image, message, count, total)
if total ~= nil and total > 0 and count ~= nil and count >= 0 then
message = string.format('%s %d/%d', message, count, total)
formMonoImage.progressImage.Max = total
formMonoImage.progressImage.Position = count
end

formMonoImage.labelMessage.Caption = message
if done then self:OnImageComplete(image) end
end

image:init(imageName, progressHandler)
end

function mono.formSelectImage:OnImageComplete(image)
self.image = image
mono.selectedImage = image
formMonoImage.Close()
mono.formSearch:show()
formMonoSearch:centerScreen()
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/forms/formSearch.lua
--------------------------------------------------------------------------------]]
--[[
Form for searching an image.

Controls:
pageMain.tabSearch - main tab
editSearchText: TCEEdit
listSearchClasses: TCEListView
listSearchFields: TCEListView
listSearchMethods: TCEListView
miImage: TMenuItem - main menu Image entry
miImageSelectImage - entry to re-open select image form
--]]

mono.formSearch.found = mono.formSearch.found or {}
mono.formSearch.found.classes = mono.formSearch.found.classes or {}
mono.formSearch.found.fields = mono.formSearch.found.fields or {}
mono.formSearch.found.methods = mono.formSearch.found.methods or {}

--[[
Show the search form, mono.selectedImage should be set to the
image to search.
--]]
function mono.formSearch:show()
if mono.selectedImage == nil then return end
self.image = mono.selectedImage

-- setup event handlers
formMonoSearch.miImageSelectImage.OnClick = function(sender) self:SelectImageClick() end

formMonoSearch.listSearchClasses.OnData = function(sender, listitem)
self:listSearchClasses_OnData(sender, listitem)
end

formMonoSearch.listSearchClasses.OnDblClick = function(sender)
local class = self.found.classes[sender.ItemIndex + 1]
mono.formClass:show(class, nil, nil)
end

formMonoSearch.listSearchFields.OnData = function(sender, listitem)
self:listSearchFields_OnData(sender, listitem)
end

formMonoSearch.listSearchFields.OnDblClick = function(sender)
local field = self.found.fields[sender.ItemIndex + 1]
if field then
mono.formClass:show(field.class, field, nil)
end
end

formMonoSearch.listSearchMethods.OnData = function(sender, listitem)
self:listSearchMethods_OnData(sender, listitem)
end

formMonoSearch.listSearchMethods.OnDblClick = function(sender)
local method = self.found.methods[sender.ItemIndex + 1]
if method then
mono.formClass:show(method.class, nil, method)
end
end

formMonoSearch.editSearchText.OnChange = function(sender)
self:search(sender.text)
end

-- popups
formMonoSearch.listSearchClasses.PopupMenu = formMonoSearch.popupClasses
local count = 0
formMonoSearch.popupClasses.OnPopup = function(sender)
print('formMonoSearch.popupClasses.OnPopup "'..tostring(sender.name)..'" count '..tostring(count))
count = count + 1
end

-- perform initial search to set 'found' results, probably empty text
self:search(formMonoSearch.editSearchText.Text)


-- show form
formMonoSearch.show()
end

--[[
When menu item to select an image is clicked, hide this form and
show the image select form
--]]
function mono.formSearch:SelectImageClick()
formMonoSearch.close()
mono.formSelectImage:show()
end

--[[
When typing in the edit box to filter results, filter the lists of
classes, fields, and methods with the lower case of the text
--]]
function mono.formSearch:search(text)
local lower = nil
if text ~= nil then lower = text:lower() end

local classes = {}
local methods = {}
local fields = {}
for i,class in ipairs(self.image.classes) do
if lower == nil or class.lowerName:find(lower, 1, true) ~= nil then table.insert(classes, class) end
for j,method in ipairs(class.methods) do
if lower == nil or method.lowerName:find(lower, 1, true) ~= nil then table.insert(methods, method) end
end
for j,field in ipairs(class.fields) do
if lower == nil or field.lowerName:find(lower, 1, true) ~= nil then table.insert(fields, field) end
end
end
self.found.classes = classes
self.found.fields = fields
self.found.methods = methods
formMonoSearch.listSearchClasses.Items.Count = #classes
formMonoSearch.listSearchFields.Items.Count = #fields
formMonoSearch.listSearchMethods.Items.Count = #methods
end

-- handler to display classes in list view
function mono.formSearch:listSearchClasses_OnData(sender, listitem)
local index = listitem.Index + 1
local class = self.found.classes[index]
listitem.Caption = class.name
end

-- handler to display fields in list view
function mono.formSearch:listSearchFields_OnData(sender, listitem)
local field = self.found.fields[listitem.Index + 1]
if field == nil then
listitem.Caption = 'nil index '..tostring(index)
else
listitem.Caption = field.name
listitem.SubItems.text = field.class.name
end
end

-- handler to display methods in list view
function mono.formSearch:listSearchMethods_OnData(sender, listitem)
local method = self.found.methods[listitem.Index + 1]
if method == nil then
listitem.Caption = 'nil index '..tostring(index)
else
listitem.Caption = method.name
listitem.SubItems.text = method.class.name
end
end


--[[--------------------------------------------------------------------------------
-- Included File: src/lua/forms/formClass.lua
--------------------------------------------------------------------------------]]
--[[
Form for viewing a class

Controls:
listFields: TCEListView
listMethods: TCEListView
miSortFieldsByOffset - if Checked, sort by offset, otherwise by name
miShowInherited - if Checked, add in methods and fields of parent(s)
miShowUsage - if Checked, funcs and methods will be on other classes that use the type

miFindFields - When clicked, find fields in all classes that have this class as a type
miFindMethodCode - When clicked, find methods in all classes that have this class as a type


Standard Mode:
listFields (can sort by name (default) or offset)
Offset
Type
Name
Class - class it is defined on, blank if not inherited
listMethods (sorted by name)
Name
Signature (return type, parameter types and names)
Class - class it is defined on, blank if not inherited

Usage Mode:
listFields (sorted by Class then Name)
Offset
Type
Class
--]]

local sortByClassThenName = function(a, b)
if a.isConst and not b.isConst then return true end
if b.isConst and not a.isConst then return false end
if a.isConst and b.isConst then return a.constValue < b.constValue end
if a.class.lowerName < b.class.lowerName then return true end
if b.class.lowerName < a.class.lowerName then return false end
return a.name < b.name
end

local sortByClassThenOffset = function(a, b)
if a.isConst and not b.isConst then return true end
if b.isConst and not a.isConst then return false end
if a.isConst and b.isConst then return a.constValue < b.constValue end
if a.class.lowerName < b.class.lowerName then return true end
if b.class.lowerName < a.class.lowerName then return false end
return a.offset < b.offset
end

local sortByName = function(a, b)
if a.isConst and not b.isConst then return true end
if b.isConst and not a.isConst then return false end
if a.isConst and b.isConst then return a.constValue < b.constValue end
return a.lowerName < b.lowerName
end

local sortByOffset = function(a, b)
if a.isConst and not b.isConst then return true end
if b.isConst and not a.isConst then return false end
if a.isConst and b.isConst then return a.constValue < b.constValue end
return a.offset < b.offset
end


--[[
Show the search form, mono.selectedImage should be set to the
image to search.
--]]
function mono.formClass:show(class, field, method)
if mono.selectedImage == nil or class == nil then return end
self.image = mono.selectedImage
self.class = class

-- function to update lists, for setting on menu items that
-- make other changes
local funcUpdate = function(sender) self:setFieldsAndMethods() end

formMonoClass.listFields.OnData = function(sender, listitem)
self:listFields_OnData(sender, listitem)
end

formMonoClass.listFields.OnDblClick = function(sender)
self:listFields_OnDblClick(sender)
end

formMonoClass.listMethods.OnData = function(sender, listitem)
self:listMethods_OnData(sender, listitem)
end

formMonoClass.listMethods.OnDblClick = function(sender)
self:listMethods_OnDblClick(sender)
end

formMonoClass.miSortFieldsByOffset.OnClick = funcUpdate
formMonoClass.miShowInherited.OnClick = funcUpdate
formMonoClass.miShowUsage.OnClick = funcUpdate

-- create our own lists of fields and methods that we can sort
-- and filter
self:setFieldsAndMethods()

-- show form
formMonoClass.show()
end

--[[
Set fields and methods arrays, sorted appropriately and
with extra fields, including possibly parent fields and methods
--]]
function mono.formClass:setFieldsAndMethods()
local other = ''
if formMonoClass.miShowUsage.Checked then other = ' (usage by other classes)' end

formMonoClass.labelClassName.Caption = string.format('Mono Class: %s:%s%s', self.class.namespace, self.class.name, other)
local fields = {}
local methods = {}
if formMonoClass.miShowUsage.Checked then
---------- show where class is used in other classes
for i,class in ipairs(self.image.classes) do
for j,method in ipairs(class.methods) do
local found = false
if method.returnType == self.class.name then
found = true
else
for k,p in ipairs(method.parameters) do
if p.typeName == self.class.name then found = true end
end
end
if found then table.insert(methods, method) end
end

for j,field in ipairs(class.fields) do
if field.typeName == self.class.name then table.insert(fields, field) end
end
end
else
---------- basic class fields and methods
local c = self.class

while c ~= nil do
for i,field in ipairs(c.fields) do
table.insert(fields, field)
end

for i,method in ipairs(c.methods) do
table.insert(methods, method)
end

if formMonoClass.miShowInherited.Checked then
c = c.parent
else
c = nil
end
end
end


if formMonoClass.miSortByClassFirst.Checked then
table.sort(fields, formMonoClass.miSortFieldsByOffset.Checked and sortByClassThenOffset or sortByClassThenName)
table.sort(methods, sortByClassThenName)
else
table.sort(fields, formMonoClass.miSortFieldsByOffset.Checked and sortByOffset or sortByName)
table.sort(methods, sortByName)
end

self.fields = fields
self.methods = methods
formMonoClass.listFields.Items.Count = 0
formMonoClass.listFields.Items.Count = #fields
formMonoClass.listMethods.Items.Count = 0
formMonoClass.listMethods.Items.Count = #methods
end

-- handler to display fields in list view
function mono.formClass:listFields_OnData(sender, listitem)
-- columns are offset (or 'STATIC'), Type, Name
local index = listitem.Index + 1
local field = self.fields[index]

-- columns are Offset, Type, Name
if field.isStatic then
if field.isConst then
listitem.Caption = 'Const:'..string.format('%2X', field.constValue or 0)
else
listitem.Caption = 'Static:'..string.format('%2X', field.offset or 0)
end
else
listitem.Caption = string.format('%02X', field.offset or 0)
end
local className = ''
if field.class.name ~= self.class.name then className = field.class.name end
listitem.SubItems.text = table.concat({field.typeName or '??', field.name, className}, '\n')
end

-- handler to display methods in list view
function mono.formClass:listMethods_OnData(sender, listitem)
local method = self.methods[listitem.Index + 1]
if method == nil then
listitem.Caption = 'nil index '..tostring(listitem.Index + 1)
else
listitem.Caption = method.name

local className = ''
if method.class.name ~= self.class.name then className = method.class.name end

local ps = {}
for i,p in ipairs(method.parameters) do
table.insert(ps, string.format('%s %s', p.type, p.name))
end
local parms = method.returnType..' ('..table.concat(ps, ', ')..')'

--print('className, method.class.name', className, method.class.name)
listitem.SubItems.text = table.concat({ parms, className }, '\n')
end
end

local parameters = { 'RCX', 'RDX', 'R8', 'R9', '[RBP+30]', '[RBP+38]', '[RBP+40]', '[RBP+48]', '[RBP+50]' }
local floatParameters = { 'XMM0', 'XMM1', 'XMM2', 'XMM3', 'XMM4', 'XMM5', 'XMM6'}

function mono.formClass:popupMethod_OnPopup(sender)

end

function mono.formClass:listMethods_OnDblClick(sender)
local method = self.methods[sender.ItemIndex + 1]
--print("method: "..tostring(method.id))
if method then
local address = mono_compile_method(method.id)
--print("address: "..tostring(address))
getMemoryViewForm().DisassemblerView.SelectedAddress = address
getMemoryViewForm().show()
local hookInfo = hookAt(address)
-- have aobString, hookString, returnString, instructions
--[[ how to get method signature
local ps = {}
for i,p in ipairs(method.parameters) do
table.insert(ps, string.format('%s %s', p.type, p.name))
end
local parms = method.returnType..' ('..table.concat(ps, ', ')..')'
]]

local lines = {}
table.insert(lines, "define(hook,"..hookInfo.hookString..")")
table.insert(lines, "define(bytes,"..hookInfo.aobString..")")
table.insert(lines, "")
table.insert(lines, "[enable]")
table.insert(lines, "")
table.insert(lines, "assert(hook, bytes)")
table.insert(lines, "alloc(newmem,$1000, hook)")
table.insert(lines, "{")


-- note: per x64 calling convention, RCX might actually be space for
-- a pre-allocated structure for the return value and other parameters
-- might be moved one further down the list
table.insert(lines, " RCX: "..method.class.name.." (this)")
for i,p in ipairs(method.parameters) do
local param = parameters[i + 1]
if (p.type == "System.Single" or p.type == "System.Double") then param = floatParameters[i + 1] end
table.insert(lines, " "..param..": "..tostring(p.type).." "..tostring(p.name))
end
table.insert(lines, "")

table.insert(lines, " Returns (RAX) "..method.returnType)
table.insert(lines, "}")
table.insert(lines, "")
table.insert(lines, "newmem:")
table.insert(lines, " // original code")
for i,c in ipairs(hookInfo.instructions) do
table.insert(lines, " "..c)
end
table.insert(lines, " jmp hook+"..string.format("%X", hookInfo.returnOffset))
table.insert(lines, "")
table.insert(lines, "hook:")
table.insert(lines, " jmp newmem")
table.insert(lines, "")
table.insert(lines, "[disable]")
table.insert(lines, "")
table.insert(lines, "hook:")
table.insert(lines, " db bytes")
table.insert(lines, "")
table.insert(lines, "dealloc(newmem)")

local t = {}
for i,v in ipairs(lines) do
table.insert(t, v);
table.insert(t, "\r\n")
end

local aa = table.concat(t)

getMemoryViewForm().AutoInject1.DoClick()

for i=0,getFormCount()-1 do --this is sorted from z-level. 0 is top
local f=getForm(i)

if getForm(i).ClassName == 'TfrmAutoInject' then
f.assemblescreen.Lines.Text = aa
break
end
end
end
end

--[[
When double-clicking a field, print out the base address for the statics of the
class and the address of the clicked-on static field.
--]]
function mono.formClass:listFields_OnDblClick(sender)
local field = self.fields[sender.ItemIndex + 1]
if field then
local class = field.class
local image = class.image
local domainId = image.domain
print('double-clicked on class '..tostring(field.class.name)..' field '..tostring(field.name)..' domain '..tostring(domainId))
local address = mono_class_getStaticFieldAddress(domainId, class.id)
print('statics base address: '..string.format("%x", address))
print(class.name..'.'..field.name..': '..string.format("%x", address + field.offset))
end
end

--[[
IN PROGRESS - take an address and create an AA script to hook at that address
expecting MONO code. Will process instructions until 5 bytes (for jmp) are
processed. Basic format is like this for address 'CryingSuns.PlayerStatus:BattleshipState:HasAuxiliarySystemType+28'

[enable]
assert("CryingSuns.PlayerStatus:BattleshipState:HasAuxiliarySystemType":+28, )
]]
function hookAt(address)
local pos = string.find(address, "+", 1, true)
local name = address
local offset = 0
if (pos ~= nil) then
name = string.substring(1, pos - 1)
offset = tonumber(string.sub(pos + 1), 16)
end
local actualAddress = getAddress(name) + offset

local data = {
hookString = util.safeAddress(getNameFromAddress(actualAddress)), -- used for injection, etc
instructions = {},
aobString = ""
}

local aobs = {}

while (offset < 5) do
local parsed = disassembleAndParse(actualAddress + offset)
if #aobs > 0 then table.insert(aobs, " ") end
table.insert(aobs, parsed.bytesString)
table.insert(data.instructions, parsed.instructionString)
offset = offset + parsed.length
end

data.aobString = table.concat(aobs)
data.returnString = util.safeAddress(getNameFromAddress(actualAddress + offset))
data.returnOffset = offset
return data
end

function hookMethod(method)

end

--[[
Expects address to be a number
]]
function disassembleAndParse(address)
local disassembly = disassemble(address)
local parts = util.split(disassembly, "-")
for i = 1,#parts do
if i == 2 then
parts = parts:gsub("%s+", "") -- remove ALL whitespace from bytes
else
parts = parts:gsub("^%s*(.-)%s*$", "%1") -- remove whitespace from ends
end
end

local aob = {}
local i = 1
while i < string.len(parts[2]) do
if (i ~= 1) then table.insert(aob, " ") end
table.insert(aob, string.sub(parts[2], i, i+1))
i = i + 2
end

local instructionString = parts[3]
for k,v in parts[3]:gmatch("[0-9a-fA-F]+") do
if k:len() == 8 or k:len() == 16 then
instructionString = instructionString:gsub(k, getNameFromAddress(k))
end
end


local result = {
address = getAddress(address),
addressString = util.safeAddress(getNameFromAddress(address)),
aob = aob,
bytesString = table.concat(aob),
disassembly = disassembly,
instructionString = instructionString,
length = getInstructionSize(address),
originalInstructionString = parts[3]
}

return result
end


//Later back on when i launch it up as on the screen here
//When i select game i cannot launch any of scripts image down below.

// I CANT CHECK ANY OF BOXES OR CHANGE VALUES
+ maybe that helps //The first line shows up some error, idk what is goin on

//IM USING NEW .CT version

mibro91
What is cheating?
What is cheating?
Posts: 1
Joined: Wed Apr 27, 2022 8:04 pm
Reputation: 0

Re: [REQUEST] Tap Ninja

Post by mibro91 »

There is a new update and the Player data does not work

User avatar
BabyGroot
Table Makers
Table Makers
Posts: 1337
Joined: Sun Mar 29, 2020 1:39 pm
Reputation: 2177

Re: [REQUEST] Tap Ninja

Post by BabyGroot »

Cheat table Update
v2.7.2 build ID : 8605273

Check build ID here
[Link]

Baltus
What is cheating?
What is cheating?
Posts: 2
Joined: Wed Apr 27, 2022 4:33 pm
Reputation: 0

Re: [REQUEST] Tap Ninja

Post by Baltus »

ReskyAW wrote:
Wed Apr 27, 2022 8:28 pm
Cheat table Update
v2.7.2 build ID : 8605273

Check build ID here
[Link]
So we wait now for cheat update?

User avatar
BabyGroot
Table Makers
Table Makers
Posts: 1337
Joined: Sun Mar 29, 2020 1:39 pm
Reputation: 2177

Re: [REQUEST] Tap Ninja

Post by BabyGroot »

Baltus wrote:
Wed Apr 27, 2022 10:26 pm
ReskyAW wrote:
Wed Apr 27, 2022 8:28 pm
Cheat table Update
v2.7.2 build ID : 8605273

Check build ID here
[Link]
So we wait now for cheat update?
CT has been updated, check my post Here
and see the latest CT

Komarov
What is cheating?
What is cheating?
Posts: 1
Joined: Sun May 01, 2022 11:48 am
Reputation: 0

Re: [REQUEST] Tap Ninja

Post by Komarov »

ReskyAW wrote:
Thu Apr 28, 2022 2:04 am

CT has been updated, check my post Here
and see the latest CT
Hi, is it still working, or do we need to wait for an update?
Unfortunately I'm not able to execute any scripts.

Thanks!

Post Reply

Who is online

Users browsing this forum: Baidu [Spider]