Compare commits
16 Commits
6486731698
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 392dd8a68e | |||
| 9264c819ee | |||
| 1d4c1ca900 | |||
| e817d874c0 | |||
| 28c92e78c2 | |||
| c430904fa6 | |||
| 60db9abb31 | |||
| 16b1f474c4 | |||
| 8c46690f52 | |||
| 55abc526bf | |||
| 41a79d80a5 | |||
| 166fd3efc3 | |||
| a8d4d01378 | |||
| e47713e0c3 | |||
| b85f7e29f2 | |||
| d1900f8327 |
@@ -213,19 +213,19 @@ function handleMessages(side, channel, replyChannel, message, dist)
|
||||
|
||||
-- cmd validation
|
||||
if not message.name then
|
||||
log.warning("received nameless command?")
|
||||
log.warning("Received nameless command?")
|
||||
return
|
||||
end
|
||||
|
||||
if not commands[message.name] then
|
||||
log.error("unhandled command (%s)", message.name)
|
||||
log.error("Unhandled command (%s)", message.name)
|
||||
return
|
||||
end
|
||||
|
||||
local cmd = commands[message.name]
|
||||
for i, v in pairs(cmd.keys) do
|
||||
if type(message.data[i]) ~= v and v ~= "optional" then
|
||||
log.error("command %s requires key %s of type %s (was %s)", message.name, i, v, type(message[i]))
|
||||
log.error("Command %s requires key %s of type %s (was %s)", message.name, i, v, type(message[i]))
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -233,10 +233,10 @@ function handleMessages(side, channel, replyChannel, message, dist)
|
||||
-- cmd execution
|
||||
local success, err = pcall(cmd.handler, message.data, message.id)
|
||||
if not success then
|
||||
log.error("error occurred while executing command %s: %s", message.name, err)
|
||||
log.error("Error occurred while executing command %s: %s", message.name, err)
|
||||
end
|
||||
|
||||
log.info("processed command (%s)", message.name)
|
||||
log.info("Processed command (%s)", message.name)
|
||||
end
|
||||
|
||||
registerEventListener("modem_message", handleMessages)
|
||||
@@ -267,8 +267,14 @@ registerEventListener("key", scrollLogs)
|
||||
local consoleCommands = {}
|
||||
local commandBuffer = ""
|
||||
|
||||
function registerConsoleCommand(name, handler)
|
||||
consoleCommands[name] = handler
|
||||
function registerConsoleCommand(name, handler, desc, usage)
|
||||
local cmd = {
|
||||
["name"] = name,
|
||||
["handler"] = handler,
|
||||
["desc"] = desc or "",
|
||||
["usage"] = usage or nil
|
||||
}
|
||||
consoleCommands[name] = cmd
|
||||
end
|
||||
|
||||
function processCommand()
|
||||
@@ -285,7 +291,7 @@ function processCommand()
|
||||
|
||||
if consoleCommands[cmd] then
|
||||
log.info("> %s %s", cmd, table.concat(args, " "))
|
||||
consoleCommands[cmd](args)
|
||||
consoleCommands[cmd].handler(args)
|
||||
else
|
||||
log.warning("Unknown command: %s", cmd)
|
||||
end
|
||||
@@ -319,42 +325,71 @@ function echoCommand(args)
|
||||
log.info(table.concat(args, " "))
|
||||
end
|
||||
|
||||
registerConsoleCommand("echo", echoCommand)
|
||||
registerConsoleCommand("echo", echoCommand, "Prints your message", "echo (string)")
|
||||
|
||||
function exitCommand(args)
|
||||
shouldRun = false
|
||||
end
|
||||
|
||||
registerConsoleCommand("exit", exitCommand)
|
||||
registerConsoleCommand("exit", exitCommand, "Exits the program")
|
||||
|
||||
function scanCommand(args)
|
||||
log.info("broadcasting SCAN")
|
||||
log.info("Broadcasting SCAN")
|
||||
sendToAll("SCAN", { ["hostChannel"] = HOST_CHANNEL })
|
||||
end
|
||||
|
||||
registerConsoleCommand("scan", scanCommand)
|
||||
registerConsoleCommand("scan", scanCommand, "Sends out a scan command to pair unlinked turtles")
|
||||
|
||||
function clearCommand()
|
||||
function clearCommand(args)
|
||||
log.buffer = {}
|
||||
end
|
||||
registerConsoleCommand("clear", clearCommand)
|
||||
|
||||
function turtlesCommand()
|
||||
registerConsoleCommand("clear", clearCommand, "Clears the console")
|
||||
|
||||
function turtlesCommand(args)
|
||||
if #turtles == 0 then
|
||||
log.info("no turtles registered")
|
||||
log.info("No turtles registered")
|
||||
return
|
||||
end
|
||||
|
||||
for i=0, #turtles, 1 do
|
||||
for i = 1, #turtles, 1 do
|
||||
local turt = turtles[i]
|
||||
|
||||
local turtleMessage = ("coords: %x, %x, %x - fuel: %d - channel: %d - id: %d - status: %s"):format(turt.position[1],
|
||||
turt.position[2], turt.position[3], turt.fuel, turt.channel, turt.id, turt.status)
|
||||
local turtleMessage = ("Coords: %d, %d, %d - fuel: %d - channel: %d - id: %d - status: %s"):format(
|
||||
turt.position[1],
|
||||
turt.position[2], turt.position[3], turt.fuel, turt.channel, turt.id, turt.status)
|
||||
|
||||
log.info(turtleMessage)
|
||||
end
|
||||
end
|
||||
registerConsoleCommand("turtles", turtlesCommand)
|
||||
|
||||
registerConsoleCommand("turtles", turtlesCommand, "Lists all the linked turtles")
|
||||
|
||||
function helpCommand(args)
|
||||
if #args == 0 then
|
||||
log.info("----- commands -----")
|
||||
for _, cmd in pairs(consoleCommands) do
|
||||
log.info("%s - %s", cmd.name, cmd.desc)
|
||||
end
|
||||
else
|
||||
local cmdName = args[1]
|
||||
local cmd = consoleCommands[cmdName]
|
||||
|
||||
if not cmdName then
|
||||
log.error("Unable to find command: %s", cmdName)
|
||||
return
|
||||
end
|
||||
|
||||
log.info("---- %s ----", cmdName)
|
||||
log.info(cmd.desc)
|
||||
if cmd.usage then
|
||||
log.info("Usage: %s", cmd.usage)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
registerConsoleCommand("help", helpCommand, "Prints out all the console commands or usage of a specified command",
|
||||
"help or help (command name)")
|
||||
|
||||
--[[
|
||||
drawing functions
|
||||
@@ -435,7 +470,7 @@ function drawStatusBar(y)
|
||||
scr.setTextColor(colors.white)
|
||||
scr.clearLine()
|
||||
|
||||
local str = ("turtles: %d"):format(#turtles)
|
||||
local str = ("Turtles: %d"):format(#turtles)
|
||||
scr.write(str)
|
||||
end
|
||||
|
||||
@@ -504,7 +539,7 @@ end
|
||||
--[[
|
||||
main
|
||||
]]
|
||||
log.general("init")
|
||||
log.general("Init")
|
||||
|
||||
while shouldRun do
|
||||
updateScreen()
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
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 class wrappers
|
||||
]]
|
||||
function MonoArray(addr)
|
||||
if not addr or addr == 0 then error("attempted to instantiate MonoArray with invalid addr") end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
local typeClass = MonoClass("System", "Type")
|
||||
function Type(typeName)
|
||||
local typeStr = mono_new_string(typeName)
|
||||
local getType = typeClass:getMethod("GetType")
|
||||
local typeRet = getType(typeStr)
|
||||
|
||||
print(type(typeRet), typeRet)
|
||||
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 alterFunds = GameDataClass:getMethod("CmdAlterFunds")
|
||||
printf("GameData.CmdAlterFunds: %x", alterFunds._id or 0)
|
||||
alterFunds(gameDataInstance, 13371337)
|
||||
Reference in New Issue
Block a user