-
Notifications
You must be signed in to change notification settings - Fork 231
gui/mod-manager improvements
#1481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
df9d85a
3b49b24
cadf06b
f194ffd
d6e1254
a292f12
90d437e
3655e85
3612f48
71c5b15
16ce689
821fef9
466c058
077e3c9
0fb8e3a
7127f4b
fbb2ae0
ef7986a
68f87f6
72b13db
63a64fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,10 +12,29 @@ local widgets = require('gui.widgets') | |
| local presets_file = json.open("dfhack-config/mod-manager.json") | ||
| local GLOBAL_KEY = 'mod-manager' | ||
|
|
||
| -- get_newregion_viewscreen and get_modlist_fields are declared as global functions | ||
| -- so external tools can call them to get the DF mod list | ||
| function get_newregion_viewscreen() | ||
| -- Shamelessly taken from hack/library/lua/script-manager.lua | ||
| local function vanilla(dir) | ||
| dir = dir.value | ||
| return dir:startswith('data/vanilla') | ||
| end | ||
|
|
||
| -- get_moddable_viewscreen(), get_any_moddable_viewscreen() and get_modlist_fields are declared | ||
| -- as global functions so external tools can call them to get the DF mod list | ||
| function get_moddable_viewscreen(type) | ||
| local vs = nil | ||
| if type == 'region' then | ||
| vs = dfhack.gui.getViewscreenByType(df.viewscreen_new_regionst, 0) | ||
| elseif type == 'arena' then | ||
| vs = dfhack.gui.getViewscreenByType(df.viewscreen_new_arenast, 0) | ||
| end | ||
| return vs | ||
| end | ||
|
|
||
| function get_any_moddable_viewscreen() | ||
| local vs = dfhack.gui.getViewscreenByType(df.viewscreen_new_regionst, 0) | ||
| if not vs then | ||
| vs = dfhack.gui.getViewscreenByType(df.viewscreen_new_arenast, 0) | ||
| end | ||
| return vs | ||
| end | ||
|
|
||
|
|
@@ -55,21 +74,29 @@ function get_modlist_fields(kind, viewscreen) | |
| end | ||
| end | ||
|
|
||
| --- @return { success: boolean, version: string } | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local function move_mod_entry(viewscreen, to, from, mod_id, mod_version) | ||
| local to_fields = get_modlist_fields(to, viewscreen) | ||
| local from_fields = get_modlist_fields(from, viewscreen) | ||
|
|
||
| local mod_index = nil | ||
| local loaded_version = nil | ||
| for i, v in ipairs(from_fields.id) do | ||
| local version = from_fields.numeric_version[i] | ||
| if v.value == mod_id and version == mod_version then | ||
| local src_dir = from_fields.src_dir[i] | ||
| local displayed_version = from_fields.displayed_version[i].value | ||
| -- assumes that vanilla mods will not have multiple possible indices. | ||
| if v.value == mod_id and (vanilla(src_dir) or version == mod_version) then | ||
| if version ~= mod_version then | ||
| loaded_version = displayed_version | ||
| end | ||
| mod_index = i | ||
| break | ||
| end | ||
| end | ||
|
|
||
| if mod_index == nil then | ||
| return false | ||
| return { success= false, version= nil } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think either is fine. And I think there is a decent argument for using "named" return values like this instead of unnamed ones (multiple returns) |
||
| end | ||
|
|
||
| for k, v in pairs(to_fields) do | ||
|
|
@@ -84,13 +111,15 @@ local function move_mod_entry(viewscreen, to, from, mod_id, mod_version) | |
| v:erase(mod_index) | ||
| end | ||
|
|
||
| return true | ||
| return { success= true, version= loaded_version } | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| end | ||
|
|
||
| --- @return { success: boolean, version: string } | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local function enable_mod(viewscreen, mod_id, mod_version) | ||
| return move_mod_entry(viewscreen, "object_load_order", "available", mod_id, mod_version) | ||
|
ong-yinggao98 marked this conversation as resolved.
|
||
| end | ||
|
|
||
| --- @return { success: boolean, version: string } | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local function disable_mod(viewscreen, mod_id, mod_version) | ||
| return move_mod_entry(viewscreen, "available", "object_load_order", mod_id, mod_version) | ||
| end | ||
|
|
@@ -105,19 +134,24 @@ local function get_active_modlist(viewscreen) | |
| return t | ||
| end | ||
|
|
||
| --- @return { failures: [string], changed: [{ id: string, new: string }] } | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local function swap_modlist(viewscreen, modlist) | ||
| local current = get_active_modlist(viewscreen) | ||
| for _, v in ipairs(current) do | ||
| disable_mod(viewscreen, v.id, v.version) | ||
| end | ||
|
|
||
| local failures = {} | ||
| local changed = {} | ||
| for _, v in ipairs(modlist) do | ||
| if not enable_mod(viewscreen, v.id, v.version) then | ||
| local res = enable_mod(viewscreen, v.id, v.version) | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| if not res.success then | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| table.insert(failures, v.id) | ||
| elseif res.version then | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| table.insert(changed, { id= v.id, new= res.version }) | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| end | ||
| end | ||
| return failures | ||
| return { failures= failures, changed= changed } | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| end | ||
|
|
||
| -------------------- | ||
|
|
@@ -137,7 +171,7 @@ ModmanageMenu.ATTRS { | |
| } | ||
|
|
||
| local function save_new_preset(preset_name) | ||
| local viewscreen = get_newregion_viewscreen() | ||
| local viewscreen = get_any_moddable_viewscreen() | ||
| local modlist = get_active_modlist(viewscreen) | ||
| table.insert(presets_file.data, { name = preset_name, modlist = modlist }) | ||
| presets_file:write() | ||
|
|
@@ -157,27 +191,17 @@ local function overwrite_preset(idx) | |
| return | ||
| end | ||
|
|
||
| local viewscreen = get_newregion_viewscreen() | ||
| local viewscreen = get_any_moddable_viewscreen() | ||
| local modlist = get_active_modlist(viewscreen) | ||
| presets_file.data[idx].modlist = modlist | ||
| presets_file:write() | ||
| end | ||
|
|
||
| local function load_preset(idx, unset_default_on_failure) | ||
| if idx > #presets_file.data then | ||
| return | ||
| end | ||
| local function prepare_warning(text, failed, changed, unset_default_on_failure) | ||
| if not failed and not changed then return end | ||
|
|
||
| local viewscreen = get_newregion_viewscreen() | ||
| local modlist = presets_file.data[idx].modlist | ||
| local failures = swap_modlist(viewscreen, modlist) | ||
|
|
||
| if #failures > 0 then | ||
| local text = {} | ||
| if failed then | ||
| if unset_default_on_failure then | ||
| presets_file.data[idx].default = false | ||
| presets_file:write() | ||
|
|
||
| table.insert(text, { | ||
| text='Failed to load some mods from your default preset.', | ||
| pen=COLOR_LIGHTRED, | ||
|
|
@@ -193,19 +217,72 @@ local function load_preset(idx, unset_default_on_failure) | |
| pen=COLOR_LIGHTRED, | ||
| }) | ||
| end | ||
| end | ||
|
|
||
| if failed and changed then | ||
| table.insert(text, NEWLINE) | ||
| table.insert(text, NEWLINE) | ||
| table.insert(text, 'Please re-create your preset with mods you currently have installed.') | ||
| table.insert(text, NEWLINE) | ||
| end | ||
|
|
||
| if changed then | ||
| table.insert(text, { | ||
| text='Some vanilla mods have been updated.', | ||
| pen=COLOR_LIGHTRED, | ||
| }) | ||
| end | ||
| table.insert(text, NEWLINE) | ||
| table.insert(text, 'Please re-create your preset with mods you currently have installed.') | ||
| table.insert(text, NEWLINE) | ||
| table.insert(text, NEWLINE) | ||
| end | ||
|
|
||
| local function load_preset(idx, unset_default_on_failure) | ||
| if idx > #presets_file.data then | ||
| return | ||
| end | ||
|
|
||
| local viewscreen = get_any_moddable_viewscreen() | ||
| local modlist = presets_file.data[idx].modlist | ||
| local results = swap_modlist(viewscreen, modlist) | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local failures = results.failures | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local changes = results.changed | ||
|
ong-yinggao98 marked this conversation as resolved.
Outdated
|
||
| local text = {} | ||
|
|
||
| local failed = #failures > 0 | ||
| local changed = #changes > 0 | ||
|
|
||
| prepare_warning(text, failed, changed) | ||
| if failed and unset_default_on_failure then | ||
| presets_file.data[idx].default = false | ||
| presets_file:write() | ||
| end | ||
|
|
||
| if failed then | ||
| table.insert(text, 'Here are the mods that failed to load:') | ||
| table.insert(text, NEWLINE) | ||
| table.insert(text, NEWLINE) | ||
| for _, v in ipairs(failures) do | ||
| table.insert(text, ('- %s'):format(v)) | ||
| table.insert(text, NEWLINE) | ||
| end | ||
| end | ||
|
|
||
| if failed and changed then | ||
| table.insert(text, NEWLINE) -- just to separate the sections | ||
| end | ||
|
|
||
| if changed then | ||
| table.insert(text, 'Here are the vanilla mods that have been updated:') | ||
| table.insert(text, NEWLINE) | ||
| table.insert(text, NEWLINE) | ||
| for _, v in ipairs(changes) do | ||
| table.insert(text, ('- %s to %s'):format(v.id, v.new)) | ||
| table.insert(text, NEWLINE) | ||
| end | ||
| end | ||
|
|
||
| if failed or changed then | ||
| dialogs.showMessage("Warning", text) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| local function find_preset_by_name(name) | ||
|
|
@@ -573,7 +650,7 @@ ModmanageOverlay.ATTRS { | |
| desc = "Adds a link to the mod selection screen for accessing the mod manager.", | ||
| default_pos = { x=5, y=-6 }, | ||
| version = 2, | ||
| viewscreens = { "new_region/Mods" }, | ||
| viewscreens = { "new_region/Mods", "new_arena/Mods" }, | ||
| default_enabled=true, | ||
| } | ||
|
|
||
|
|
@@ -636,7 +713,7 @@ notification_timer_fn() | |
| local default_applied = false | ||
| dfhack.onStateChange[GLOBAL_KEY] = function(sc) | ||
| if sc == SC_VIEWSCREEN_CHANGED then | ||
| local vs = get_newregion_viewscreen() | ||
| local vs = get_any_moddable_viewscreen() | ||
| if vs and not default_applied then | ||
| default_applied = true | ||
| for i, v in ipairs(presets_file.data) do | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.