Skip to content

Commit

Permalink
Add check_mod_configuration to main menu
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenwardy committed Jul 14, 2022
1 parent 06de82f commit 9f41b4f
Show file tree
Hide file tree
Showing 11 changed files with 277 additions and 13 deletions.
89 changes: 85 additions & 4 deletions builtin/mainmenu/dlg_config_world.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,68 @@ local function init_data(data)
data.list:set_sortmode("alphabetic")
end


-- Returns errors errors and a list of all enabled mods (inc. game and world mods)
--
-- `with_errors` is a table from mod virtual path to `{ type = "error" | "warning" }`.
-- `enabled_mods_by_name` is a table from mod virtual path to `true`.
--
-- @param world_path Path to the world
-- @param all_mods List of mods, with `enabled` property.
-- @returns with_errors, enabled_mods_by_name
local function check_mod_configuration(world_path, all_mods)
-- Build up lookup tables for enabled mods and all mods by vpath
local enabled_mod_paths = {}
local all_mods_by_vpath = {}
for _, mod in ipairs(all_mods) do
if mod.type == "mod" then
all_mods_by_vpath[mod.virtual_path] = mod
end
if mod.enabled then
enabled_mod_paths[mod.virtual_path] = mod.path
end
end

-- Use the engine's mod configuration code to resolve dependencies and return any errors
local config_status = core.check_mod_configuration(world_path, enabled_mod_paths)

-- Build the list of enabled mod virtual paths
local enabled_mods_by_name = {}
for _, mod in ipairs(config_status.satisfied_mods) do
assert(mod.virtual_path ~= "")
enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
end
for _, mod in ipairs(config_status.unsatisfied_mods) do
assert(mod.virtual_path ~= "")
enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
end

-- Build the table of errors
local with_error = {}
for _, mod in ipairs(config_status.unsatisfied_mods) do
local error = { type = "warning" }
with_error[mod.virtual_path] = error

for _, depname in ipairs(mod.unsatisfied_depends) do
if not enabled_mods_by_name[depname] then
error.type = "error"
break
end
end
end

return with_error, enabled_mods_by_name
end

local function get_formspec(data)
if not data.list then
init_data(data)
end

local mod = data.list:get_list()[data.selected_mod] or {name = ""}
local all_mods = data.list:get_list()
local with_error, enabled_mods_by_name = check_mod_configuration(data.worldspec.path, all_mods)

local mod = all_mods[data.selected_mod] or {name = ""}

local retval =
"size[11.5,7.5,true]" ..
Expand All @@ -87,6 +143,29 @@ local function get_formspec(data)
"textarea[0.25,0.7;5.75,7.2;;" .. info .. ";]"
else
local hard_deps, soft_deps = pkgmgr.get_dependencies(mod.path)

-- Add error messages to dep lists
if mod.enabled or mod.is_game_content then
for i, dep_name in ipairs(hard_deps) do
local dep = enabled_mods_by_name[dep_name]
if not dep then
hard_deps[i] = mt_color_red .. dep_name .. " " .. fgettext("(Unsatisfied)")
elseif with_error[dep.virtual_path] then
hard_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
else
hard_deps[i] = mt_color_green .. dep_name
end
end
for i, dep_name in ipairs(soft_deps) do
local dep = enabled_mods_by_name[dep_name]
if dep and with_error[dep.virtual_path] then
soft_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
elseif dep then
soft_deps[i] = mt_color_green .. dep_name
end
end
end

local hard_deps_str = table.concat(hard_deps, ",")
local soft_deps_str = table.concat(soft_deps, ",")

Expand Down Expand Up @@ -138,7 +217,6 @@ local function get_formspec(data)

if mod.name ~= "" and not mod.is_game_content then
if mod.is_modpack then

if pkgmgr.is_modpack_entirely_enabled(data, mod.name) then
retval = retval ..
"button[5.5,0.125;3,0.5;btn_mp_disable;" ..
Expand Down Expand Up @@ -167,9 +245,12 @@ local function get_formspec(data)
local use_technical_names = core.settings:get_bool("show_technical_names")

return retval ..
"tablecolumns[color;tree;text]" ..
"tablecolumns[color;tree;image,align=inline,width=1.5,0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") ..
",1=" .. core.formspec_escape(defaulttexturedir .. "checkbox_16_white.png") ..
",2=" .. core.formspec_escape(defaulttexturedir .. "error_icon_orange.png") ..
",3=" .. core.formspec_escape(defaulttexturedir .. "error_icon_red.png") .. ";text]" ..
"table[5.5,0.75;5.75,6;world_config_modlist;" ..
pkgmgr.render_packagelist(data.list, use_technical_names) .. ";" .. data.selected_mod .."]"
pkgmgr.render_packagelist(data.list, use_technical_names, with_error) .. ";" .. data.selected_mod .."]"
end

local function handle_buttons(this, fields)
Expand Down
1 change: 1 addition & 0 deletions builtin/mainmenu/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mt_color_lightblue = "#99CCFF"
mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800"
mt_color_red = "#FF3300"

