668 changes: 668 additions & 0 deletions src/guiConfigureWorld.cpp

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions src/guiConfigureWorld.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
Minetest-c55
Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef GUICONFIGUREWORLD_HEADER
#define GUICONFIGUREWORLD_HEADER

#include "irrlichttypes_extrabloated.h"
#include "modalMenu.h"
#include "mods.h"
#include "subgame.h"
#include "settings.h"


namespace irr{
namespace gui{
class IGUITreeViewNode;
}
}

class GUIConfigureWorld : public GUIModalMenu
{
public:
GUIConfigureWorld(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, WorldSpec wspec);

void regenerateGui(v2u32 screensize);

void drawMenu();

bool OnEvent(const SEvent& event);

private:
WorldSpec m_wspec;
SubgameSpec m_gspec;

// tree of installed add-on mods. key is the mod name, modpacks
// are not expanded.
std::map<std::string, ModSpec> m_addontree;

// like m_addontree, but modpacks are expanded.
std::map<std::string, ModSpec> m_addonmods;

// list of game mods (flattened)
std::map<std::string, ModSpec> m_gamemods;

// list of world mods (flattened)
std::map<std::string, ModSpec> m_worldmods;

// for each mod, the set of mods depending on it
std::multimap<std::string, std::string> m_reverse_depends;

// the settings in the world.mt file
Settings m_settings;

// mods that are installed but not mentioned in world.mt file
std::set<std::string> m_new_mod_names;

// maps modnames to nodes in m_treeview
std::map<std::string,gui::IGUITreeViewNode*> m_nodes;

gui::IGUIStaticText* m_modname_text;
gui::IGUITreeView* m_treeview;
gui::IGUIButton* m_enableall;
gui::IGUIButton* m_disableall;
gui::IGUICheckBox* m_enabled_checkbox;
gui::IGUIListBox* m_dependencies_listbox;
gui::IGUIListBox* m_rdependencies_listbox;
void buildTreeView(std::map<std::string,ModSpec> mods,
gui::IGUITreeViewNode* node);
void adjustSidebar();
void enableAllMods(std::map<std::string,ModSpec> mods, bool enable);
void setEnabled(std::string modname, bool enable)
{
if(enable)
enableMod(modname);
else
disableMod(modname);
};

void enableMod(std::string modname);
void disableMod(std::string modname);

// hack to work around wonky handling of double-click in
// irrlicht. store selected index of listbox items here so event
// handling can check whether it was a real double click on the
// same item. (irrlicht also reports a double click if you rapidly
// select two different items.)
int selecting_dep;
int selecting_rdep;

IMenuManager* m_menumgr;
};
#endif
22 changes: 17 additions & 5 deletions src/guiMainMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiMainMenu.h"
#include "guiKeyChangeMenu.h"
#include "guiCreateWorld.h"
#include "guiConfigureWorld.h"
#include "guiMessageMenu.h"
#include "guiConfirmMenu.h"
#include "debug.h"
Expand Down Expand Up @@ -1033,11 +1034,22 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
return true;
}
case GUI_ID_CONFIGURE_WORLD_BUTTON: {
GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
-1, menumgr,
wgettext("Nothing here"));
menu->drop();
return true;
MainMenuData cur;
readInput(&cur);
if(cur.selected_world == -1)
{
(new GUIMessageMenu(env, parent, -1, menumgr,
wgettext("Cannot configure world: Nothing selected"))
)->drop();
}
else
{
WorldSpec wspec = m_data->worlds[cur.selected_world];
GUIConfigureWorld *menu = new GUIConfigureWorld(env, parent,
-1, menumgr, wspec);
menu->drop();
return true;
}
}
case GUI_ID_SERVERLIST_DELETE: {
gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
Expand Down
276 changes: 168 additions & 108 deletions src/mods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/

#include "mods.h"
#include <queue>
#include <fstream>
#include <sstream>
#include <map>
#include "filesys.h"
#include "strfnd.h"
#include "log.h"
#include "subgame.h"
#include "settings.h"

static void collectMods(const std::string &modspath,
std::queue<ModSpec> &mods_satisfied,
core::list<ModSpec> &mods_unsorted,
std::map<std::string, std::string> &mod_names,
std::string indentation)
std::map<std::string, ModSpec> getModsInPath(std::string path)
{
TRACESTREAM(<<indentation<<"collectMods(\""<<modspath<<"\")"<<std::endl);
TRACEDO(indentation += " ");
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
std::map<std::string, ModSpec> result;
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
for(u32 j=0; j<dirlist.size(); j++){
if(!dirlist[j].dir)
continue;
Expand All @@ -43,119 +36,186 @@ static void collectMods(const std::string &modspath,
// VCS directories like ".git" or ".svn"
if(modname[0] == '.')
continue;
std::string modpath = modspath + DIR_DELIM + modname;
TRACESTREAM(<<indentation<<"collectMods: "<<modname<<" at \""<<modpath<<"\""<<std::endl);
std::string modpath = path + DIR_DELIM + modname;

// Handle modpacks (defined by containing modpack.txt)
{
std::ifstream is((modpath+DIR_DELIM+"modpack.txt").c_str(),
std::ifstream modpack_is((modpath+DIR_DELIM+"modpack.txt").c_str(),
std::ios_base::binary);
if(is.good()){
// Is a modpack
is.close(); // We don't actually need the file
// Recurse into it
collectMods(modpath, mods_satisfied, mods_unsorted, mod_names, indentation);
continue;
}
}
// Detect mod name conflicts
if(modpack_is.good()) //a modpack, recursively get the mods in it
{
std::map<std::string, std::string>::const_iterator i;
i = mod_names.find(modname);
if(i != mod_names.end()){
std::string s;
infostream<<indentation<<"WARNING: Mod name conflict detected: "
<<std::endl
<<"Already loaded: "<<i->second<<std::endl
<<"Will not load: "<<modpath<<std::endl;
continue;
}
modpack_is.close(); // We don't actually need the file
ModSpec spec(modname,modpath);
spec.modpack_content = getModsInPath(modpath);
result.insert(std::make_pair(modname,spec));
}
std::set<std::string> depends;
std::ifstream is((modpath+DIR_DELIM+"depends.txt").c_str(),
else // not a modpack, add the modspec
{
std::set<std::string> depends;
std::ifstream is((modpath+DIR_DELIM+"depends.txt").c_str(),
std::ios_base::binary);
while(is.good()){
std::string dep;
std::getline(is, dep);
dep = trim(dep);
if(dep != "")
depends.insert(dep);
while(is.good())
{
std::string dep;
std::getline(is, dep);
dep = trim(dep);
if(dep != "")
depends.insert(dep);
}

ModSpec spec(modname, modpath, depends);
result.insert(std::make_pair(modname,spec));
}
ModSpec spec(modname, modpath, depends);
mods_unsorted.push_back(spec);
if(depends.empty())
mods_satisfied.push(spec);
mod_names[modname] = modpath;
}
return result;
}

// Get a dependency-sorted list of ModSpecs
core::list<ModSpec> getMods(core::list<std::string> &modspaths)
throw(ModError)
std::map<std::string, ModSpec> flattenModTree(std::map<std::string, ModSpec> mods)
{
std::queue<ModSpec> mods_satisfied;
core::list<ModSpec> mods_unsorted;
core::list<ModSpec> mods_sorted;
// name, path: For detecting name conflicts
std::map<std::string, std::string> mod_names;
for(core::list<std::string>::Iterator i = modspaths.begin();
i != modspaths.end(); i++){
std::string modspath = *i;
collectMods(modspath, mods_satisfied, mods_unsorted, mod_names, "");
std::map<std::string, ModSpec> result;
for(std::map<std::string,ModSpec>::iterator it = mods.begin();
it != mods.end(); ++it)
{
ModSpec mod = (*it).second;
if(!mod.modpack_content.empty()) //is a modpack
{
std::map<std::string, ModSpec> content =
flattenModTree(mod.modpack_content);
result.insert(content.begin(),content.end());
result.insert(std::make_pair(mod.name,mod));
}
else //not a modpack
{
result.insert(std::make_pair(mod.name,mod));
}
}
// Sort by depencencies
while(!mods_satisfied.empty()){
ModSpec mod = mods_satisfied.front();
mods_satisfied.pop();
mods_sorted.push_back(mod);
for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
i != mods_unsorted.end(); i++){
ModSpec &mod2 = *i;
if(mod2.unsatisfied_depends.empty())
continue;
mod2.unsatisfied_depends.erase(mod.name);
if(!mod2.unsatisfied_depends.empty())
continue;
mods_satisfied.push(mod2);
return result;
}

std::vector<ModSpec> flattenMods(std::map<std::string, ModSpec> mods)
{
std::vector<ModSpec> result;
for(std::map<std::string,ModSpec>::iterator it = mods.begin();
it != mods.end(); ++it)
{
ModSpec mod = (*it).second;
if(!mod.modpack_content.empty()) //is a modpack
{
std::vector<ModSpec> content = flattenMods(mod.modpack_content);
result.reserve(result.size() + content.size());
result.insert(result.end(),content.begin(),content.end());

}
else //not a modpack
{
// infostream << "inserting mod " << mod.name << std::endl;
result.push_back(mod);
}
}
std::ostringstream errs(std::ios::binary);
// Check unsatisfied dependencies
for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
i != mods_unsorted.end(); i++){
ModSpec &mod = *i;
if(mod.unsatisfied_depends.empty())
continue;
errs<<"mod \""<<mod.name
<<"\" has unsatisfied dependencies:";
for(std::set<std::string>::iterator
i = mod.unsatisfied_depends.begin();
i != mod.unsatisfied_depends.end(); i++){
errs<<" \""<<(*i)<<"\"";
return result;
}

std::vector<ModSpec> filterMods(std::vector<ModSpec> mods,
std::set<std::string> exclude_mod_names)
{
std::vector<ModSpec> result;
for(std::vector<ModSpec>::iterator it = mods.begin();
it != mods.end(); ++it)
{
ModSpec& mod = *it;
if(exclude_mod_names.count(mod.name) == 0)
result.push_back(mod);
}
return result;
}

void ModConfiguration::addModsInPathFiltered(std::string path, std::set<std::string> exclude_mods)
{
addMods(filterMods(flattenMods(getModsInPath(path)),exclude_mods));
}


void ModConfiguration::addMods(std::vector<ModSpec> new_mods)
{
// Step 1: remove mods in sorted_mods from unmet dependencies
// of new_mods. new mods without unmet dependencies are
// temporarily stored in satisfied_mods
std::vector<ModSpec> satisfied_mods;
for(std::vector<ModSpec>::iterator it = m_sorted_mods.begin();
it != m_sorted_mods.end(); ++it)
{
ModSpec mod = *it;
for(std::vector<ModSpec>::iterator it_new = new_mods.begin();
it_new != new_mods.end(); ++it_new)
{
ModSpec& mod_new = *it_new;
//infostream << "erasing dependency " << mod.name << " from " << mod_new.name << std::endl;
mod_new.unsatisfied_depends.erase(mod.name);
}
errs<<"."<<std::endl;
mods_sorted.push_back(mod);
}
// If an error occurred, throw an exception
if(errs.str().size() != 0){
throw ModError(errs.str());

// split new mods into satisfied and unsatisfied
for(std::vector<ModSpec>::iterator it = new_mods.begin();
it != new_mods.end(); ++it)
{
ModSpec mod_new = *it;
if(mod_new.unsatisfied_depends.empty())
satisfied_mods.push_back(mod_new);
else
m_unsatisfied_mods.push_back(mod_new);
}
// Print out some debug info
TRACESTREAM(<<"Detected mods in load order:"<<std::endl);
for(core::list<ModSpec>::Iterator i = mods_sorted.begin();
i != mods_sorted.end(); i++){
ModSpec &mod = *i;
TRACESTREAM(<<"name=\""<<mod.name<<"\" path=\""<<mod.path<<"\"");
TRACESTREAM(<<" depends=[");
for(std::set<std::string>::iterator i = mod.depends.begin();
i != mod.depends.end(); i++)
TRACESTREAM(<<" "<<(*i));
TRACESTREAM(<<" ] unsatisfied_depends=[");
for(std::set<std::string>::iterator i = mod.unsatisfied_depends.begin();
i != mod.unsatisfied_depends.end(); i++)
TRACESTREAM(<<" "<<(*i));
TRACESTREAM(<<" ]"<<std::endl);

// Step 2: mods without unmet dependencies can be appended to
// the sorted list.
while(!satisfied_mods.empty())
{
ModSpec mod = satisfied_mods.back();
m_sorted_mods.push_back(mod);
satisfied_mods.pop_back();
for(std::list<ModSpec>::iterator it = m_unsatisfied_mods.begin();
it != m_unsatisfied_mods.end(); )
{
ModSpec& mod2 = *it;
mod2.unsatisfied_depends.erase(mod.name);
if(mod2.unsatisfied_depends.empty())
{
satisfied_mods.push_back(mod2);
it = m_unsatisfied_mods.erase(it);
}
else
++it;
}
}
return mods_sorted;
}

ModConfiguration::ModConfiguration(std::string worldpath)
{
// Add all world mods and all game mods
addModsInPath(worldpath + DIR_DELIM + "worldmods");
SubgameSpec gamespec = findWorldSubgame(worldpath);
addModsInPath(gamespec.gamemods_path);

// check world.mt file for mods explicitely declared to be
// loaded or not by a load_mod_<modname> = ... line.
std::string worldmt = worldpath+DIR_DELIM+"world.mt";
Settings worldmt_settings;
worldmt_settings.readConfigFile(worldmt.c_str());
std::vector<std::string> names = worldmt_settings.getNames();
std::set<std::string> exclude_mod_names;
for(std::vector<std::string>::iterator it = names.begin();
it != names.end(); ++it)
{
std::string name = *it;
// for backwards compatibility: exclude only mods which are
// explicitely excluded. if mod is not mentioned at all, it is
// enabled. So by default, all installed mods are enabled.
if (name.compare(0,9,"load_mod_") == 0 &&
!worldmt_settings.getBool(name))
{
exclude_mod_names.insert(name.substr(9));
}
}

for(std::set<std::string>::const_iterator i = gamespec.addon_mods_paths.begin();
i != gamespec.addon_mods_paths.end(); ++i)
addModsInPathFiltered((*i),exclude_mod_names);
}
89 changes: 82 additions & 7 deletions src/mods.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#include "irrlichttypes.h"
#include <irrList.h>
#include <list>
#include <set>
#include <vector>
#include <string>
#include <map>
#include <exception>

class ModError : public std::exception
Expand All @@ -47,21 +50,93 @@ struct ModSpec
{
std::string name;
std::string path;
//if normal mod:
std::set<std::string> depends;
std::set<std::string> unsatisfied_depends;

ModSpec(const std::string &name_="", const std::string path_="",
const std::set<std::string> &depends_=std::set<std::string>()):
// if modpack:
std::map<std::string,ModSpec> modpack_content;
ModSpec(const std::string name_="", const std::string path_="",
const std::set<std::string> depends_=std::set<std::string>()):
name(name_),
path(path_),
depends(depends_),
unsatisfied_depends(depends_)
unsatisfied_depends(depends_),
modpack_content()
{}
};

// Get a dependency-sorted list of ModSpecs
core::list<ModSpec> getMods(core::list<std::string> &modspaths)
throw(ModError);

std::map<std::string,ModSpec> getModsInPath(std::string path);

// expands modpack contents, but does not replace them.
std::map<std::string, ModSpec> flattenModTree(std::map<std::string, ModSpec> mods);

// replaces modpack Modspecs with their content
std::vector<ModSpec> flattenMods(std::map<std::string,ModSpec> mods);

// removes Mods mentioned in exclude_mod_names
std::vector<ModSpec> filterMods(std::vector<ModSpec> mods,
std::set<std::string> exclude_mod_names);

// a ModConfiguration is a subset of installed mods, expected to have
// all dependencies fullfilled, so it can be used as a list of mods to
// load when the game starts.
class ModConfiguration
{
public:
ModConfiguration():
m_unsatisfied_mods(),
m_sorted_mods()
{}


ModConfiguration(std::string worldpath);

// adds all mods in the given path. used for games, modpacks
// and world-specific mods (worldmods-folders)
void addModsInPath(std::string path)
{
addMods(flattenMods(getModsInPath(path)));
}

// adds all mods in the given path whose name does not appear
// in the exclude_mods set.
void addModsInPathFiltered(std::string path, std::set<std::string> exclude_mods);

// adds all mods in the set.
void addMods(std::vector<ModSpec> mods);

// checks if all dependencies are fullfilled.
bool isConsistent()
{
return m_unsatisfied_mods.empty();
}

std::vector<ModSpec> getMods()
{
return m_sorted_mods;
}

std::list<ModSpec> getUnsatisfiedMods()
{
return m_unsatisfied_mods;
}

private:

// mods with unmet dependencies. This is a list and not a
// vector because we want easy removal of elements at every
// position.
std::list<ModSpec> m_unsatisfied_mods;

// list of mods sorted such that they can be loaded in the
// given order with all dependencies being fullfilled. I.e.,
// every mod in this list has only dependencies on mods which
// appear earlier in the vector.
std::vector<ModSpec> m_sorted_mods;

};


#endif

80 changes: 55 additions & 25 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -980,33 +980,65 @@ Server::Server(
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
m_rollback = createRollbackManager(rollback_path, this);

// Add world mod search path
m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
// Add addon mod search path
for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
i != m_gamespec.mods_paths.end(); i++)
m_modspaths.push_front((*i));

// Print out mod search paths
for(core::list<std::string>::Iterator i = m_modspaths.begin();
i != m_modspaths.end(); i++){
std::string modspath = *i;
infostream<<"- mods: "<<modspath<<std::endl;
}

// Path to builtin.lua
std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";

// Create world if it doesn't exist
if(!initializeWorld(m_path_world, m_gamespec.id))
throw ServerError("Failed to initialize world");

ModConfiguration modconf(m_path_world);
m_mods = modconf.getMods();
// complain about mods with unsatisfied dependencies
if(!modconf.isConsistent())
{
errorstream << "The following mods have unsatisfied dependencies: ";
std::list<ModSpec> modlist = modconf.getUnsatisfiedMods();
for(std::list<ModSpec>::iterator it = modlist.begin();
it != modlist.end(); ++it)
{
errorstream << (*it).name << " ";
}
errorstream << std::endl;
}

Settings worldmt_settings;
std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
worldmt_settings.readConfigFile(worldmt.c_str());
std::vector<std::string> names = worldmt_settings.getNames();
std::set<std::string> exclude_mod_names;
std::set<std::string> load_mod_names;
for(std::vector<std::string>::iterator it = names.begin();
it != names.end(); ++it)
{
std::string name = *it;
if (name.compare(0,9,"load_mod_")==0)
{
if(worldmt_settings.getBool(name))
load_mod_names.insert(name.substr(9));
else
exclude_mod_names.insert(name.substr(9));
}
}
// complain about mods declared to be loaded, but not found
for(std::vector<ModSpec>::iterator it = m_mods.begin();
it != m_mods.end(); ++it)
load_mod_names.erase((*it).name);
if(!load_mod_names.empty())
{
errorstream << "The following mods could not be found: ";
for(std::set<std::string>::iterator it = load_mod_names.begin();
it != load_mod_names.end(); ++it)
errorstream << (*it) << " ";
errorstream << std::endl;
}

// Path to builtin.lua
std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";

// Lock environment
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);

// Initialize scripting

infostream<<"Server: Initializing Lua"<<std::endl;
m_lua = script_init();
assert(m_lua);
Expand All @@ -1021,18 +1053,16 @@ Server::Server(
<<builtinpath<<std::endl;
throw ModError("Failed to load and run "+builtinpath);
}
// Find mods in mod search paths
m_mods = getMods(m_modspaths);
// Print 'em
infostream<<"Server: Loading mods: ";
for(core::list<ModSpec>::Iterator i = m_mods.begin();
for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
infostream<<mod.name<<" ";
}
infostream<<std::endl;
// Load and run "mod" scripts
for(core::list<ModSpec>::Iterator i = m_mods.begin();
for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
Expand Down Expand Up @@ -4105,7 +4135,7 @@ void Server::fillMediaCache()

// Collect all media file paths
std::list<std::string> paths;
for(core::list<ModSpec>::Iterator i = m_mods.begin();
for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
paths.push_back(mod.path + DIR_DELIM + "textures");
Expand Down Expand Up @@ -4770,7 +4800,7 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager()

const ModSpec* Server::getModSpec(const std::string &modname)
{
for(core::list<ModSpec>::Iterator i = m_mods.begin();
for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
if(mod.name == modname)
Expand All @@ -4780,7 +4810,7 @@ const ModSpec* Server::getModSpec(const std::string &modname)
}
void Server::getModNames(core::list<std::string> &modlist)
{
for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
{
modlist.push_back((*i).name);
}
Expand Down
2 changes: 1 addition & 1 deletion src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
EventManager *m_event;

// Mods
core::list<ModSpec> m_mods;
std::vector<ModSpec> m_mods;

/*
Threads
Expand Down
20 changes: 20 additions & 0 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,26 @@ class Settings
os<<name<<" = "<<value<<"\n";
}
}

// return all keys used
std::vector<std::string> getNames(){
std::vector<std::string> names;
for(core::map<std::string, std::string>::Iterator
i = m_settings.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
names.push_back(name);
}
return names;
}

// remove a setting
bool remove(const std::string& name)
{
return m_settings.remove(name);
}


bool parseConfigLine(const std::string &line)
{
Expand Down
6 changes: 3 additions & 3 deletions src/subgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,17 @@ SubgameSpec findSubgame(const std::string &id)
}
if(game_path == "")
return SubgameSpec();
std::string gamemod_path = game_path + DIR_DELIM + "mods";
// Find mod directories
std::set<std::string> mods_paths;
mods_paths.insert(game_path + DIR_DELIM + "mods");
if(!user_game)
mods_paths.insert(share + DIR_DELIM + "mods" + DIR_DELIM + id);
if(user != share || user_game)
mods_paths.insert(user + DIR_DELIM + "mods" + DIR_DELIM + id);
std::string game_name = getGameName(game_path);
if(game_name == "")
game_name = id;
return SubgameSpec(id, game_path, mods_paths, game_name);
return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name);
}

SubgameSpec findWorldSubgame(const std::string &world_path)
Expand All @@ -96,7 +96,7 @@ SubgameSpec findWorldSubgame(const std::string &world_path)
SubgameSpec gamespec;
gamespec.id = world_gameid;
gamespec.path = world_gamepath;
gamespec.mods_paths.insert(world_gamepath + DIR_DELIM + "mods");
gamespec.gamemods_path= world_gamepath + DIR_DELIM + "mods";
gamespec.name = getGameName(world_gamepath);
if(gamespec.name == "")
gamespec.name = "unknown";
Expand Down
13 changes: 8 additions & 5 deletions src/subgame.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct SubgameSpec
{
std::string id; // "" = game does not exist
std::string path;
std::set<std::string> mods_paths;
std::string path; // path to game
std::string gamemods_path; //path to mods of the game
std::set<std::string> addon_mods_paths; //paths to addon mods for this game
std::string name;

SubgameSpec(const std::string &id_="",
const std::string &path_="",
const std::set<std::string> &mods_paths_=std::set<std::string>(),
const std::string &path_="",
const std::string &gamemods_path_="",
const std::set<std::string> &addon_mods_paths_=std::set<std::string>(),
const std::string &name_=""):
id(id_),
path(path_),
mods_paths(mods_paths_),
gamemods_path(gamemods_path_),
addon_mods_paths(addon_mods_paths_),
name(name_)
{}

Expand Down