Beispiel #1
0
void Client::loadMods()
{
	// Load builtin
	scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());

	// If modding is not enabled, don't load mods, just builtin
	if (!m_modding_enabled) {
		return;
	}
	ClientModConfiguration modconf(getClientModsLuaPath());
	m_mods = modconf.getMods();
	std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
	// complain about mods with unsatisfied dependencies
	if (!modconf.isConsistent()) {
		modconf.printUnsatisfiedModsError();
	}

	// Print mods
	infostream << "Client Loading mods: ";
	for (const ModSpec &mod : m_mods)
		infostream << mod.name << " ";
	infostream << std::endl;

	// Load and run "mod" scripts
	for (const ModSpec &mod : m_mods) {
		if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
			throw ModError("Error loading mod \"" + mod.name +
				"\": Mod name does not follow naming conventions: "
					"Only characters [a-z0-9_] are allowed.");
		}
		scanModIntoMemory(mod.name, mod.path);
	}
}
Beispiel #2
0
void Client::initMods()
{
	m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);

	// If modding is not enabled, don't load mods, just builtin
	if (!m_modding_enabled) {
		return;
	}

	ClientModConfiguration modconf(getClientModsLuaPath());
	std::vector<ModSpec> mods = modconf.getMods();
	std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
	// complain about mods with unsatisfied dependencies
	if (!modconf.isConsistent()) {
		modconf.printUnsatisfiedModsError();
	}

	// Print mods
	infostream << "Client Loading mods: ";
	for (std::vector<ModSpec>::const_iterator i = mods.begin();
		i != mods.end(); ++i) {
		infostream << (*i).name << " ";
	}

	infostream << std::endl;
	// Load and run "mod" scripts
	for (std::vector<ModSpec>::const_iterator it = mods.begin();
		it != mods.end(); ++it) {
		const ModSpec &mod = *it;
		if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
			throw ModError("Error loading mod \"" + mod.name +
				"\": Mod name does not follow naming conventions: "
					"Only characters [a-z0-9_] are allowed.");
		}
		std::string script_path = mod.path + DIR_DELIM + "init.lua";
		infostream << "  [" << padStringRight(mod.name, 12) << "] [\""
			<< script_path << "\"]" << std::endl;
		m_script->loadMod(script_path, mod.name);
	}
}
Beispiel #3
0
ModConfiguration::ModConfiguration(std::string worldpath)
{
	SubgameSpec gamespec = findWorldSubgame(worldpath);

	// Add common mods
	std::map<std::string, ModSpec> common_mods;
	std::vector<std::string> inexistent_common_mods;
	Settings gameconf;
	if(getGameConfig(gamespec.path, gameconf)){
		if(gameconf.exists("common_mods")){
			Strfnd f(gameconf.get("common_mods"));
			while(!f.atend()){
				std::string modname = trim(f.next(","));
				if(modname.empty())
					continue;
				ModSpec spec = findCommonMod(modname);
				if(spec.name.empty())
					inexistent_common_mods.push_back(modname);
				else
					common_mods.insert(std::make_pair(modname, spec));
			}
		}
	}
	if(!inexistent_common_mods.empty()){
		std::string s = "Required common mods ";
		for(u32 i=0; i<inexistent_common_mods.size(); i++){
			if(i != 0) s += ", ";
			s += std::string("\"") + inexistent_common_mods[i] + "\"";
		}
		s += " could not be found.";
		throw ModError(s);
	}
	addMods(flattenMods(common_mods));

	// Add all game mods and all world mods
	addModsInPath(gamespec.gamemods_path);
	addModsInPath(worldpath + DIR_DELIM + "worldmods");

	// 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));
		}
	}

	// Collect all mods in gamespec.addon_mods_paths,
	// excluding those in the set exclude_mod_names
	std::vector<ModSpec> addon_mods;
	for(std::set<std::string>::const_iterator it_path = gamespec.addon_mods_paths.begin();
			it_path != gamespec.addon_mods_paths.end(); ++it_path)
	{
		std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(*it_path));
		for(std::vector<ModSpec>::iterator it = addon_mods_in_path.begin();
			it != addon_mods_in_path.end(); ++it)
		{
			ModSpec& mod = *it;
			if(exclude_mod_names.count(mod.name) == 0)
				addon_mods.push_back(mod);
		}
	}

	addMods(addon_mods);

	// report on name conflicts
	if(!m_name_conflicts.empty()){
		std::string s = "Unresolved name conflicts for mods ";
		for(std::set<std::string>::const_iterator it = m_name_conflicts.begin();
				it != m_name_conflicts.end(); ++it)
		{
			if(it != m_name_conflicts.begin()) s += ", ";
			s += std::string("\"") + (*it) + "\"";
		}
		s += ".";
		throw ModError(s);
	}

	// get the mods in order
	resolveDependencies();
}
Beispiel #4
0
ModConfiguration::ModConfiguration(std::string worldpath)
{
	SubgameSpec gamespec = findWorldSubgame(worldpath);

	// Add all game mods and all world mods
	addModsInPath(gamespec.gamemods_path);
	addModsInPath(worldpath + DIR_DELIM + "worldmods");

	// 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> include_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))
		{
			include_mod_names.insert(name.substr(9));
		}
	}

	// Collect all mods that are also in include_mod_names
	std::vector<ModSpec> addon_mods;
	for(std::set<std::string>::const_iterator it_path = gamespec.addon_mods_paths.begin();
			it_path != gamespec.addon_mods_paths.end(); ++it_path)
	{
		std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(*it_path));
		for(std::vector<ModSpec>::iterator it = addon_mods_in_path.begin();
			it != addon_mods_in_path.end(); ++it)
		{
			ModSpec& mod = *it;
			if(include_mod_names.count(mod.name) != 0)
				addon_mods.push_back(mod);
			else
				worldmt_settings.setBool("load_mod_" + mod.name, false);
		}
	}
	worldmt_settings.updateConfigFile(worldmt.c_str());

	addMods(addon_mods);

	// report on name conflicts
	if(!m_name_conflicts.empty()){
		std::string s = "Unresolved name conflicts for mods ";
		for(std::set<std::string>::const_iterator it = m_name_conflicts.begin();
				it != m_name_conflicts.end(); ++it)
		{
			if(it != m_name_conflicts.begin()) s += ", ";
			s += std::string("\"") + (*it) + "\"";
		}
		s += ".";
		throw ModError(s);
	}

	// get the mods in order
	resolveDependencies();
}
Beispiel #5
0
// Get a dependency-sorted list of ModSpecs
core::list<ModSpec> getMods(core::list<std::string> &modspaths)
		throw(ModError)
{
	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;
		std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
		for(u32 j=0; j<dirlist.size(); j++){
			if(!dirlist[j].dir)
				continue;
			std::string modname = dirlist[j].name;
			std::string modpath = modspath + DIR_DELIM + modname;
			// Detect mod name conflicts
			{
				std::map<std::string, std::string>::const_iterator i;
				i = mod_names.find(modname);
				if(i != mod_names.end()){
					std::string s;
					infostream<<"WARNING: Mod name conflict detected: "
							<<std::endl
							<<"Already loaded: "<<i->second<<std::endl
							<<"Will not load: "<<modpath<<std::endl;
					continue;
				}
			}
			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);
			}
			ModSpec spec(modname, modpath, depends);
			mods_unsorted.push_back(spec);
			if(depends.empty())
				mods_satisfied.push(spec);
			mod_names[modname] = modpath;
		}
	}
	// 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);
		}
	}
	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)<<"\"";
		}
		errs<<"."<<std::endl;
		mods_sorted.push_back(mod);
	}
	if(errs.str().size() != 0){
		throw ModError(errs.str());
	}
	return mods_sorted;
}