Files
scripts/lua/Cheat Engine/Supermarket.lua
T

261 lines
7.9 KiB
Lua

if (mono_enumDomains() == nil) then LaunchMonoDataCollector() end
local is64Bit = targetIs64Bit()
local ARRAY_SIZE_OFF = is64Bit and 0x18 or 0x10
local ARRAY_DATA_OFF = is64Bit and 0x20 or 0x14
local PTR_SIZE = is64Bit and 8 or 4
local monoTypeToVartypeLookup = {
[0x02] = vtByte, -- BOOLEAN
[0x03] = vtWord, -- CHAR
[0x04] = vtByte, -- I1
[0x05] = vtByte, -- U1
[0x06] = vtWord, -- I2
[0x07] = vtWord, -- U2
[0x08] = vtDword, -- I4 (Int32)
[0x09] = vtDword, -- U4
[0x0a] = vtQword, -- I8
[0x0b] = vtQword, -- U8
[0x0c] = vtSingle, -- R4
[0x0d] = vtDouble, -- R8
[0x0e] = vtString, -- STRING
[0x0f] = vtPointer, -- PTR
[0x12] = vtPointer, -- CLASS
[0x14] = vtPointer -- ARRAY
}
--[[
generic helper functions
]]
function printf(fmt, ...) print(fmt:format(...)) end
function splitByComma(str)
if str == nil or str == "" then return {} end
local result = {}
for word in string.gmatch(str, "([^,]+)") do table.insert(result, word) end
return result
end
--[[
mono helper functions
]]
function dumpFields(class)
print("class fields:")
for i, v in pairs(mono_class_enumFields(class)) do
printf("\tname: %s - static: %s", v.name, tostring(v.isStatic))
end
end
function getFieldFromName(class, name, shouldBeStatic)
local fields = mono_class_enumFields(class)
if not fields then return nil end
for i, v in pairs(fields) do
if v.isStatic == (shouldBeStatic == true) and v.name == name then
return v
end
end
print(("could not find field: %s"):format(name))
return nil
end
--[[
mono wrappers
]]
-- UNUSED
function MonoArray(addr)
local classId, className = mono_object_getClass(addr)
if not className then error("address did not point to valid object") end
if className:sub(-2) ~= "[]" then error("address did not point to array") end
local array = {
_address = addr,
getLength = function(self)
return readInteger(self._address + ARRAY_SIZE_OFF)
end,
getElement = function(self, idx)
if idx < 0 or idx >= self:getLength() then
error("invalid index")
end
return
readPointer(self._address + ARRAY_DATA_OFF + (idx * PTR_SIZE))
end
}
setmetatable(array, {
__tostring = function() return "Mono array instance" end,
__index = function(self, k)
local idx = tonumber(k)
if idx ~= nil then return self:getElement(idx) end
return rawget(self, k)
end
})
return array
end
-- UNUSED
local stringClass = mono_findClass("System", "String")
local string_Length = getFieldFromName(stringClass, "_stringLength")
local string_FirstChar = getFieldFromName(stringClass, "_firstChar")
function MonoStringReader(addr)
if not addr or addr == 0 then return nil end
local classId, className = mono_object_getClass(addr)
if className ~= "String" then error("address did not point to string") end
local str = {
_address = addr,
getLength = function(self)
return readInteger(self._address + string_Length.offset)
end,
getValue = function(self)
return readString(self._address + string_FirstChar.offset,
self:getLength() * 2, true)
end
}
setmetatable(str, {
__tostring = function(self) return self:getValue() end,
__index = str
})
return str
end
function MonoFunctionHelper(fnName, fnId, isStatic)
local fn = {
_name = fnName,
_id = fnId,
_signatures = {},
_static = isStatic
}
if type(fnId) == "table" then
for i, v in ipairs(fnId) do
local sig = mono_method_getSignature(v)
table.insert(fn._signatures, {id = v, params = splitByComma(sig)})
end
end
setmetatable(fn, {
__call = function(self, ...)
local args = {...}
local methodArgs = args
local instancePtr = nil
if not self._static then
if #args == 0 then
error("Instance method " .. self._name ..
" requires instance pointer")
end
instancePtr = table.remove(methodArgs, 1)
end
local activeId = nil
if type(self._id) == "table" then
for _, candidate in ipairs(self._signatures) do
if #candidate.params == #methodArgs then
activeId = candidate.id
break
end
end
if not activeId then
error("No overload for " .. self._name ..
" matches arg count " .. #methodArgs)
end
else
activeId = self._id
end
local paramsInfo = mono_method_get_parameters(activeId)
local monoArgs = {}
for i = 1, #methodArgs do
local pType = paramsInfo.parameters[i].type
table.insert(monoArgs, {
type = monoTypeToVartypeLookup[pType] or vtPointer,
value = methodArgs[i]
})
end
return mono_invoke_method(mono_enumDomains()[1], activeId,
instancePtr, monoArgs)
end,
__tostring = function(self) return "MonoFunction: " .. self._name end
})
return fn
end
function MonoClass(namespace, name)
local classId = mono_findClass(namespace, name)
if not classId then error("Could not find class " .. name) end
local domain = mono_enumDomains()[1]
local staticAddr = mono_class_getStaticFieldAddress(domain, classId)
local methodsRaw = mono_class_enumMethods(classId)
local methodsSorted = {}
for _, v in pairs(methodsRaw) do
if methodsSorted[v.name] then
if type(methodsSorted[v.name]) ~= "table" then
methodsSorted[v.name] = {methodsSorted[v.name]}
end
table.insert(methodsSorted[v.name], v.method)
else
methodsSorted[v.name] = v.method
end
end
local methodsWrapped = {}
for mName, mId in pairs(methodsSorted) do
local checkId = type(mId) == "table" and mId[1] or mId
local flags = mono_method_getFlags(checkId)
local isStatic = bAnd(flags, 0x0010) ~= 0
methodsWrapped[mName] = MonoFunctionHelper(mName, mId, isStatic)
end
local classObj = {
_id = classId,
_name = name,
_ns = namespace,
_fieldInfo = {},
_staticAddr = staticAddr,
_methods = methodsWrapped,
getStaticFieldOffset = function(self, name)
local field = getFieldFromName(self._id, name, true)
return field and field.offset or nil
end,
getStaticField = function(self, offset)
return readPointer(self._staticAddr + offset)
end,
getMethod = function(self, methodName)
local m = self._methods[methodName]
if not m then
error("Method " .. methodName .. " not found!")
end
return m
end
}
return setmetatable(classObj, {
__index = function(self, key)
return self._methods[key] or rawget(self, key)
end
})
end
--[[
game
]]
local GameDataClass = MonoClass("", "GameData")
local instanceOffset = GameDataClass:getStaticFieldOffset("Instance")
printf("GameData class id: %s", tostring(GameDataClass))
printf("GameData.Instance field offset: %x", instanceOffset or 0)
local gameDataInstance = GameDataClass:getStaticField(instanceOffset)
printf("GameData: %x", gameDataInstance or 0)
local moneySpentHelper = GameDataClass:getMethod("CmdAlterFundsWithoutExperience")
printf("GameData.CmdAlterFundsWithoutExperience: %x", moneySpentHelper._id or 0)
moneySpentHelper(gameDataInstance, -51170)