Skip to content

Commit 5f13a42

Browse files
Merge branch 'squid-active-modlist' into glom
2 parents d587cff + fca0788 commit 5f13a42

File tree

2 files changed

+65
-61
lines changed

2 files changed

+65
-61
lines changed

docs/gui/mod-manager.rst

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,28 @@ gui/mod-manager
66
:tags: dfhack interface
77

88
In a loaded world, shows a list of active mods with the ability to copy to clipboard.
9-
Adds an optional overlay to the mod list screen that allows you to save and
10-
load mod list presets, as well as set a default mod list preset for new worlds.
9+
1110

1211
Usage
1312
-----
1413

1514
::
1615

1716
gui/mod-manager
17+
18+
Overlay
19+
-------
20+
21+
This tool also provides two overlays that are managed by the `overlay`
22+
framework.
23+
24+
gui/mod-manager.button
25+
~~~~~~~~~~~~~~~~~~~~~~
26+
27+
Adds an optional overlay to the mod list screen that allows you to save and
28+
load mod list presets, as well as set a default mod list preset for new worlds.
29+
30+
gui/mod-manager.notification
31+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32+
33+
Displays a message when a mod preset has been auto-applied.

gui/mod-manager.lua

Lines changed: 47 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ local dialogs = require('gui.dialogs')
88
local json = require('json')
99
local utils = require('utils')
1010

11+
local scriptmanager = require('script-manager')
12+
1113
local presets_file = json.open("dfhack-config/mod-manager.json")
1214
local GLOBAL_KEY = 'mod-manager'
13-
local INSTALLED_MODS_PATH = 'data/installed_mods/'
1415

1516
-- get_newregion_viewscreen and get_modlist_fields are declared as global functions
1617
-- so external tools can call them to get the DF mod list
@@ -404,99 +405,86 @@ end
404405

405406
ModlistMenu = defclass(ModlistMenu, widgets.Window)
406407
ModlistMenu.ATTRS {
407-
view_id = "modlist_menu",
408408
frame_title = "Active Modlist",
409-
frame_style = gui.WINDOW_FRAME,
410409

411410
resize_min = { w = 30, h = 15 },
412-
frame = { w = 40, t = 10, b = 15 },
411+
frame = { w = 40, h = 20 },
413412

414413
resizable = true,
415-
autoarrange_subviews=false,
416414
}
417415

418-
local function get_mod_id_and_version(path)
419-
local idfile = path .. '/info.txt'
420-
local ok, lines = pcall(io.lines, idfile)
421-
if not ok then return end
422-
local id, version
423-
for line in lines do
424-
if not id then
425-
_,_,id = line:find('^%[ID:([^%]]+)%]')
426-
end
427-
if not version then
428-
-- note this doesn't include the closing brace since some people put
429-
-- non-number characters in here, and DF only reads the leading digits
430-
-- as the numeric version
431-
_,_,version = line:find('^%[NUMERIC_VERSION:(%d+)')
432-
end
433-
-- note that we do *not* want to break out of this loop early since
434-
-- lines has to hit EOF to close the file
435-
end
436-
return id, version
437-
end
438-
439-
local function add_mod_paths(mod_paths, id, base_path, subdir)
440-
local sep = base_path:endswith('/') and '' or '/'
441-
local path = ('%s%s%s'):format(base_path, sep, subdir)
442-
if dfhack.filesystem.isdir(path) then
443-
table.insert(mod_paths, {id=id, path=path})
444-
end
445-
end
446-
447-
local function getWorldModlist()
416+
local function getWorldModlist(detailed, include_vanilla)
448417
-- ordered map of mod id -> {handled=bool, versions=map of version -> path}
449418
local mods = utils.OrderedTable()
450419
local mod_paths = {}
451420

