- // 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);
+
+ // Add new mods
+ for(int want_from_modpack = 1; want_from_modpack >= 0; --want_from_modpack){
+ // First iteration:
+ // Add all the mods that come from modpacks
+ // Second iteration:
+ // Add all the mods that didn't come from modpacks
+
+ std::set<std::string> seen_this_iteration;
+
+ for(std::vector<ModSpec>::const_iterator it = new_mods.begin();
+ it != new_mods.end(); ++it){
+ const ModSpec &mod = *it;
+ if(mod.part_of_modpack != (bool)want_from_modpack)
+ continue;
+ if(existing_mods.count(mod.name) == 0){
+ // GOOD CASE: completely new mod.
+ m_unsatisfied_mods.push_back(mod);
+ existing_mods[mod.name] = m_unsatisfied_mods.size() - 1;
+ }
+ else if(seen_this_iteration.count(mod.name) == 0){
+ // BAD CASE: name conflict in different levels.
+ u32 oldindex = existing_mods[mod.name];
+ const ModSpec &oldmod = m_unsatisfied_mods[oldindex];
+ actionstream<<"WARNING: Mod name conflict detected: \""
+ <<mod.name<<"\""<<std::endl
+ <<"Will not load: "<<oldmod.path<<std::endl
+ <<"Overridden by: "<<mod.path<<std::endl;
+ m_unsatisfied_mods[oldindex] = mod;
+
+ // If there was a "VERY BAD CASE" name conflict
+ // in an earlier level, ignore it.
+ m_name_conflicts.erase(mod.name);
+ }
+ else{
+ // VERY BAD CASE: name conflict in the same level.
+ u32 oldindex = existing_mods[mod.name];
+ const ModSpec &oldmod = m_unsatisfied_mods[oldindex];
+ errorstream<<"WARNING: Mod name conflict detected: \""
+ <<mod.name<<"\""<<std::endl
+ <<"Will not load: "<<oldmod.path<<std::endl
+ <<"Will not load: "<<mod.path<<std::endl;
+ m_unsatisfied_mods[oldindex] = mod;
+ m_name_conflicts.insert(mod.name);
+ }
+ seen_this_iteration.insert(mod.name);
+ }
+ }
+}
+
+void ModConfiguration::resolveDependencies()
+{
+ // Step 1: Compile a list of the mod names we're working with
+ std::set<std::string> modnames;
+ for(std::vector<ModSpec>::iterator it = m_unsatisfied_mods.begin();
+ it != m_unsatisfied_mods.end(); ++it){
+ modnames.insert((*it).name);
+ }
+
+ // Step 2: get dependencies (including optional dependencies)
+ // of each mod, split mods into satisfied and unsatisfied
+ std::list<ModSpec> satisfied;
+ std::list<ModSpec> unsatisfied;
+ for(std::vector<ModSpec>::iterator it = m_unsatisfied_mods.begin();
+ it != m_unsatisfied_mods.end(); ++it){
+ ModSpec mod = *it;
+ mod.unsatisfied_depends = mod.depends;
+ // check which optional dependencies actually exist
+ for(std::set<std::string>::iterator it_optdep = mod.optdepends.begin();
+ it_optdep != mod.optdepends.end(); ++it_optdep){
+ std::string optdep = *it_optdep;
+ if(modnames.count(optdep) != 0)
+ mod.unsatisfied_depends.insert(optdep);
+ }
+ // if a mod has no depends it is initially satisfied
+ if(mod.unsatisfied_depends.empty())
+ satisfied.push_back(mod);
+ else
+ unsatisfied.push_back(mod);
+ }
+
+ // Step 3: mods without unmet dependencies can be appended to
+ // the sorted list.
+ while(!satisfied.empty()){
+ ModSpec mod = satisfied.back();
+ m_sorted_mods.push_back(mod);
+ satisfied.pop_back();
+ for(std::list<ModSpec>::iterator it = unsatisfied.begin();
+ it != unsatisfied.end(); ){
+ ModSpec& mod2 = *it;
+ mod2.unsatisfied_depends.erase(mod.name);
+ if(mod2.unsatisfied_depends.empty()){
+ satisfied.push_back(mod2);
+ it = unsatisfied.erase(it);
+ }
+ else{
+ ++it;
+ }
+ }