Ported items plugin with more stuff

develop
Warmist 2011-08-03 17:59:06 +03:00
parent e98e4a5111
commit ef4a459214
7 changed files with 665 additions and 32 deletions

@ -25,6 +25,8 @@ public:
std::vector<uint64_t> FindAll(); std::vector<uint64_t> FindAll();
private: private:
bool Compare(int a,int b);
void ReparseArgs();
SearchArgType args_; SearchArgType args_;
uint64_t pos_,startpos_,endpos_; uint64_t pos_,startpos_,endpos_;
std::vector<int> BadCharShifts,GoodSuffixShift; std::vector<int> BadCharShifts,GoodSuffixShift;

@ -17,6 +17,12 @@ offsets.load = function ()
end end
end end
offsets.load() offsets.load()
STD_STRING=0
DWORD=1
WORD=2
BYTE=3
function GetTextRegion() function GetTextRegion()
local ranges=Process.getMemRanges() local ranges=Process.getMemRanges()
for k,v in pairs(ranges) do for k,v in pairs(ranges) do
@ -50,6 +56,358 @@ end
engine=engine or {} engine=engine or {}
engine.peekd=Process.readDWord engine.peekd=Process.readDWord
engine.poked=Process.writeDWord engine.poked=Process.writeDWord
engine.peekb=Process.readByte
engine.pokeb=Process.writeByte
engine.peekw=Process.readWord
engine.pokew=Process.writeWord
engine.peekstr=Process.readCString
--engine.pokestr=Process.readCString
engine.peekarb=Process.read
engine.pokearb=Process.write
function engine.peek(offset,rtype)
if type(rtype)=="table" then
if rtype.off ==nil then
return engine.peekpattern(offset,rtype)
else
return engine.peek(rtype.off+offset,rtype.rtype)
end
end
if rtype==STD_STRING then
return engine.peekstr(offset)
elseif rtype==DWORD then
return engine.peekd(offset)
elseif rtype==WORD then
return engine.peekw(offset)
elseif rtype==BYTE then
return engine.peekb(offset)
else
error("Invalid peek type")
return
end
end
function engine.poke(offset,rtype,val)
if type(rtype)=="table" then
if rtype.off ==nil then
return engine.pokepattern(offset,rtype,val)
else
return engine.poke(rtype.off+offset,rtype.rtype,val)
end
end
if rtype==STD_STRING then
return engine.pokestr(offset,val)
elseif rtype==DWORD then
return engine.poked(offset,val)
elseif rtype==WORD then
return engine.pokew(offset,val)
elseif rtype==BYTE then
return engine.pokeb(offset,val)
else
error("Invalid poke type:"..tostring(rtype))
return
end
end
function engine.sizeof(rtype)
if rtype==STD_STRING then
error("String has no constant size")
return
elseif rtype==DWORD then
return 4;
elseif rtype==WORD then
return 2;
elseif rtype==BYTE then
return 1;
else
error("Invalid sizeof type")
return
end
end
function engine.peekpattern(offset,pattern)
local ret={}
for k,v in pairs(pattern) do
--print("k:"..k.." v:"..type(v))
if type(v)=="table" then
ret[k]=engine.peek(offset+v.off,v.rtype)
--print(k.." peeked:"..offset+v.off)
else
ret[k]=v
end
end
ret.__offset=offset
return ret
end
function engine.pokepattern(offset,pattern,val)
for k,v in pairs(pattern) do
--print("k:"..k.." v:"..type(v))
if type(v)=="table" then
engine.poke(offset+v.off,v.rtype,val[k])
end
end
end
it_menu={}
it_menu.__index=it_menu
function it_menu:add(name,func)
table.insert(self.items,{func,name})
end
function it_menu:display()
print("Select choice (q exits):")
for p,c in pairs(self.items) do
print(p..")."..c[2])
end
local ans
repeat
local r
r=io.stdin:read()
if r=='q' then return end
ans=tonumber(r)
if ans==nil or not(ans<=table.maxn(self.items) and ans>0) then
print("incorrect choice")
end
until ans~=nil and (ans<=table.maxn(self.items) and ans>0)
self.items[ans][1]()
end
function MakeMenu()
local ret={}
ret.items={}
setmetatable(ret,it_menu)
return ret
end
function PrintPattern(loadedpattern)
for k,v in pairs(loadedpattern) do
if type(v)== "string" then
print(k.." "..v)
else
print(string.format("%s %d inhex:%x",k,v,v))
end
end
end
function printPattern(pattern)
local i=0;
local names={}
names[STD_STRING]="std_string (STD_STRING)"
names[DWORD]= "Double word (DWORD)"
names[WORD]= "Word (WORD)"
names[STD_STRING]="Byte (BYTE)"
ret={}
for k,v in pairs(pattern) do
if type(v)=="table" and v.off~=nil then
if names[v.rtype]~=nil then
lname=names[v.rtype]
else
if type(v.rtype)=="table" then
lname="Table (prob subpattern)"
else
lname="Other"
end
end
print(string.format("%d. %s is %s with offset %x",i,k,lname,v.off))
table.insert(ret,k)
else
print(string.format("%d. %s",i,k))
end
i=i+1
end
return ret;
end
function editPattern(offset,pattern,name)
if type(pattern[name].rtype)=="table" then
if pattern[name].rtype.setval~=nil then
print(string.format("%x",offset+pattern[name].off))
local t=engine.peek(offset+pattern[name].off,pattern[name].rtype)
print("Value is now:"..t:getval())
print("Enter new value:")
val=io.stdin:read()
t:setval(val)
else
ModPattern(offset+pattern[name].off,pattern[name].rtype)
end
return
end
val=engine.peek(offset,pattern[name])
print("Value is now:"..val)
print("Enter new value:")
if pattern[name].rtype==STD_STRING then
val=io.stdin:read()
else
val=tonumber(io.stdin:read())
end
engine.poke(offset,pattern[name],val)
end
function ModPattern(itemoffset,pattern)
print("Select what to edit:")
nm=printPattern(pattern)
q=tonumber(io.stdin:read())
if q~=nil and q<#nm then
editPattern(itemoffset,pattern,nm[q+1])
end
end
function findVectors()
local text=GetTextRegion()
local h=hexsearch(text.start,text["end"],0x8b,ANYBYTE,ANYDWORD,0x8b,ANYBYTE,ANYDWORD,0x2b,ANYBYTE)
local pos=h:findall()
local T={}
for k,v in pairs(pos) do
local loc1,loc2
loc1=engine.peekd(v+2)
loc2=engine.peekd(v+8)
--print(string.format("%x - %x=%x",loc1,loc2,loc1-loc2))
if(math.abs(loc1-loc2)==4) then
if T[loc1-4]~=nil then
T[loc1-4]=T[loc1-4]+1
else
T[loc1-4]=1
end
end
end
return T
end
function GetRaceToken(p) --actually gets token...
local vec=engine.peek(offsets.getEx('CreatureGloss'),ptr_vector)
local off=vec:getval(p)
local crgloss=engine.peek(off,ptr_CrGloss)
return crgloss.token:getval()
end
function BuildNameTable()
local rtbl={}
local vec=engine.peek(offsets.getEx('CreatureGloss'),ptr_vector)
--print(string.format("Vector start:%x",vec.st))
--print(string.format("Vector end:%x",vec.en))
--local i=0
for p=0,vec:size()-1 do
local off=vec:getval(p)
--print("First member:"..off)
local name=engine.peek(off,ptt_dfstring)
--print("Loading:"..p.."="..name:getval())
rtbl[name:getval()]=p
--i=i+1
--if i>100 then
-- io.stdin:read()
-- i=0
--end
end
return rtbl;
end
function BuildMaterialTable()
local rtbl={}
local vec=engine.peek(offsets.getEx('Materials'),ptr_vector)
--print(string.format("Vector start:%x",vec.st))
--print(string.format("Vector end:%x",vec.en))
--local i=0
for p=0,vec:size()-1 do
local off=vec:getval(p)
--print("First member:"..off)
local name=engine.peek(off,ptt_dfstring)
--print("Loading:"..p.."="..name:getval())
rtbl[name:getval()]=p
--i=i+1
--if i>100 then
-- io.stdin:read()
-- i=0
--end
end
return rtbl;
end
function BuildWordTables()
local names={}
local rnames={}
local vector=engine.peek(offsets.getEx('WordVec'),ptr_vector)
for i =0,vector:size()-1 do
local off=vector:getval(i)
local n=engine.peekstr(off)
names[i]=n
rnames[n]=i
end
return names,rnames
end
function ParseScript(file)
io.input(file)
f=""
first=0
nobraces=0
function updFunction()
if f~="" then
first=0
if nobraces==0 then
f=f.."}"
end
nobraces=0
print("Doing:"..f)
assert(loadstring(f))()
f=""
end
end
while true do
local line = io.read("*line")
if line == nil then break end
if string.sub(line,1,2)==">>" then
updFunction()
if string.find(line,"%b()") then
f=string.sub(line,3)
nobraces=1
else
f=string.sub(line,3).."{"
end
--print(string.sub(line,3)..)
else
if first~=0 then
f=f..","
else
first=1
end
f=f..string.format('%q',line)
end
end
updFunction()
end
function ParseNames(path)
local ret={}
local ff=io.open(path)
for n in ff:lines() do
table.insert(ret,n)
end
return ret
end
function getxyz() -- this will return pointers x,y and z coordinates.
local off=offsets.getEx("Xpointer") -- 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
local x=engine.peekd(off)
local y=engine.peekd(off+4) --next is 4 from start
local z=engine.peekd(off+8) --next is 8 from start
--print("Pointer @:"..x..","..y..","..z)
return x,y,z -- return the coords
end
function GetCreatureAtPos(x,y,z) -- gets the creature index @ x,y,z coord
--local x,y,z=getxyz() --get 'X' coords
local vector=engine.peek(offsets.getEx("AdvCreatureVec"),ptr_vector) -- load all creatures
for i = 0, vector:size() do -- look into all creatures offsets
local curoff=vector:getval(i) -- get i-th creatures offset
local cx=engine.peek(curoff,ptr_Creature.x) --get its coordinates
local cy=engine.peek(curoff,ptr_Creature.y)
local cz=engine.peek(curoff,ptr_Creature.z)
if cx==x and cy==y and cz==z then --compare them
return i --return index
end
end
print("Creature not found!")
return -1
end
dofile("dfusion/patterns.lua") dofile("dfusion/patterns.lua")
dofile("dfusion/patterns2.lua") dofile("dfusion/patterns2.lua")

