Another day, another commit.

develop
Warmist 2012-11-01 16:00:00 +02:00
parent a3f6e9e305
commit 209d593f21
5 changed files with 289 additions and 64 deletions

@ -2,9 +2,14 @@ local dfu=require("plugins.dfusion")
local ms=require("memscan")
local MAX_RACES=100
CustomEmbark=defclass(CustomEmbark,dfu.BinaryPlugin)
local myos=dfhack.getOSType()
if myos=="windows" then
CustomEmbark.ATTRS{filename="dfusion/embark/embark.o",name="CustomEmbark",race_caste_data=DEFAULT_NIL}
CustomEmbark.class_status="valid, not installed"
function CustomEmbark:install()
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if #self.race_caste_data<7 then
error("caste and race count must be bigger than 6")
end
@ -45,6 +50,7 @@ function CustomEmbark:install()
self.dwarfcount:apply()
local caste_array=self:allocate("caste_array","uint16_t",#self.race_caste_data)
local race_array=self:allocate("race_array","uint16_t",#self.race_caste_data)
self:setEmbarkParty(self.race_caste_data)
for k,v in ipairs(self.race_caste_data) do
caste_array[k-1]=v[2]
race_array[k-1]=v[1]
@ -60,6 +66,23 @@ function CustomEmbark:install()
self.call_patch:apply()
self.installed=true
end
function CustomEmbark:setEmbarkParty(racesAndCastes)
self.race_caste_data=racesAndCastes
if self.dwarfcount== nil then
self.dwarfcount=dfu.BinaryPatch{pre_data=dfu.dwordToTable(7),data=dfu.dwordToTable(#self.race_caste_data),address=stoff,name="custom_embark_embarkcount"}
self.dwarfcount:apply()
else
self.dwarfcount:repatch(dfu.dwordToTable(#self.race_caste_data))
end
end
function CustomEmbark:status()
if self.installed then
return "valid, installed"
else
return "valid, not installed"
end
end
function CustomEmbark:uninstall()
if self.installed then
self.call_patch:remove()
@ -67,3 +90,6 @@ function CustomEmbark:uninstall()
self.dwarfcount:remove()
end
end
else
CustomEmbark.class_status="invalid, os not supported"
end

@ -107,6 +107,7 @@ end
-- A binary hack (obj file) loader/manager
-- has to have: a way to get offsets for marked areas (for post load modification) or some way to do that pre-load
-- page managing (including excecute/write flags for DEP and the like)
-- TODO plugin state enum, a way to modify post install (could include repatching code...)
plugins=plugins or {}
BinaryPlugin=defclass(BinaryPlugin)
BinaryPlugin.ATTRS {filename=DEFAULT_NIL,reloc_table={},name=DEFAULT_NIL}
@ -115,14 +116,21 @@ function BinaryPlugin:init(args)
end
function BinaryPlugin:postinit(args)
if self.name==nil then error("Not a valid plugin name!") end
--if plugins[args.name]==nil then
if plugins[args.name]==nil then
plugins[self.name]=self
--else
-- error("Trying to create a same plugin")
--end
else
error("Trying to create a same plugin")
end
self.allocated_object={}
self:load()
end
function BinaryPlugin:get_or_alloc(name,typename,arrsize)
if self.allocated_object[name]~=nil then
return self.allocated_object[name]
else
return self:allocate(name,typename,arrsize)
end
end
function BinaryPlugin:allocate(name,typename,arrsize)
local trg
if df[typename]==nil then
@ -182,6 +190,9 @@ function BinaryPlugin:print_data()
end
print(out)
end
function BinaryPlugin:status()
return "invalid, base class only!"
end
function BinaryPlugin:__gc()
for k,v in pairs(self.allocated_object) do
df.delete(v)

@ -0,0 +1,148 @@
local _ENV = mkmodule('plugins.dfusion.embark')
local dfu=require("plugins.dfusion")
local ms=require("memscan")
local MAX_RACES=100
CustomEmbark=defclass(CustomEmbark,dfu.BinaryPlugin)
CustomEmbark.name="CustomEmbark"
local myos=dfhack.getOSType()
if myos=="windows" then
CustomEmbark.ATTRS{filename="hack/lua/plugins/dfusion/embark.o",name="CustomEmbark",race_caste_data=DEFAULT_NIL}
CustomEmbark.class_status="valid, not installed"
function CustomEmbark:install()
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if #self.race_caste_data<7 then
error("caste and race count must be bigger than 6")
end
if #self.race_caste_data>MAX_RACES then
error("caste and race count must be less then "..MAX_RACES)
end
if stoff==nil then
error("address for start_dwarf_count not found!")
end
local _,race_id_offset=df.sizeof(df.global.ui:_field("race_id"))
print(string.format("start=%08x",stoff))
local needle={0x0f,0xb7,0x0d} --movzx eax,dword ptr [race_id]
local tmp_table=dfu.dwordToTable(race_id_offset)
for k,v in ipairs(tmp_table) do
table.insert(needle,v)
end
local mem=ms.get_code_segment()
print(mem.uint8_t:addr2idx(stoff))
print(mem.uint8_t:find(needle,mem.uint8_t:addr2idx(stoff)))
local _,trg_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(stoff),nil)--maybe endoff=stoff+bignumber
if trg_offset==nil then
error("address for race_load not found")
end
local call_data={0x90,0x90}
local _,data_offset=df.sizeof(self.data)
dfu.concatTables(call_data,dfu.makeCall(trg_offset+2,data_offset))
self.call_patch=dfu.BinaryPatch{pre_data=needle,data=call_data,address=trg_offset,name="custom_embark_call_patch"}
needle={0x83,0xc8,0xff} -- or eax, 0xFF
local _,caste_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(trg_offset),nil)
if caste_offset==nil or caste_offset-stoff>1000 then
error("Caste change code not found or found too far!")
end
self.disable_castes=dfu.BinaryPatch{pre_data={0x83,0xc8,0xff},data={0x90,0x90,0x90},address=caste_offset,name="custom_embark_caste_disable"}
self.disable_castes:apply()
self:setEmbarkParty(self.race_caste_data)
local caste_array=self:get_or_alloc("caste_array","uint16_t",MAX_RACES)
local race_array=self:get_or_alloc("race_array","uint16_t",MAX_RACES)
local race_array_off,caste_array_off
local _
_,race_array_off=df.sizeof(race_array)
_,caste_array_off=df.sizeof(caste_array)
self:set_marker_dword("race",caste_array_off) --hehe... mixed them up i guess...
self:set_marker_dword("caste",race_array_off)
self:move_to_df()
self.call_patch:apply()
self.installed=true
end
function CustomEmbark:setEmbarkParty(racesAndCastes)
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if #racesAndCastes<7 then
error("caste and race count must be bigger than 6")
end
if #racesAndCastes>MAX_RACES then
error("caste and race count must be less then "..MAX_RACES)
end
self.race_caste_data=racesAndCastes
if self.dwarfcount== nil then
self.dwarfcount=dfu.BinaryPatch{pre_data=dfu.dwordToTable(7),data=dfu.dwordToTable(#self.race_caste_data),address=stoff,name="custom_embark_embarkcount"}
self.dwarfcount:apply()
else
self.dwarfcount:repatch(dfu.dwordToTable(#self.race_caste_data))
end
local caste_array=self:get_or_alloc("caste_array","uint16_t",MAX_RACES)
local race_array=self:get_or_alloc("race_array","uint16_t",MAX_RACES)
for k,v in ipairs(self.race_caste_data) do
caste_array[k-1]=v[2]
race_array[k-1]=v[1]
end
end
function CustomEmbark:status()
if self.installed then
return "valid, installed"
else
return "valid, not installed"
end
end
function CustomEmbark:uninstall()
if self.installed then
self.call_patch:remove()
self.disable_castes:remove()
self.dwarfcount:remove()
end
end
function CustomEmbark:edit()
local data=self.race_caste_data or {}
print(string.format("Old race count:%d",#data))
local endthis=false
print("current:")
while(not endthis) do
print(" # RaceId Race name Caste num")
for k,v in pairs(data) do
local name=df.creature_raw.find(v[1]).creature_id or ""
print(string.format("%3d. %6d %20s %d",k,v[1],name,v[2]))
end
print("a- add, r-remove, c-cancel, s-save and update")
local choice=io.stdin:read()
if choice=='a' then
print("Enter new race then caste ids:")
local race=tonumber(io.stdin:read())
local caste=tonumber(io.stdin:read())
if race and caste then
table.insert(data,{race,caste})
else
print("input parse error")
end
elseif choice=='r' then
print("enter number to remove:")
local num_rem=tonumber(io.stdin:read())
if num_rem~=nil then
table.remove(data,num_rem)
end
elseif choice=='c' then
endthis=true
elseif choice=='s' then
endthis=true
if self.installed then
self:setEmbarkParty(data)
else
self.race_caste_data=data
self:install()
end
end
end
end
else
CustomEmbark.class_status="invalid, os not supported"
end
return _ENV

Binary file not shown.

@ -1,2 +1,42 @@
-- a binary hack/plugin collection for df
local dfu=require("plugins.dfusion")
local myos=dfhack.getOSType()
--some imports go here
local plugins={
require("plugins.dfusion.embark").CustomEmbark
}
--show a table of all the statuses
function status(plug)
if dfu.plugins[plug.name]==nil then
return plug.class_status
else
return dfu.plugins[plug.name]:status()
end
end
function printPlugs()
local endthis=false
print("current:")
while(not endthis) do
for k,v in pairs(plugins) do
if v then
print(string.format("%2d. %15s-%s",k,v.name,status(v)))
end
end
print("e-edit and load, u-unload,c-cancel and then number to manipulate:")
local choice=io.stdin:read()
local num=tonumber(io.stdin:read())
if num then
local plg=dfu.plugins[plugins[num].name] or plugins[num]()
if choice=='e' then
plg:edit()
elseif choice=='u' then
plg:uninstall()
elseif choice=='c' then
endthis=true
end
end
end
end
printPlugs()