diff --git a/.gitignore b/.gitignore index 7fa100ed5..eca66f6fe 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,8 @@ AppDir /sounds /mods/* !/mods/mods_here.txt +/mapgens/* +!/mapgens/mapgens_here.txt /worlds/* !/worlds/worlds_here.txt /clientmods/* diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua index 8423bfdb6..30ec05fda 100644 --- a/builtin/mainmenu/dlg_create_world.lua +++ b/builtin/mainmenu/dlg_create_world.lua @@ -79,11 +79,22 @@ local mgv6_biomes = { } local function create_world_formspec(dialogdata) - local current_mapgen = dialogdata.mg local mapgens = core.get_mapgen_names() - local lua_mapgens = core.get_lua_mapgen_descriptions() + + -- This is used to make sure that the internal mapgens are never overwritten by an ill-playing mapgen + local is_internal_mapgen = false + for _, mg in pairs(mapgens) do + if mg == current_mapgen then + is_internal_mapgen = true + end + end + + local lua_mapgens = core.get_lua_mapgen_descriptions_and_title() for k, v in pairs(lua_mapgens) do + if not is_internal_mapgen and v.title == dialogdata.mg then + current_mapgen = k + end mapgens[#mapgens+1] = k end @@ -145,7 +156,13 @@ local function create_world_formspec(dialogdata) selindex = i end i = i + 1 - mglist = mglist .. core.formspec_escape(v) .. "," + + local mapgen_title = (lua_mapgens[v] or {}).title + if not mapgen_title then + mapgen_title = v + end + + mglist = mglist .. core.formspec_escape(mapgen_title) .. "," end if not selindex then selindex = 1 @@ -155,8 +172,12 @@ local function create_world_formspec(dialogdata) end local current_mapgen_internal = current_mapgen - if lua_mapgens[current_mapgen_internal] and current_mapgen == dialogdata.mg then - current_mapgen_internal = "singlenode" + if not is_internal_mapgen then + -- Select singlenode if using lua-defined mapgen + -- Here we have to make sure it doesn't override an internal mapgen + if lua_mapgens[current_mapgen_internal] ~= nil and (current_mapgen == dialogdata.mg or lua_mapgens[current_mapgen_internal].title == dialogdata.mg) then + current_mapgen_internal = "singlenode" + end end -- The logic of the flag element IDs is as follows: @@ -382,10 +403,24 @@ local function create_world_buttonhandler(this, fields) local mapgen_internal = this.data.mg local mapgen = nil - local lua_mapgens = core.get_lua_mapgen_descriptions() - if lua_mapgens[this.data.mg] then - mapgen_internal = "singlenode" - mapgen = this.data.mg + -- This is used to make sure that the internal mapgens are never overwritten by an ill-playing mapgen + local internal_mapgens = core.get_mapgen_names() + local is_internal_mapgen = false + for _, mg in pairs(internal_mapgens) do + if mg == this.data.mg then + is_internal_mapgen = true + end + end + + if not is_internal_mapgen then + local lua_mapgens = core.get_lua_mapgen_descriptions_and_title() + for name, v in pairs(lua_mapgens) do + if v.title == this.data.mg or (v.title == nil and name == this.data.mg) then + mapgen_internal = "singlenode" + mapgen = name + break + end + end end -- actual names as used by engine diff --git a/doc/lua_api.md b/doc/lua_api.md index 20f18366e..d3877e8a8 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -421,6 +421,7 @@ Mapgen directory structure ├── mapgenname │   ├── mapgen.conf │   ├── init.lua + │   ├── locale/ │   └── └── another diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index ead7695b4..75ae13ab7 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -109,8 +109,8 @@ of manually putting one, as different OSs use different delimiters. E.g. * `handle:stop()` or `core.sound_stop(handle)` * `core.get_mapgen_names([include_hidden=false])` -> table of map generator algorithms registered in the core (possible in async calls) -* `core.get_lua_mapgen_descriptions()` -> map of `[mapgen_name] = mapgen_description` as listed - in `mapgen.conf`. +* `core.get_lua_mapgen_descriptions_and_title()` -> map of `[mapgen_name] = {desc = , title = }` as listed + in `mapgen.conf`, and `nil` if they don't exist. * `core.get_cache_path()` -> path of cache * `core.get_temp_path([param])` (possible in async calls) * `param`=true: returns path to a newly created temporary file diff --git a/src/content/mods.cpp b/src/content/mods.cpp index 386356d6f..f37f2c86e 100644 --- a/src/content/mods.cpp +++ b/src/content/mods.cpp @@ -88,6 +88,9 @@ bool parseModContents(ModSpec &spec) else spec.deprecation_msgs.push_back("Mods not having a mod.conf file with the name is deprecated."); + if (info.exists("title")) + spec.title = info.get("title"); + if (info.exists("author")) spec.author = info.get("author"); diff --git a/src/content/mods.h b/src/content/mods.h index b3c3894f9..6a037e237 100644 --- a/src/content/mods.h +++ b/src/content/mods.h @@ -27,6 +27,7 @@ struct ModSpec std::string author; std::string path; // absolute path on disk std::string desc; + std::string title; int release = 0; // if normal mod: diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 61798038a..4e3bf9caa 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -664,18 +664,49 @@ int ModApiMainMenu::l_get_mapgen_names(lua_State *L) } /******************************************************************************/ -int ModApiMainMenu::l_get_lua_mapgen_descriptions(lua_State *L) +int ModApiMainMenu::l_get_lua_mapgen_descriptions_and_title(lua_State *L) { - std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(porting::path_share + DIR_DELIM + "mapgens" + DIR_DELIM, "mapgen/")); + std::vector<ModSpec> mapgens_in_path = flattenMods(getModsInPath(porting::path_share + DIR_DELIM + "mapgens" + DIR_DELIM, "mapgen/")); lua_newtable(L); - for (const auto &mod : addon_mods_in_path) { + int top = lua_gettop(L); + + // If more than one mapgen use the same title. + std::map<std::string, int> mapgen_title_counts; + + for (const auto &mod : mapgens_in_path) { if (mod.is_mapgen) { - lua_pushstring(L, mod.desc.c_str()); - lua_setfield(L, -2, mod.name.c_str()); + lua_pushstring(L, mod.name.c_str()); + + lua_newtable(L); + int top_lvl2 = lua_gettop(L); + + lua_pushstring(L, "desc"); + if (mod.title != "") + lua_pushstring(L, mod.desc.c_str()); + else + lua_pushnil(L); + lua_settable(L, top_lvl2); + + lua_pushstring(L, "title"); + if (mod.title != "") { + std::string mapgen_tite = mod.title; + if (mapgen_title_counts.find(mod.title) == mapgen_title_counts.end()) { + mapgen_title_counts[mod.title] = 0; + } else { + mapgen_title_counts[mod.title]++; + mapgen_tite = mapgen_tite + " (" + mod.name + ")"; + } + + lua_pushstring(L, mapgen_tite.c_str()); + } else { + lua_pushnil(L); + } + lua_settable(L, top_lvl2); + + lua_settable(L, top); } } - return 1; } @@ -1077,7 +1108,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(set_background); API_FCT(set_topleft_text); API_FCT(get_mapgen_names); - API_FCT(get_lua_mapgen_descriptions); + API_FCT(get_lua_mapgen_descriptions_and_title); API_FCT(get_user_path); API_FCT(get_modpath); API_FCT(get_modpaths); @@ -1119,7 +1150,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top) API_FCT(get_worlds); API_FCT(get_games); API_FCT(get_mapgen_names); - API_FCT(get_lua_mapgen_descriptions); + API_FCT(get_lua_mapgen_descriptions_and_title); API_FCT(get_user_path); API_FCT(get_modpath); API_FCT(get_modpaths); diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index b6e27f0b2..f45138493 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -51,7 +51,7 @@ private: static int l_get_mapgen_names(lua_State *L); - static int l_get_lua_mapgen_descriptions(lua_State *L); + static int l_get_lua_mapgen_descriptions_and_title(lua_State *L); static int l_get_language(lua_State *L);