Merge remote-tracking branch 'warmist/dev-modmanager' into develop
commit
ec14b2d1e9
@ -0,0 +1,306 @@
|
||||
|
||||
local gui=require 'gui'
|
||||
local widgets=require 'gui.widgets'
|
||||
|
||||
local entity_file=dfhack.getDFPath().."/raw/objects/entity_default.txt"
|
||||
local init_file=dfhack.getDFPath().."/raw/init.lua"
|
||||
function fileExists(filename)
|
||||
local file=io.open(filename,"rb")
|
||||
if file==nil then
|
||||
return
|
||||
else
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
function copyFile(from,to) --oh so primitive
|
||||
local filefrom=io.open(from,"rb")
|
||||
local fileto=io.open(to,"w+b")
|
||||
local buf=filefrom:read("*a")
|
||||
printall(buf)
|
||||
fileto:write(buf)
|
||||
filefrom:close()
|
||||
fileto:close()
|
||||
end
|
||||
function patchInit(initFileName,patch_guard,code)
|
||||
local initFile=io.open(initFileName,"a")
|
||||
initFile:write(string.format("\n%s\n%s\n%s",patch_guard[1],
|
||||
code,patch_guard[2]))
|
||||
initFile:close()
|
||||
end
|
||||
function patchFile(file_name,patch_guard,after_string,code)
|
||||
local input_lines=patch_guard[1].."\n"..code.."\n"..patch_guard[2]
|
||||
|
||||
local badchars="[%:%[%]]"
|
||||
local find_string=after_string:gsub(badchars,"%%%1") --escape some bad chars
|
||||
|
||||
local entityFile=io.open(file_name,"r")
|
||||
local buf=entityFile:read("*all")
|
||||
entityFile:close()
|
||||
local entityFile=io.open(file_name,"w+")
|
||||
buf=string.gsub(buf,find_string,after_string.."\n"..input_lines)
|
||||
entityFile:write(buf)
|
||||
entityFile:close()
|
||||
end
|
||||
function findGuards(str,start,patch_guard)
|
||||
local pStart=string.find(str,patch_guard[1],start)
|
||||
if pStart==nil then return nil end
|
||||
local pEnd=string.find(str,patch_guard[2],pStart)
|
||||
if pEnd==nil then error("Start guard token found, but end was not found") end
|
||||
return pStart-1,pEnd+#patch_guard[2]+1
|
||||
end
|
||||
function findGuardsFile(filename,patch_guard)
|
||||
local file=io.open(filename,"r")
|
||||
local buf=file:read("*all")
|
||||
return findGuards(buf,1,patch_guard)
|
||||
end
|
||||
function unPatchFile(filename,patch_guard)
|
||||
local file=io.open(filename,"r")
|
||||
local buf=file:read("*all")
|
||||
file:close()
|
||||
|
||||
local newBuf=""
|
||||
local pos=1
|
||||
local lastPos=1
|
||||
repeat
|
||||
local endPos
|
||||
pos,endPos=findGuards(buf,lastPos,patch_guard)
|
||||
newBuf=newBuf..string.sub(buf,lastPos,pos)
|
||||
if endPos~=nil then
|
||||
lastPos=endPos
|
||||
end
|
||||
until pos==nil
|
||||
|
||||
local file=io.open(filename,"w+")
|
||||
file:write(newBuf)
|
||||
file:close()
|
||||
end
|
||||
function checkInstalled(dfMod) --try to figure out if installed
|
||||
if dfMod.checkInstalled then
|
||||
return dfMod.checkInstalled()
|
||||
else
|
||||
if dfMod.raws_list then
|
||||
for k,v in pairs(dfMod.raws_list) do
|
||||
if fileExists(dfhack.getDFPath().."/raw/objects/"..v) then
|
||||
return true,v
|
||||
end
|
||||
end
|
||||
end
|
||||
if dfMod.patch_entity then
|
||||
if findGuardsFile(entity_file,dfMod.guard)~=nil then
|
||||
return true,"entity_default.txt"
|
||||
end
|
||||
end
|
||||
if dfMod.patch_files then
|
||||
for k,v in pairs(dfMod.patch_files) do
|
||||
if findGuardsFile(dfhack.getDFPath().."/raw/objects/"..v.filename,dfMod.guard)~=nil then
|
||||
return true,"v.filename"
|
||||
end
|
||||
end
|
||||
end
|
||||
if dfMod.patch_init then
|
||||
if findGuardsFile(init_file,dfMod.guard_init)~=nil then
|
||||
return true,"init.lua"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
manager=defclass(manager,gui.FramedScreen)
|
||||
|
||||
function manager:init(args)
|
||||
self.mods={}
|
||||
local mods=self.mods
|
||||
local mlist=dfhack.internal.getDir("mods")
|
||||
for k,v in ipairs(mlist) do
|
||||
if v~="." and v~=".." then
|
||||
local f,modData=pcall(dofile,"mods/".. v .. "/init.lua")
|
||||
if f then
|
||||
mods[modData.name]=modData
|
||||
modData.guard=modData.guard or {">>"..modData.name.." patch","<<End "..modData.name.." patch"}
|
||||
modData.guard_init={"--"..modData.guard[1],"--"..modData.guard[2]}
|
||||
modData.path=dfhack.getDFPath()..'/mods/'..v..'/'
|
||||
end
|
||||
end
|
||||
end
|
||||
---show thingy
|
||||
local modList={}
|
||||
for k,v in pairs(self.mods) do
|
||||
table.insert(modList,{text=k,data=v})
|
||||
end
|
||||
|
||||
self:addviews{
|
||||
|
||||
|
||||
widgets.Panel{subviews={
|
||||
widgets.Label{
|
||||
text="Info:",
|
||||
frame={t=1,l=1}
|
||||
},
|
||||
widgets.Label{
|
||||
text="<no-info>",
|
||||
--text={text=self:callback("formDescription")},
|
||||
view_id='info',
|
||||
frame={t=2,l=1},
|
||||
},
|
||||
widgets.Label{
|
||||
text={"Author:",{text=self:callback("formAuthor")}},
|
||||
view_id='author',
|
||||
frame={b=5,l=1}
|
||||
},
|
||||
widgets.Label{
|
||||
text={
|
||||
{text="Install",key="CUSTOM_I",key_sep="()",disabled=self:callback("curModInstalled"),
|
||||
on_activate=self:callback("installCurrent")},NEWLINE,
|
||||
{text="Uninstall",key="CUSTOM_U",key_sep="()",enabled=self:callback("curModInstalled"),
|
||||
on_activate=self:callback("uninstallCurrent")},NEWLINE,
|
||||
{text="Settings",key="CUSTOM_S",key_sep="()",enabled=self:callback("hasSettings")},NEWLINE,
|
||||
{text="Exit",key="LEAVESCREEN",key_sep="()",},NEWLINE
|
||||
},
|
||||
frame={l=1,b=0}
|
||||
},
|
||||
},
|
||||
frame={l=21,t=1,b=1}
|
||||
},
|
||||
widgets.Panel{subviews={
|
||||
widgets.Label{
|
||||
text="Mods:",
|
||||
frame={t=1,l=1}
|
||||
},
|
||||
widgets.List{
|
||||
choices=modList,
|
||||
frame={t=2,l=1},
|
||||
on_select=self:callback("selectMod")
|
||||
},
|
||||
},
|
||||
frame={w=20,t=1,l=1,b=1}
|
||||
},
|
||||
}
|
||||
self:updateState()
|
||||
|
||||
end
|
||||
function manager:postinit(args)
|
||||
self:selectMod(1,{data=self.selected})-- workaround for first call, now the subviews are constructed
|
||||
end
|
||||
function manager:curModInstalled()
|
||||
return self.selected.installed
|
||||
end
|
||||
function manager:hasSettings()
|
||||
return self.selected.settings -- somehow add the entity selection as a default, if it mods entities
|
||||
end
|
||||
function manager:formDescription()
|
||||
local ret={}
|
||||
if self.selected.description then
|
||||
return self.selected.description
|
||||
--[[
|
||||
local str=require('utils').split_string(self.selected.description,"\n")
|
||||
for _,s in ipairs(str) do
|
||||
table.insert(ret,{text=s})
|
||||
table.insert(ret,NEWLINE)
|
||||
end
|
||||
return ret]]
|
||||
else
|
||||
return "<no-info>"
|
||||
end
|
||||
end
|
||||
function manager:formAuthor()
|
||||
return self.selected.author or "<no-info>"
|
||||
end
|
||||
function manager:selectMod(idx,choice)
|
||||
self.selected=choice.data
|
||||
if self.subviews.info then
|
||||
self.subviews.info:setText(self:formDescription())
|
||||
self:updateLayout()
|
||||
end
|
||||
end
|
||||
function manager:updateState()
|
||||
for k,v in pairs(self.mods) do
|
||||
v.installed=checkInstalled(v)
|
||||
end
|
||||
end
|
||||
function manager:installCurrent()
|
||||
self:install(self.selected)
|
||||
end
|
||||
function manager:uninstallCurrent()
|
||||
self:uninstall(self.selected)
|
||||
end
|
||||
function manager:install(trgMod,force)
|
||||
|
||||
if trgMod==nil then
|
||||
qerror 'Mod does not exist'
|
||||
end
|
||||
if not force then
|
||||
local isInstalled,file=checkInstalled(trgMod) -- maybe load from .installed?
|
||||
if isInstalled then
|
||||
qerror("Mod already installed. File:"..file)
|
||||
end
|
||||
end
|
||||
print("installing:"..trgMod.name)
|
||||
if trgMod.pre_install then
|
||||
trgMod.pre_install(args)
|
||||
end
|
||||
if trgMod.raws_list then
|
||||
for k,v in pairs(trgMod.raws_list) do
|
||||
copyFile(trgMod.path..v,dfhack.getDFPath().."/raw/objects/"..v)
|
||||
end
|
||||
end
|
||||
if trgMod.patch_entity then
|
||||
local entity_target="[ENTITY:MOUNTAIN]" --TODO configure
|
||||
patchFile(entity_file,trgMod.guard,entity_target,trgMod.patch_entity)
|
||||
end
|
||||
if trgMod.patch_files then
|
||||
for k,v in pairs(trgMod.patch_files) do
|
||||
patchFile(dfhack.getDFPath().."/raw/objects/"..v.filename,trgMod.guard,v.after,v.patch)
|
||||
end
|
||||
end
|
||||
if trgMod.patch_init then
|
||||
patchInit(init_file,trgMod.guard_init,trgMod.patch_init)
|
||||
end
|
||||
|
||||
trgMod.installed=true
|
||||
|
||||
if trgMod.post_install then
|
||||
trgMod.post_install(self)
|
||||
end
|
||||
print("done")
|
||||
end
|
||||
function manager:uninstall(trgMod)
|
||||
print("Uninstalling:"..trgMod.name)
|
||||
if trgMod.pre_uninstall then
|
||||
trgMod.pre_uninstall(args)
|
||||
end
|
||||
|
||||
if trgMod.raws_list then
|
||||
for k,v in pairs(trgMod.raws_list) do
|
||||
os.remove(dfhack.getDFPath().."/raw/objects/"..v)
|
||||
end
|
||||
end
|
||||
if trgMod.patch_entity then
|
||||
unPatchFile(entity_file,trgMod.guard)
|
||||
end
|
||||
if trgMod.patch_files then
|
||||
for k,v in pairs(trgMod.patch_files) do
|
||||
unPatchFile(dfhack.getDFPath().."/raw/objects/"..v.filename,trgMod.guard)
|
||||
end
|
||||
end
|
||||
if trgMod.patch_init then
|
||||
unPatchFile(init_file,trgMod.guard_init)
|
||||
end
|
||||
trgMod.installed=false
|
||||
if trgMod.post_uninstall then
|
||||
trgMod.post_uninstall(args)
|
||||
end
|
||||
print("done")
|
||||
end
|
||||
function manager:onInput(keys)
|
||||
|
||||
if keys.LEAVESCREEN then
|
||||
self:dismiss()
|
||||
else
|
||||
self:inputToSubviews(keys)
|
||||
end
|
||||
|
||||
end
|
||||
if dfhack.gui.getCurFocus()~='title' then
|
||||
qerror("Can only be used in title screen")
|
||||
end
|
||||
local m=manager{}
|
||||
m:show()
|
Loading…
Reference in New Issue