@ -10,31 +10,30 @@ function dofile(filename) --safer dofile, with traceback (very usefull)
print(perr) print(perr)
end end
end end
dofile("dfusion/common.lua")
print("Unlocking Df .text section...")
--unlockDF()
print("Done unlock")
text=GetTextRegion()
h=hexsearch(text.start,text["end"],0x73,0x02,0x8b,0xce,0x53,0x6a,0x01,0x6a,0x06)
pos=h:findall()
for k,v in pairs(pos) do
print(k..v)
end
--hexsearch.delete(h)
lockDF() --DOES NOT WORK?!
--dofile("dfusion/simple_embark/plugin.lua")
--print("hello world")
--Console.print("Hello world in console!\n")
--name=Console.lineedit("Enter name:")
--Console.print("Your name is:"..name)
function OnTick() -- floods the console function mainmenu(t1)
r=Console.get_rows()
c=Console.get_columns()
Console.clear() Console.clear()
Console.gotoxy(math.random(1,r),math.random(1,2)) while true do
Console.color(math.random(0,15)) print("No. Name Desc")
Console.print("*") for k,v in pairs(t1) do
print(string.format("%d %s %s",k,v[1],v[2]))
end
local q=Console.lineedit("Select plugin to run (q to quit):")
if q=='q' then return end
q=tonumber(q)
if q~=nil then
if q>=1 and q<=#t1 then
dofile("dfusion/"..t1[q][1].."/plugin.lua")
end
end
end
end end
OnTick=nil dofile("dfusion/common.lua")
unlockDF()
plugins={}
table.insert(plugins,{"simple_embark","A simple embark dwarf count editor"})
table.insert(plugins,{"items","A collection of item hacking tools"})
mainmenu(plugins)