local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path()
Expand Down
55 changes: 47 additions & 8 deletions builtin/mainmenu/pkgmgr.lua
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ function pkgmgr.identify_modname(modpath,filename)
return nil
end
--------------------------------------------------------------------------------
function pkgmgr.render_packagelist(render_list, use_technical_names)
function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
if not render_list then
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
Expand All @@ -349,31 +349,70 @@ function pkgmgr.render_packagelist(render_list, use_technical_names)
local retval = {}
for i, v in ipairs(list) do
local color = ""
local icon = 0
local error = with_error and with_error[v.virtual_path]
local function update_error(val)
if val and (not error or (error.type == "warning" and val.type == "error")) then
error = val
end
end

if v.is_modpack then
local rawlist = render_list:get_raw_list()
color = mt_color_dark_green

for j = 1, #rawlist, 1 do
if rawlist[j].modpack == list[i].name and
not rawlist[j].enabled then
-- Modpack not entirely enabled so showing as grey
color = mt_color_grey
break
for j = 1, #rawlist do
if rawlist[j].modpack == list[i].name then
if with_error then
update_error(with_error[rawlist[j].virtual_path])
end

if rawlist[j].enabled then
icon = 1
else
-- Modpack not entirely enabled so showing as grey
color = mt_color_grey
end
end
end
elseif v.is_game_content or v.type == "game" then
icon = 1
color = mt_color_blue

local rawlist = render_list:get_raw_list()
if v.type == "game" and with_error then
for j = 1, #rawlist do
if rawlist[j].is_game_content then
update_error(with_error[rawlist[j].virtual_path])
end
end
end
elseif v.enabled or v.type == "txp" then
icon = 1
color = mt_color_green
end

if error then
if error.type == "warning" then
color = mt_color_orange
icon = 2
else
color = mt_color_red
icon = 3
end
end

retval[#retval + 1] = color
if v.modpack ~= nil or v.loc == "game" then
retval[#retval + 1] = "1"
else
retval[#retval + 1] = "0"
end

if with_error then
retval[#retval + 1] = icon
end

if use_technical_names then
retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
else
Expand Down Expand Up @@ -503,7 +542,7 @@ function pkgmgr.enable_mod(this, toset)
if not mod_to_enable then
core.log("warning", "Mod dependency \"" .. name ..
"\" not found!")
else
elseif not mod_to_enable.is_game_content then
if not mod_to_enable.enabled then
mod_to_enable.enabled = true
toggled_mods[#toggled_mods+1] = mod_to_enable.name
Expand Down
11 changes: 11 additions & 0 deletions doc/menu_lua_api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,18 @@ Package - content which is downloadable from the content db, may or may not be i
depends = {"mod", "names"}, -- mods only
optional_depends = {"mod", "names"}, -- mods only
}
* core.check_mod_configuration(world_path, mod_paths)
* Checks whether configuration is valid.
* `world_path`: path to the world
* `mod_paths`: list of enabled mod paths
* returns:

{
is_consistent = true, -- true is consistent, false otherwise
unsatisfied_mods = {}, -- list of mod specs
satisfied_mods = {}, -- list of mod specs
error_message = "", -- message or nil
}

Logging
-------
Expand Down
32 changes: 32 additions & 0 deletions src/script/common/c_content.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2143,3 +2143,35 @@ void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
lua_setfield(L, -2, "collisions");
/**/
}


void push_mod_spec(lua_State *L, const ModSpec &spec, bool include_unsatisfied)
{
lua_newtable(L);

lua_pushstring(L, spec.name.c_str());
lua_setfield(L, -2, "name");

lua_pushstring(L, spec.author.c_str());
lua_setfield(L, -2, "author");

lua_pushinteger(L, spec.release);
lua_setfield(L, -2, "release");

lua_pushstring(L, spec.desc.c_str());
lua_setfield(L, -2, "description");

lua_pushstring(L, spec.path.c_str());
lua_setfield(L, -2, "path");

lua_pushstring(L, spec.virtual_path.c_str());
lua_setfield(L, -2, "virtual_path");

lua_newtable(L);
int i = 1;
for (const auto &dep : spec.unsatisfied_depends) {
lua_pushstring(L, dep.c_str());
lua_rawseti(L, -2, i++);
}
lua_setfield(L, -2, "unsatisfied_depends");
}
3 changes: 3 additions & 0 deletions src/script/common/c_content.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extern "C" {
// We do a explicit path include because by default c_content.h include src/client/hud.h
// prior to the src/hud.h, which is not good on server only build
#include "../../hud.h"
#include "content/mods.h"

namespace Json { class Value; }

Expand Down Expand Up @@ -204,3 +205,5 @@ void push_hud_element (lua_State *L, HudElement *elem);
bool read_hud_change (lua_State *L, HudElementStat &stat, HudElement *elem, void **value);

void push_collision_move_result(lua_State *L, const collisionMoveResult &res);

void push_mod_spec(lua_State *L, const ModSpec &spec, bool include_unsatisfied);
Loading

0 comments on commit 9f41b4f

Please sign in to comment.