Petr Mrázek 2011-08-23 13:47:04 +02:00
commit 8ab5697f4a
21 changed files with 516 additions and 214 deletions

@ -520,7 +520,11 @@
*/ */
#define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_SCAN "%lf"
#define LUA_NUMBER_FMT "%.14g" #define LUA_NUMBER_FMT "%.14g"
#ifdef WIN32 //More specifically MSVC, but did not work, either way only MSVC is used in windows build
#define lua_number2str(s,n) sprintf_s((s),32, LUA_NUMBER_FMT, (n))
#else
#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) #define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
#endif
#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
#define lua_str2number(s,p) strtod((s), (p)) #define lua_str2number(s,p) strtod((s), (p))

@ -118,3 +118,5 @@ DFHACK_PLUGIN(autodump autodump.cpp)
DFHACK_PLUGIN(cleanowned cleanowned.cpp) DFHACK_PLUGIN(cleanowned cleanowned.cpp)
DFHACK_PLUGIN(deramp deramp.cpp) DFHACK_PLUGIN(deramp deramp.cpp)
DFHACK_PLUGIN(flows flows.cpp) DFHACK_PLUGIN(flows flows.cpp)
DFHACK_PLUGIN(memview memview.cpp)

@ -4,6 +4,7 @@ FILE(GLOB DFUSION_CPPS src/*.c*)
set( set(
DFUSION_CPPS_ALL DFUSION_CPPS_ALL
dfusion.cpp dfusion.cpp
${dfhack_SOURCE_DIR}/library/depends/tthread/tinythread.cpp
${DFUSION_CPPS} ${DFUSION_CPPS}
) )
DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL} LINK_LIBRARIES lua) DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL} LINK_LIBRARIES lua)

@ -24,6 +24,7 @@ using std::string;
using namespace DFHack; using namespace DFHack;
static tthread::mutex* mymutex=0; static tthread::mutex* mymutex=0;
static tthread::thread* thread_dfusion=0;
uint64_t timeLast=0; uint64_t timeLast=0;
DFhackCExport command_result dfusion (Core * c, vector <string> & parameters); DFhackCExport command_result dfusion (Core * c, vector <string> & parameters);
@ -37,15 +38,23 @@ DFhackCExport const char * plugin_name ( void )
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{ {
commands.clear(); commands.clear();
lua::state st=lua::glua::Get();
//maybe remake it to run automaticaly //maybe remake it to run automaticaly
lua::RegisterConsole(lua::glua::Get(),&c->con); lua::RegisterConsole(st,&c->con);
lua::RegisterProcess(lua::glua::Get(),c->p); lua::RegisterProcess(st,c->p);
lua::RegisterHexsearch(lua::glua::Get()); lua::RegisterHexsearch(st);
lua::RegisterMisc(lua::glua::Get()); lua::RegisterMisc(st);
lua::RegisterVersionInfo(lua::glua::Get()); lua::RegisterVersionInfo(st);
commands.push_back(PluginCommand("dfusion","Init dfusion system.",dfusion)); #ifdef LINUX_BUILD
commands.push_back(PluginCommand("lua", "Run interactive interpreter.\ st.push(1);
\n Options: <filename> = run <filename> instead",lua_run)); st.setglobal("LINUX");
#else
st.push(1);
st.setglobal("WINDOWS");
#endif
commands.push_back(PluginCommand("dfusion","Init dfusion system. Use 'dfusion thready' to spawn a different thread.",dfusion));
commands.push_back(PluginCommand("lua", "Run interactive interpreter. Use 'lua <filename>' to run <filename> instead.",lua_run));
mymutex=new tthread::mutex; mymutex=new tthread::mutex;
return CR_OK; return CR_OK;
@ -55,11 +64,13 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
{ {
// shutdown stuff // shutdown stuff
if(thread_dfusion)
delete thread_dfusion;
delete mymutex; delete mymutex;
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_onupdate ( Core * c ) DFhackCExport command_result plugin_onupdate_DISABLED ( Core * c )
{ {
uint64_t time2 = GetTimeMs64(); uint64_t time2 = GetTimeMs64();
uint64_t delta = time2-timeLast; uint64_t delta = time2-timeLast;
@ -137,13 +148,12 @@ DFhackCExport command_result lua_run (Core * c, vector <string> & parameters)
mymutex->unlock(); mymutex->unlock();
return CR_OK; return CR_OK;
} }
DFhackCExport command_result dfusion (Core * c, vector <string> & parameters) void RunDfusion(void *p)
{ {
Console &con=static_cast<Core*>(p)->con;
Console &con=c->con;
mymutex->lock(); mymutex->lock();
lua::state s=lua::glua::Get();
lua::state s=lua::glua::Get();
try{ try{
s.loadfile("dfusion/init.lua"); //load script s.loadfile("dfusion/init.lua"); //load script
s.pcall(0,0);// run it s.pcall(0,0);// run it
@ -151,9 +161,20 @@ DFhackCExport command_result dfusion (Core * c, vector <string> & parameters)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str()); con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
} }
s.settop(0);// clean up s.settop(0);// clean up
mymutex->unlock(); mymutex->unlock();
}
DFhackCExport command_result dfusion (Core * c, vector <string> & parameters)
{
if(thread_dfusion==0)
thread_dfusion=new tthread::thread(RunDfusion,c);
if(parameters[0]!="thready")
{
thread_dfusion->join();
delete thread_dfusion;
thread_dfusion=0;
}
return CR_OK; return CR_OK;
} }

@ -0,0 +1,89 @@
adv_tools=adv_tools or {}
adv_tools.menu=adv_tools.menu or MakeMenu()
function adv_tools.ressurect()
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=GetCreatureAtPos(getxyz())
if indx<0 then indx=0 end
--print(string.format("%x",vector:getval(indx)))
v2=engine.peek(vector:getval(indx),ptr_Creature.hurt1)
for i=0,v2:size()-1 do
v2:setval(i,0)
end
v2=engine.peek(vector:getval(indx),ptr_Creature.hurt2)
v2.type=DWORD
for i=0,v2:size()-1 do
v2:setval(i,0)
end
engine.poke(vector:getval(indx),ptr_Creature.bloodlvl,60000) --give blood
engine.poke(vector:getval(indx),ptr_Creature.bleedlvl,0) --stop some bleeding...
local flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false) --ALIVE
flg:set(39,false) -- leave body yet again
flg:set(37,false) -- something todo with wounds- lets you walk again.
flg:set(58,true) -- makes them able to breathe
flg:set(61,true) -- gives them sight
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
end
function adv_tools.wagonmode() --by rumrusher
--first three lines same as before (because we will need an offset of creature at location x,y,z)
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=GetCreatureAtPos(getxyz())
--indx=0
--print(string.format("%x",vector:getval(indx)))
flg=engine.peek(vector:getval(indx),ptr_Creature.flags) --get flags
flg:set(1,false)
flg:set(74,false)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
print("To stay normal press y, else hit Enter turn Wagon mode on.")
r=io.stdin:read() -- repeat for it too work... also creature will be dead.
if r== "y" then
flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
else
flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false)
flg:flip(74)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
end
end
function selectall()
local retvec={} --return vector (or a list)
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector) --standart start
for i=0,vector:size()-1 do --check all creatures
local off
off=vector:getval(i)
local flags=engine.peek(off,ptr_Creature.flags)
if flags:get(1)==true then --if dead ...
table.insert(retvec,off)--... add it to return vector
end
end
return retvec --return the "return vector" :)
end
function adv_tools.hostilate()
vector=engine.peek(offsets.getEx("AdvCreatureVec"),ptr_vector)
id=GetCreatureAtPos(getxyz())
print(string.format("Vec:%d cr:%d",vector:size(),id))
off=vector:getval(id)
crciv=engine.peek(vector:getval(id),ptr_Creature.civ)
curciv=engine.peek(vector:getval(0),ptr_Creature.civ)
if curciv==crciv then
print("Friendly-making enemy")
engine.poke(off,ptr_Creature.civ,-1)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,true)
engine.poke(off,ptr_Creature.flags,flg)
else
print("Enemy- making friendly")
engine.poke(off,ptr_Creature.civ,curciv)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,false)
flg:set(19,false)
engine.poke(off,ptr_Creature.flags,flg)
end
end

@ -1,89 +0,0 @@
adv_tools=adv_tools or {}
adv_tools.menu=adv_tools.menu or MakeMenu()
function adv_tools.ressurect()
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=GetCreatureAtPos(getxyz())
if indx<0 then indx=0 end
--print(string.format("%x",vector:getval(indx)))
v2=engine.peek(vector:getval(indx),ptr_Creature.hurt1)
for i=0,v2:size()-1 do
v2:setval(i,0)
end
v2=engine.peek(vector:getval(indx),ptr_Creature.hurt2)
v2.type=DWORD
for i=0,v2:size()-1 do
v2:setval(i,0)
end
engine.poke(vector:getval(indx),ptr_Creature.bloodlvl,60000) --give blood
engine.poke(vector:getval(indx),ptr_Creature.bleedlvl,0) --stop some bleeding...
local flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false) --ALIVE
flg:set(39,false) -- leave body yet again
flg:set(37,false) -- something todo with wounds- lets you walk again.
flg:set(58,true) -- makes them able to breathe
flg:set(61,true) -- gives them sight
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
end
function adv_tools.wagonmode() --by rumrusher
--first three lines same as before (because we will need an offset of creature at location x,y,z)
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=GetCreatureAtPos(getxyz())
--indx=0
--print(string.format("%x",vector:getval(indx)))
flg=engine.peek(vector:getval(indx),ptr_Creature.flags) --get flags
flg:set(1,false)
flg:set(74,false)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
print("To stay normal press y, else hit Enter turn Wagon mode on.")
r=io.stdin:read() -- repeat for it too work... also creature will be dead.
if r== "y" then
flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
else
flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false)
flg:flip(74)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
end
end
function selectall()
local retvec={} --return vector (or a list)
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector) --standart start
for i=0,vector:size()-1 do --check all creatures
local off
off=vector:getval(i)
local flags=engine.peek(off,ptr_Creature.flags)
if flags:get(1)==true then --if dead ...
table.insert(retvec,off)--... add it to return vector
end
end
return retvec --return the "return vector" :)
end
function adv_tools.hostilate()
vector=engine.peek(offsets.getEx("AdvCreatureVec"),ptr_vector)
id=GetCreatureAtPos(getxyz())
print(string.format("Vec:%d cr:%d",vector:size(),id))
off=vector:getval(id)
crciv=engine.peek(vector:getval(id),ptr_Creature.civ)
curciv=engine.peek(vector:getval(0),ptr_Creature.civ)
if curciv==crciv then
print("Friendly-making enemy")
engine.poke(off,ptr_Creature.civ,-1)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,true)
engine.poke(off,ptr_Creature.flags,flg)
else
print("Enemy- making friendly")
engine.poke(off,ptr_Creature.civ,curciv)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,false)
flg:set(19,false)
engine.poke(off,ptr_Creature.flags,flg)
end
end

@ -26,7 +26,7 @@ function GetTextRegion()
return nil return nil
end end
function GetRegionIn(pos) function GetRegionIn(pos)
ranges__=ranges__ or Process.getMemRanges() ranges__= Process.getMemRanges()
for k,v in pairs(ranges__) do for k,v in pairs(ranges__) do
--for k2,v2 in pairs(v) do --for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2))) -- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
@ -84,6 +84,8 @@ engine.peekb=Process.readByte
engine.pokeb=Process.writeByte engine.pokeb=Process.writeByte
engine.peekw=Process.readWord engine.peekw=Process.readWord
engine.pokew=Process.writeWord engine.pokew=Process.writeWord
engine.peekstr_stl=Process.readSTLString
engine.pokestr_stl=Process.writeSTLString
engine.peekstr=Process.readCString engine.peekstr=Process.readCString
--engine.pokestr=Process.readCString --engine.pokestr=Process.readCString
engine.peekarb=Process.read engine.peekarb=Process.read
@ -204,7 +206,7 @@ end
function it_menu:display() function it_menu:display()
print("Select choice (q exits):") print("Select choice (q exits):")
for p,c in pairs(self.items) do for p,c in pairs(self.items) do
print(p..")."..c[2]) print(string.format("%3d).%s",p,c[2]))
end end
local ans local ans
repeat repeat
@ -438,7 +440,7 @@ function ParseNames(path)
end end
function getxyz() -- this will return pointers x,y and z coordinates. function getxyz() -- this will return pointers x,y and z coordinates.
local off=offsets.getEx("Xpointer") -- lets find where in memory its being held local off=VersionInfo.getGroup("Position"):getAddress("cursor_xyz") -- lets find where in memory its being held
-- now lets read them (they are double words (or unsigned longs or 4 bits each) and go in sucesion -- now lets read them (they are double words (or unsigned longs or 4 bits each) and go in sucesion
local x=engine.peekd(off) local x=engine.peekd(off)
local y=engine.peekd(off+4) --next is 4 from start local y=engine.peekd(off+4) --next is 4 from start
@ -448,8 +450,8 @@ function getxyz() -- this will return pointers x,y and z coordinates.
end end
function GetCreatureAtPos(x,y,z) -- gets the creature index @ x,y,z coord function GetCreatureAtPos(x,y,z) -- gets the creature index @ x,y,z coord
--local x,y,z=getxyz() --get 'X' coords --local x,y,z=getxyz() --get 'X' coords
local vector=engine.peek(offsets.getEx("AdvCreatureVec"),ptr_vector) -- load all creatures local vector=engine.peek(VersionInfo.getGroup("Creatures"):getAddress("vector"),ptr_vector) -- load all creatures
for i = 0, vector:size() do -- look into all creatures offsets for i = 0, vector:size()-1 do -- look into all creatures offsets
local curoff=vector:getval(i) -- get i-th creatures offset local curoff=vector:getval(i) -- get i-th creatures offset
local cx=engine.peek(curoff,ptr_Creature.x) --get its coordinates local cx=engine.peek(curoff,ptr_Creature.x) --get its coordinates
local cy=engine.peek(curoff,ptr_Creature.y) local cy=engine.peek(curoff,ptr_Creature.y)

@ -0,0 +1,45 @@
function analyzeF(off)
pos=offsets.find(off,0x39,ANYBYTE,0x8c,00,00,00)
print(string.format("Compare at:%x",pos))
if pos ==0 then
return 0
end
if(pos-off>0x100) then
print(string.format("Distance to cmp:%x",pos-off))
pos =offsets.find(off,CALL)
print(string.format("Distance to call:%x",pos-off))
return 0
--return analyzeF(pos)
else
return pos
end
end
function minEx(...)
local imin=arg[1]
for _,v in ipairs(arg) do
if imin> v and v~=0 then
imin=v
end
end
return imin
end
function signDword(dw)
if(dw>0xFFFFFFFF) then
return dw-0xFFFFFFFF
end
return dw
end
--[[
Warning: not all mov's are acounted for. Found one: mov EAX,WORD PTR[EBP+1EF4] WTF??
Two more compares are missing. There are calls instead (same function)
]]--
friendship_in={}
dofile("dfusion/friendship/install.lua")
dofile("dfusion/friendship/patch.lua")
function friendship(names)
friendship_in.install(names)
friendship_in.patch()
end

@ -1,65 +1,19 @@
--if(mypos~=0) then
--print("plugin already active")
--maybe set options for reinit?
--return
--end
function analyzeF(off)
pos=offsets.find(off,0x39,ANYBYTE,0x8c,00,00,00)
print(string.format("Compare at:%x",pos))
if pos ==0 then
return 0
end
if(pos-off>0x100) then
print(string.format("Distance to cmp:%x",pos-off))
pos =offsets.find(off,CALL)
print(string.format("Distance to call:%x",pos-off))
return 0
--return analyzeF(pos)
else
return pos
end
end
function minEx(...)
local imin=arg[1]
for _,v in ipairs(arg) do
if imin> v and v~=0 then
imin=v
end
end
return imin
end
function signDword(dw)
if(dw>0xFFFFFFFF) then
return dw-0xFFFFFFFF
end
return dw
end
--[[
Warning: not all mov's are acounted for. Found one: mov EAX,WORD PTR[EBP+1EF4] WTF??
Two more compares are missing. There are calls instead (same function)
]]--
if not(FILE) then if not(FILE) then
--print("race num:"..engine.peekw(offsets.getEx("CurrentRace"))) --sanity test
--print(string.format("%x vs %x",offsets.getEx("CurrentRace"),VersionInfo.getGroup("Creatures"):getAddress("current_race"))) --print("race num:"..engine.peekw(offsets.getEx("CurrentRace")))
add_race=VersionInfo.getGroup("Creatures"):getAddress("current_race") --print(string.format("%x vs %x",offsets.getEx("CurrentRace"),VersionInfo.getGroup("Creatures"):getAddress("current_race")))
print("Race num:"..engine.peekw(add_race)) add_race=VersionInfo.getGroup("Creatures"):getAddress("current_race")
print("Your current race is:"..GetRaceToken(engine.peekw(add_race))) print("Race num:"..engine.peekw(add_race))
print("If this is wrong please type 'q'") print("Your current race is:"..GetRaceToken(engine.peekw(add_race)))
if(io.stdin:read()=='q') then print("If this is wrong please type 'q'")
return if(io.stdin:read()=='q') then
end return
end
end end
friendship_in={}
dofile("dfusion/friendship/install.lua")
dofile("dfusion/friendship/patch.lua")
if not(FILE) then if not(FILE) then
names=ParseNames("dfusion/friendship/races.txt")--io.open("plugins/friendship/races.txt"):lines() names=ParseNames("dfusion/friendship/races.txt")--io.open("plugins/friendship/races.txt"):lines()
friendship_in.install(names) friendship_in.install(names)
friendship_in.patch() friendship_in.patch()
end end
function friendship(names)
friendship_in.install(names)
friendship_in.patch()
end

@ -13,13 +13,23 @@ function dofile(filename) --safer dofile, with traceback (very usefull)
print(perr) print(perr)
end end
end end
function dofile_silent(filename) --safer dofile, with traceback, no file not found error
f,perr=loadfile(filename)
if f~=nil then
return xpcall(f,err)
end
end
function loadall(t1) --loads all non interactive plugin parts, so that later they could be used
for k,v in pairs(t1) do
dofile_silent("dfusion/"..v[1].."/init.lua")
end
end
function mainmenu(t1) function mainmenu(t1)
Console.clear() Console.clear()
while true do while true do
print("No. Name Desc") print("No. Name Desc")
for k,v in pairs(t1) do for k,v in pairs(t1) do
print(string.format("%d %s %s",k,v[1],v[2])) print(string.format("%3d %15s %s",k,v[1],v[2]))
end end
local q=Console.lineedit("Select plugin to run (q to quit):") local q=Console.lineedit("Select plugin to run (q to quit):")
if q=='q' then return end if q=='q' then return end
@ -44,5 +54,9 @@ table.insert(plugins,{"adv_tools","some tools for (mainly) advneturer hacking"})
table.insert(plugins,{"tools","some misc tools"}) table.insert(plugins,{"tools","some misc tools"})
table.insert(plugins,{"triggers","a function calling plug (discontinued...)"}) table.insert(plugins,{"triggers","a function calling plug (discontinued...)"})
table.insert(plugins,{"migrants","multi race imigrations"}) table.insert(plugins,{"migrants","multi race imigrations"})
table.insert(plugins,{"onfunction","run lua on some df function"})
loadall(plugins)
if not INIT then
mainmenu(plugins) mainmenu(plugins)
end

@ -1,6 +1,8 @@
function f_dwarves() function f_dwarves()
--mov DWORD PTR [ESP+14],7
--jmp +0x08
pos_=offsets.findall(0,0x24,0x14,0x07,0,0,0) --search pattern pos_=offsets.findall(0,0x24,0x14,0x07,0,0,0) --search pattern
for _,v in pairs(pos_) do for _,v in pairs(pos_) do
print(string.format("Possible hit:%x",v)) print(string.format("Possible hit:%x",v))

@ -0,0 +1 @@
as -anl --32 -o functions.o functions.asm

@ -0,0 +1,23 @@
.intel_syntax
push eax
push ebp
push esp
push esi
push edi
push edx
push ecx
push ebx
push eax
mov eax,[esp+36]
push eax
function:
call 0xdeadbee0
function2:
mov [0xdeadbeef],eax
pop eax
function3:
jmp [0xdeadbeef]

@ -0,0 +1,61 @@
onfunction=onfunction or {}
function onfunction.install()
ModData=engine.installMod("dfusion/onfunction/functions.o","functions",4)
modpos=ModData.pos
modsize=ModData.size
onfunction.pos=modpos
trgpos=engine.getpushvalue()
print(string.format("Function installed in:%x function to call is: %x",modpos,trgpos))
local firstpos=modpos+engine.FindMarker(ModData,"function")
engine.poked(firstpos,trgpos-firstpos-4) --call Lua-Onfunction
onfunction.fpos=modpos+engine.FindMarker(ModData,"function3")
engine.poked(modpos+engine.FindMarker(ModData,"function2"),modpos+modsize)
engine.poked(onfunction.fpos,modpos+modsize)
SetExecute(modpos)
onfunction.calls={}
onfunction.functions={}
onfunction.names={}
onfunction.hints={}
end
function OnFunction(values)
--[=[print("Onfunction called!")
print("Data:")
for k,v in pairs(values) do
print(string.format("%s=%x",k,v))
end
print("stack:")
for i=0,3 do
print(string.format("%d %x",i,engine.peekd(values.esp+i*4)))
end
--]=]
if onfunction.functions[values.ret] ~=nil then
onfunction.functions[values.ret](values)
end
return onfunction.calls[values.ret] --returns real function to call
end
function onfunction.patch(addr)
if(engine.peekb(addr)~=0xe8) then
error("Incorrect address, not a function call")
else
onfunction.calls[addr+5]=addr+engine.peekd(addr+1)+5 --adds real function to call
engine.poked(addr+1,engine.getmod("functions")-addr-5)
end
end
function onfunction.AddFunction(addr,name,hints)
onfunction.patch(addr)
onfunction.names[name]=addr+5
if hints~=nil then
onfunction.hints[name]=hints
end
end
function onfunction.SetCallback(name,func)
if onfunction.names[name]==nil then
error("No such function:"..name)
else
onfunction.functions[onfunction.names[name]]=func
end
end

@ -0,0 +1,7 @@
if WINDOWS then --windows function defintions
onfunction.AddFunction(0x55499D+offsets.base(),"Move") --on creature move found with "watch mem=xcoord"
onfunction.AddFunction(0x275933+offsets.base(),"Die",{creature="edi"}) --on creature death? found by watching dead flag then stepping until new function
else --linux
onfunction.AddFunction(0x899befe+offsets.base(),"Move") -- found out by attaching watch...
onfunction.AddFunction(0x850eecd+offsets.base(),"Die",{creature="ebx"}) -- same
end

@ -0,0 +1,14 @@
mypos=engine.getmod("functions")
function DeathMsg(values)
local name
name=engine.peek(values[onfunction.hints["Die"].creature],ptt_dfstring)
print(name:getval().." died")
end
if mypos then
print("Onfunction already installed")
--onfunction.patch(0x189dd6+offsets.base())
else
onfunction.install()
dofile("dfusion/onfunction/locations.lua")
onfunction.SetCallback("Die",DeathMsg)
end

@ -1,50 +1,51 @@
ptt_dfstring={} ptt_dfstring={}
if(COMPATMODE) then if WINDOWS then
ptt_dfstring.ptr={off=4,rtype=DWORD} ptt_dfstring.ptr={off=0,rtype=DWORD}
ptt_dfstring.size={off=20,rtype=DWORD} ptt_dfstring.size={off=16,rtype=DWORD}
ptt_dfstring.alloc={off=20,rtype=DWORD}
else function ptt_dfstring:getval()
ptt_dfstring.ptr={off=0,rtype=DWORD}
ptt_dfstring.size={off=16,rtype=DWORD}
ptt_dfstring.alloc={off=20,rtype=DWORD}
end
function ptt_dfstring:getval()
--print(string.format("GETTING FROM:%x",self.__offset))
if self.size<16 then
--print(string.format("GETTING FROM:%x",self.__offset)) --print(string.format("GETTING FROM:%x",self.__offset))
return string.sub(engine.peekstr(self.__offset),1,self.size) if self.size<16 then
else --print(string.format("GETTING FROM:%x",self.__offset))
--print(string.format("GETTING FROM:%x",self.ptr)) return string.sub(engine.peekstr(self.__offset),1,self.size)
return string.sub(engine.peekstr(self.ptr),1,self.size) else
--print(string.format("GETTING FROM:%x",self.ptr))
return string.sub(engine.peekstr(self.ptr),1,self.size)
end
end end
end function ptt_dfstring:setval(newstring)
function ptt_dfstring:setval(newstring) local offset=self.__offset
local offset=self.__offset local strl=string.len(newstring)
local strl=string.len(newstring) if strl<16 then
if strl<16 then --print(string.format("GETTING FROM:%x",self.__offset))
--print(string.format("GETTING FROM:%x",self.__offset))
engine.poked(offset+ptt_dfstring.size.off,strl) engine.poked(offset+ptt_dfstring.size.off,strl)
engine.poked(offset+ptt_dfstring.alloc.off,15) engine.poked(offset+ptt_dfstring.alloc.off,15)
engine.pokestr(offset,newstring) engine.pokestr(offset,newstring)
else
local loc
if engine.peekd(offset+ptt_dfstring.alloc.off) > strl then
loc=engine.peekd(offset)
print("Will fit:"..loc.." len:"..strl)
else else
loc=Allocate(strl+1) local loc
engine.poked(offset+ptt_dfstring.alloc.off,strl) if engine.peekd(offset+ptt_dfstring.alloc.off) > strl then
print("Will not fit:"..loc.." len:"..strl) loc=engine.peekd(offset)
print("Will fit:"..loc.." len:"..strl)
else
loc=Allocate(strl+1)
engine.poked(offset+ptt_dfstring.alloc.off,strl)
print("Will not fit:"..loc.." len:"..strl)
end
--print(string.format("GETTING FROM:%x",self.ptr))
engine.poked(self.__offset+ptt_dfstring.size.off,strl)
engine.pokestr(loc,newstring)
engine.poked(self.__offset,loc)
end end
--print(string.format("GETTING FROM:%x",self.ptr)) end
engine.poked(self.__offset+ptt_dfstring.size.off,strl) else
engine.pokestr(loc,newstring) --ptt_dfstring.ptr={off=0,rtype=DWORD}
engine.poked(self.__offset,loc) function ptt_dfstring:getval()
return engine.peekstr_stl(self.__offset)
end end
end end
--if(COMPATMODE) then --if(COMPATMODE) then
--ptr_vector={} --ptr_vector={}
--ptr_vector.st={off=4,rtype=DWORD} --ptr_vector.st={off=4,rtype=DWORD}
@ -169,10 +170,11 @@ end
]]-- ]]--
ptr_Creature={} ptr_Creature={}
ptr_Creature.x={off=144,rtype=WORD} --ok local posoff=VersionInfo.getGroup("Creatures"):getGroup("creature"):getOffset("position")
ptr_Creature.y={off=146,rtype=WORD} --ok ptr_Creature.x={off=posoff,rtype=WORD} --ok
ptr_Creature.z={off=148,rtype=WORD} --ok ptr_Creature.y={off=posoff+2,rtype=WORD} --ok
ptr_Creature.flags={off=224,rtype=ptt_dfflag.new(10)} ptr_Creature.z={off=posoff+4,rtype=WORD} --ok
ptr_Creature.flags={off=VersionInfo.getGroup("Creatures"):getGroup("creature"):getOffset("flags1"),rtype=ptt_dfflag.new(10)}
ptr_Creature.name={off=0,rtype=ptt_dfstring} ptr_Creature.name={off=0,rtype=ptt_dfstring}
ptr_Creature.ID={off=252,rtype=DWORD} --ok i guess ptr_Creature.ID={off=252,rtype=DWORD} --ok i guess
ptr_Creature.followID={off=592,rtype=DWORD} --ok ptr_Creature.followID={off=592,rtype=DWORD} --ok

@ -4,7 +4,7 @@ function func.Find_Print()
end end
function func.PrintMessage(msg,color1,color2) function func.PrintMessage(msg,color1,color2)
func.f_print_pos= func.f_print_pos or func.Find_Print() func.f_print_pos= func.f_print_pos or func.Find_Print()
--print(string.format("%x",func.f_print_pos)) print(string.format("Print @:%x",func.f_print_pos))
debuger.suspend() debuger.suspend()
d=NewCallTable() -- make a call table d=NewCallTable() -- make a call table
t=Allocate(string.len(msg)) t=Allocate(string.len(msg))

@ -129,6 +129,40 @@ static int GetMod(lua_State *L)
st.push(pos); st.push(pos);
return 1; return 1;
} }
static size_t __attribute__((stdcall)) PushValue(size_t ret,uint32_t eax,uint32_t ebx,uint32_t ecx,uint32_t edx,uint32_t edi,uint32_t esi,uint32_t esp,uint32_t ebp)
{
lua::state st=lua::glua::Get();
st.getglobal("OnFunction");
if(st.is<lua::nil>())
return 0;
st.newtable();
st.push(eax);
st.setfield("eax");
st.push(ebx);
st.setfield("ebx");
st.push(ecx);
st.setfield("ecx");
st.push(edx);
st.setfield("edx");
st.push(edi);
st.setfield("edi");
st.push(esi);
st.setfield("esi");
st.push(esp);
st.setfield("esp");
st.push(ebp);
st.setfield("ebp");
st.push(ret);
st.setfield("ret");
st.pcall(1,1);
return st.as<uint32_t>();
}
static int Get_PushValue(lua_State *L)
{
lua::state st(L);
st.push((uint32_t)&PushValue);
return 1;
}
const luaL_Reg lua_misc_func[]= const luaL_Reg lua_misc_func[]=
{ {
{"loadmod",LoadMod}, {"loadmod",LoadMod},
@ -137,6 +171,7 @@ const luaL_Reg lua_misc_func[]=
{"loadobjsymbols",LoadObjSymbols}, {"loadobjsymbols",LoadObjSymbols},
{"findmarker",FindMarker}, {"findmarker",FindMarker},
{"newmod",NewMod}, {"newmod",NewMod},
{"getpushvalue",Get_PushValue},
{NULL,NULL} {NULL,NULL}
}; };
void lua::RegisterMisc(lua::state &st) void lua::RegisterMisc(lua::state &st)

@ -0,0 +1,114 @@
#include <dfhack/Core.h>
#include <dfhack/Console.h>
#include <dfhack/PluginManager.h>
#include <dfhack/Process.h>
#include <dfhack/extra/stopwatch.h>
#include <string>
#include <vector>
#include <sstream>
using std::vector;
using std::string;
using namespace DFHack;
DFhackCExport command_result memview (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "memview";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("memview","Shows memory in real time. Params: adrr length refresh_rate.",memview));
return CR_OK;
}
size_t convert(const std::string& p,bool ishex=false)
{
size_t ret;
std::stringstream conv;
if(ishex)
conv<<std::hex;
conv<<p;
conv>>ret;
return ret;
}
bool isAddr(uint32_t *trg,vector<t_memrange> & ranges)
{
if(trg[0]%4==0)
for(size_t i=0;i<ranges.size();i++)
if(ranges[i].isInRange(trg[0]))
return true;
return false;
}
void outputHex(uint8_t *buf,uint8_t *lbuf,size_t len,size_t start,Console &con,vector<t_memrange> & ranges)
{
con.clear();
const size_t page_size=16;
for(size_t i=0;i<len;i+=page_size)
{
con.print("%8x ",i+start);
for(size_t j=0;(j<page_size) && (i+j<len);j++)
{
if(j%4==0)
{
con.reset_color();
if(isAddr((uint32_t *)(buf+j+i),ranges))
con.color(Console::COLOR_LIGHTRED);
}
if(lbuf[j+i]!=buf[j+i])
con.print("*%2x",buf[j+i]);
else
con.print(" %2x",buf[j+i]);
}
con.reset_color();
con.print(" | ");
for(size_t j=0;(j<page_size) && (i+j<len);j++)
if(buf[j+i]>20)
con.print("%c",buf[j+i]);
else
con.print(".");
con.print("\n");
}
}
DFhackCExport command_result memview (Core * c, vector <string> & parameters)
{
size_t addr=convert(parameters[0],true);
size_t len;
if(parameters.size()>1)
len=convert(parameters[1]);
else
len=20*16;
size_t refresh;
if(parameters.size()>2)
refresh=convert(parameters[2]);
else
refresh=0;
Console &con=c->con;
uint8_t *buf,*lbuf;
buf=new uint8_t[len];
lbuf=new uint8_t[len];
uint64_t timeLast=0;
vector<t_memrange> ranges;
c->p->getMemRanges(ranges);
while(true)//TODO add some sort of way to exit loop??!!
{
uint64_t time2 = GetTimeMs64();
uint64_t delta = time2-timeLast;
if(refresh!=0)
if(delta<refresh)
continue;
timeLast = time2;
c->p->read(addr,len,buf);
outputHex(buf,lbuf,len,addr,con,ranges);
if(refresh==0)
break;
memcpy(lbuf, buf, len);
}
delete[] buf;
delete[] lbuf;
}