@ -0,0 +1,212 @@
items={} --> first lets make a menu table
items.menu=MakeMenu()
function items.dest()
myoff=offsets.getEx("Items") -- first find out where "item vector" is
vector=engine.peek(myoff,ptr_vector) -- get list of items
for i=0,vector:size()-1 do --look at each item
flg=engine.peek(vector:getval(i),ptr_item.flags)
flg:set(17,1)
engine.poke(vector:getval(i),ptr_item.flags,flg)
end
end
function items.eggs()
myoff=offsets.getEx("Items") -- first find out where "item vector" is
vector=engine.peek(myoff,ptr_vector) -- get list of items
for i=0,vector:size()-1 do --look at each item
rti=engine.peek(vector:getval(i),ptr_item.RTI)
if ptr_item.getname(nil,rti)=="item_eggst" then
egg=engine.peek(vector:getval(i),ptr_subitems["item_eggst"])
egg.isfertile=1
egg.hatchtime=0xffffff
--egg.race=123 -- change race for fun times
engine.poke(vector:getval(i),ptr_subitems["item_eggst"],egg)
end
end
end
function editFlags(offset)
while true do
flags=engine.peek(offset,ptr_item.flags)
for i=0,8*8-1 do
if flags:get(i) then
print(i.." is true")
else
print(i.." is false")
end
end
print(" enter number to switch flag or not a number to quit:")
q=tonumber(io.stdin:read())
if q==nil then return end
flags:flip(q)
engine.poke(offset,ptr_item.flags,flags)
end
end
function editCovering(offset)
off=engine.peek(offset,ptr_item.ptr_covering)
if off == 0 then
print("No coverings found.")
end
vec=engine.peek(off,ptr_vector)
print("Covering list:")
for i=0,vec:size()-1 do
cov=engine.peek(vec:getval(i),ptr_cover)
print(string.format("%d. mat=%d submat=%d state=%d",i,cov.mat,cov.submat,cov.state))
end
print("To edit type number:")
q=tonumber(io.stdin:read())
if q==nil then return end
if q>=vec:size() or q<0 then return end
off=vec:getval(q)
cov=engine.peek(off,ptr_cover)
print("Enter mat:")
q=tonumber(io.stdin:read())
if q==nil then q=0xffff end
print("Enter submat:")
v=tonumber(io.stdin:read())
if v==nil then v=0xffff end
print("Enter state:")
y=tonumber(io.stdin:read())
if y==nil then y=0 end
cov.mat=q
cov.submat=v
cov.state=y
engine.poke(off,ptr_cover,cov)
end
function editMaterial(offset)
print("Mat id 0 to 18 is in normal materials (inorganic, amber etc...) after that creature mat (with submat2 being race)")
print("from 219 with submat2=0xffffffff (type not a number) it reads legends id, from 419 submat2 means plant id")
print("Probably submat is not used :? ")
mat=engine.peek(offset,ptr_item.mat)
submat=engine.peek(offset,ptr_item.submat)
submat2=engine.peek(offset,ptr_item.submat2)
lid=engine.peek(offset,ptr_item.legendid)
print(string.format("Now is mat=%d, submat=%d submat2=%d legend id=%d",mat,submat,submat2,lid))
print("Enter mat:")
q=tonumber(io.stdin:read())
if q==nil then return end
print("Enter submat:")
v=tonumber(io.stdin:read())
if v==nil then v=0xffff end
print("Enter submat2:")
z=tonumber(io.stdin:read())
if z==nil then z=0xffffffff end
print("Enter legendid:")
y=tonumber(io.stdin:read())
if y==nil then y=0xffffffff end
engine.poke(offset,ptr_item.mat,q)
engine.poke(offset,ptr_item.submat,v)
engine.poke(offset,ptr_item.legendid,y)
engine.poke(offset,ptr_item.submat2,z)
print("Done")
end
function items.select()
myoff=offsets.getEx("Items")
vector=engine.peek(myoff,ptr_vector)
tx,ty,tz=getxyz()
T={}
for i=0,vector:size()-1 do --this finds all item offsets that are on pointer
itoff=vector:getval(i)
x=engine.peek(itoff,ptr_item.x)
y=engine.peek(itoff,ptr_item.y)
z=engine.peek(itoff,ptr_item.z)
if x==tx and y==ty and z==tz then
table.insert(T,itoff)
end
end
print("Items under cursor:")
i=1
for _,v in pairs(T) do
RTI=engine.peek(v,ptr_item.RTI)
print(i..". "..ptr_item.getname(nil,RTI))
i=i+1
end
print("Type number to edit or 'q' to exit")
while true do
q=io.stdin:read()
if q=='q' then return end
if tonumber(q) ~=nil and tonumber(q)<i then break end
end
return T[tonumber(q)]
end
function items.select_creature(croff)
vector=engine.peek(croff,ptr_Creature.itemlist2)
print("Vector size:"..vector:size())
T={}
for i=0,vector:size()-1 do
table.insert(T,vector:getval(i)) -- item list is itemptr+location?
end
print("Items in inventory:")
i=1
for _,v in pairs(T) do
RTI=engine.peek(engine.peekd(v),ptr_item.RTI)
print(i..". "..ptr_item.getname(nil,RTI).." locations:"..engine.peekw(v+4).." "..engine.peekw(v+6))
i=i+1
end
print("Type number to edit or 'q' to exit")
while true do
q=io.stdin:read()
if q=='q' then return end
if tonumber(q) ~=nil and tonumber(q)<i then break end
end
return engine.peekd(T[tonumber(q)])
end
function items.edit(itoff)
if itoff==nil then
itoff=items.select()
end
print(string.format("Item offset:%x",itoff))
print("Type what to edit:")
print("1. material")
print("2. flags")
print("3. covering")
Z={}
Z[1]=editMaterial
Z[2]=editFlags
Z[3]=editCovering
name=ptr_item.getname(nil,engine.peek(itoff,ptr_item.RTI))
if name~=nil and ptr_subitems[name]~=nil then
print("4. Item specific edit")
--Z[4]=items.fedit[name]
Z[4]="dummy"
end
while true do
q=io.stdin:read()
if q=='q' then return end
if tonumber(q) ~=nil and tonumber(q)<#Z+1 then break end
end
if Z[tonumber(q)]=="dummy" then
ModPattern(itoff,ptr_subitems[name])
else
Z[tonumber(q)](itoff)
end
end
function items.printref()
itoff=items.select()
vec=engine.peek(itoff,ptr_item.ref)
for i=0, vec:size()-1 do
toff=vec:getval(i)
print(RTTI_GetName(engine.peekd(toff)))
end
print("Decorations:")
vec=engine.peek(itoff,ptr_item.decorations)
for i=0, vec:size()-1 do
toff=vec:getval(i)
print(ptr_decoration_gen.getname(nil,engine.peek(toff,ptr_decoration_gen.RTI)))
end
end
function items.edit_adv()
vec=engine.peek(offsets.getEx("CreatureVec"),ptr_vector)
items.edit(items.select_creature(vec:getval(0)))
end
if not(FILE) then -- if not in script mode
items.menu:add("Destroy all",items.dest)
items.menu:add("Hatch eggs",items.eggs)
items.menu:add("Edit item",items.edit)
items.menu:add("Print ref",items.printref)
items.menu:add("Edit adventurer's items",items.edit_adv)
items.menu:display()
end