452421
-- if a world is loaded, process active mods first, and lock to active version
453422
if dfhack.isWorldLoaded() then
454-
for _,path in ipairs(df.global.world.object_loader.object_load_order_src_dir) do
455-
path = tostring(path.value)
456-
-- skip vanilla "mods"
457-
if not path:startswith(INSTALLED_MODS_PATH) then goto continue end
458-
local id = get_mod_id_and_version(path)
459-
if not id then goto continue end
460-
mods[id] = {handled=true}
461-
add_mod_paths(mod_paths, id, path, '.')
462-
::continue::
463-
end
423+
scriptmanager.getAllModsInfo(include_vanilla, mods, mod_paths)
464424
local modlist = {}
465425
for _,mod in ipairs(mod_paths) do
466-
table.insert(modlist,mod.id)
426+
if detailed then
427+
local url
428+
if mods[mod.id].steam_id then
429+
url = ': https://steamcommunity.com/sharedfiles/filedetails/?id='.. mods[mod.id].steam_id
430+
end
431+
table.insert(modlist,('%s %s (%s)%s'):format(mods[mod.id].name or mod.id, mods[mod.id].version or '', mod.id, url or ''))
432+
else
433+
table.insert(modlist,mods[mod.id].name or mod.id)
434+
end
467435
end
468436
return modlist
469437
end
470438
qerror('No world is loaded')
471439
end
472440

473441
function ModlistMenu:init()
474-
local modlist = widgets.List{
475-
view_id='modlist',
476-
frame = {t=3},
477-
choices = getWorldModlist()
478-
}
442+
self.include_vanilla = self.include_vanilla or false
479443
self:addviews{
480444
widgets.Label{
481445
frame = { l=0, t=0 },
482446
text = {'Active mods:'},
483447
},
484448
widgets.HotkeyLabel{
485-
view_id='copy',
449+
view_id='copy_names',
486450
frame={t=1, r=1},
487-
label='Copy modlist to clipboard',
451+
label='Copy mod names to clipboard',
488452
text_pen=COLOR_YELLOW,
489453
auto_width=true,
490454
on_activate=function()
491-
local mods = ''
492-
for _,mod in ipairs(getWorldModlist()) do
493-
mods = (mods == '' and mod) or (mods .. ', ' .. mod)
494-
end
455+
local mods = table.concat(getWorldModlist(false, self.include_vanilla), ', ')
495456
dfhack.internal.setClipboardTextCp437(mods)
496457
end,
497-
enabled=function() return #modlist:getChoices() > 0 end,
458+
enabled=function() return #self.subviews.modlist:getChoices() > 0 end,
498459
},
499-
modlist
460+
widgets.HotkeyLabel{
461+
view_id='copy_list',
462+
frame={t=2, r=1},
463+
label='Copy list to clipboard',
464+
text_pen=COLOR_YELLOW,
465+
auto_width=true,
466+
on_activate=function()
467+
local mods = table.concat(getWorldModlist(true, self.include_vanilla), NEWLINE)
468+
dfhack.internal.setClipboardTextCp437Multiline(mods)
469+
end,
470+
enabled=function() return #self.subviews.modlist:getChoices() > 0 end,
471+
},
472+
widgets.List{
473+
view_id='modlist',
474+
frame = {t=4,b=2},
475+
choices = getWorldModlist(true,self.include_vanilla)
476+
},
477+
widgets.HotkeyLabel{
478+
view_id='include_vanilla',
479+
frame={b=0},
480+
key='CUSTOM_V',
481+
label='Include Vanilla Mods: ' .. ((self.include_vanilla and 'Yes') or 'No'),
482+
on_activate=function ()
483+
self.include_vanilla = not self.include_vanilla
484+
self.subviews.include_vanilla:setLabel('Include Vanilla Mods: ' .. ((self.include_vanilla and 'Yes') or 'No'))
485+
self.subviews.modlist:setChoices(getWorldModlist(true,self.include_vanilla))
486+
end
487+
}
500488
}
501489
end
502490

0 commit comments

Comments
 (0)