@ -13,7 +13,28 @@ Other than std lua commands supported:
get_rows() get_rows()
lineedit(string) //text input through console lineedit(string) //text input through console
history_add(string) // adds string to console history history_add(string) // adds string to console history
* Process.
readDWord
writeDWord
readFloat
readWord
writeWord
readByte
writeByte
read
write
read/writeSTLString
copySTLString
doReadClassName
readClassName
readCString
isSuspended
isIdentified
getThreadIDs
getMemRanges
getBase
getPath
setPermisions
Functions searched: Functions searched:
OnTick() OnTick()
If defined is called each DFHack tick. If defined is called each DFHack tick.

@ -3,13 +3,50 @@
Hexsearch::Hexsearch(const SearchArgType &args,uint64_t startpos,uint64_t endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos) Hexsearch::Hexsearch(const SearchArgType &args,uint64_t startpos,uint64_t endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos)
{ {
ReparseArgs();
} }
Hexsearch::~Hexsearch() Hexsearch::~Hexsearch()
{ {
} }
inline bool Hexsearch::Compare(int a,int b)
{
if(b==Hexsearch::ANYBYTE)
return true;
if(a==b)
return true;
return false;
}
void Hexsearch::ReparseArgs()
{
SearchArgType targ;
targ=args_;
args_.clear();
for(size_t i=0;i<targ.size();)
{
if(targ[i]==DWORD_)
{
i++;
for(int j=0;j<4;j++)
{
args_.push_back(targ[i+4-j]);
}
i+=4;
}
else if (targ[i]==ANYDWORD)
{
i++;
for(int j=0;j<4;j++)
args_.push_back(ANYBYTE);
}
else
{
args_.push_back(targ[i]);
i++;
}
}
}
uint64_t Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm uint64_t Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
{ {
DFHack::Core &inst=DFHack::Core::getInstance(); DFHack::Core &inst=DFHack::Core::getInstance();
@ -20,12 +57,12 @@ uint64_t Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
{ {
bool found=true; bool found=true;
p->readByte(pos_,buf[0]); p->readByte(pos_,buf[0]);
if(buf[0]==args_[0]) //TODO make a comparator if(Compare(buf[0],args_[0]))
{ {
p->read(pos_,args_.size(),buf); p->read(pos_,args_.size(),buf);
for(size_t i=0;i<args_.size();i++) for(size_t i=0;i<args_.size();i++)
{ {
if(buf[i]!=args_[i]) if(!Compare(buf[i],args_[i]))
{ {
pos_+=i; pos_+=i;
found=false; found=false;

@ -11,7 +11,7 @@ int lua::Hexsearch::findall(lua_State *L)
lua::state st(L); lua::state st(L);
std::vector<uint64_t> pos=p->FindAll(); std::vector<uint64_t> pos=p->FindAll();
st.newtable(); st.newtable();
for(int i=0;i<pos.size();i++) for(unsigned i=0;i<pos.size();i++)
{ {
st.push(i+1); st.push(i+1);
st.push(pos[i]); st.push(pos[i]);
@ -49,9 +49,13 @@ LUNE_METHODS_START(lua::Hexsearch)
method(lua::Hexsearch,findall), method(lua::Hexsearch,findall),
method(lua::Hexsearch,reset), method(lua::Hexsearch,reset),
LUNE_METHODS_END(); LUNE_METHODS_END();
#define __ADDCONST(name) st.push(::Hexsearch:: ## name); st.setglobal(#name)
void lua::RegisterHexsearch(lua::state &st) void lua::RegisterHexsearch(lua::state &st)
{ {
Lune<lua::Hexsearch>::Register(st); Lune<lua::Hexsearch>::Register(st);
__ADDCONST(ANYBYTE);
__ADDCONST(ANYDWORD);
__ADDCONST(DWORD_);
} }
#undef __ADDCONST