Remove plugin priorities

This commit is contained in:
Oliver Hamlet
2018-03-28 19:08:26 +01:00
parent 95896ed64b
commit 523dc87f04
18 changed files with 21 additions and 882 deletions
-3
View File
@@ -174,7 +174,6 @@ set (LOOT_API_SRC "${CMAKE_BINARY_DIR}/generated/loot_version.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message_content.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_cleaning_data.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_metadata.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/priority.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/tag.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game/game.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game/game_cache.cpp"
@@ -212,7 +211,6 @@ set (LOOT_API_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message_content.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_cleaning_data.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_metadata.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/priority.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/tag.h"
"${CMAKE_SOURCE_DIR}/include/loot/plugin_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/struct/masterlist_info.h"
@@ -263,7 +261,6 @@ set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_t
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/message_content_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/plugin_cleaning_data_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/plugin_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/priority_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/metadata/tag_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/plugin_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/sorting/group_sort_test.h"
-3
View File
@@ -75,9 +75,6 @@ Classes
.. doxygenclass:: loot::PluginMetadata
:members:
.. doxygenclass:: loot::Priority
:members:
.. doxygenclass:: loot::Tag
:members:
-25
View File
@@ -52,31 +52,6 @@ the group-derived plugin to the plugin would cause a cycle, and if not the edge
is recorded. Once all potential edges have been checked, the recorded edges are
added to the graph.
At this point, all explicit interdependencies have been graphed. Plugin priority
metadata values must now be propagated down the dependency trees to ensure that
priority edges are added correctly later in the process. To do this:
1. Create a list of all vertices with a global or non-global priority value
greater than zero.
2. Sort the list in order of decreasing priority value.
3. For each vertex, perform a depth-first search, setting priorities at each
vertex visited until equal or larger values are encountered.
Now that the priorities have been propagated, the priority edges can be added.
For each plugin, if it has a global priority value of zero, overrides no records
and loads no archive, skip it, otherwise iterate over all other plugins and:
* If the other plugin's global and non-global priority values equal the
plugin's own values, or if both plugins have a global priority of zero and
have no FormIDs in common, skip the other plugin.
* Otherwise, add an edge from the plugin with lower global priority to the
plugin with higher global priority, if that edge does not cause a cycle. A
cycle is caused if a circular dependency is introduced, for example for two
vertices A and B, A -> B -> A is a cycle.
If the global priorities are equal, compare the non-global priorities
instead.
Plugin overlap edges are then added. Two plugins overlap if they contain the
same FormID, i.e. if they both edit the same record or if one edits a record the
other plugin adds.
-20
View File
@@ -53,24 +53,6 @@ This is the structure that brings all the others together, and forms the main co
dependency when combined in isolation with the third rule, but having all
three rules applied causes a cycle.
.. describe:: priority
``integer``
Modifies plugin position relative to others that change one or more of the same records, but which are otherwise unrelated (ie. neither plugin lists the other as a master, requirement, or in its ``after`` list). Plugins that don't change any of the same records are not compared, unless one of the plugins contains only a header record.
A plugin with a higher ``priority`` value will load after a plugin with a lower ``priority`` value. The value can be anything in the range ``-127`` to ``127`` inclusive, and if unspecified defaults to ``0``.
.. describe:: global_priority
``integer``
Modifies plugin position relative to all unrelated plugins (ie. neither plugin lists the other as a master, requirement, or in its ``after`` list).
A plugin with a higher ``global_priority`` value will load after a plugin with a lower priority value. The value can be anything in the range ``-127`` to ``127`` inclusive, and if unspecified defaults to ``0``.
``global_priority`` takes precedence over ``priority`` when comparing two plugins' priorities: the ``priority`` value is only compared if the two plugins have the same ``global_priority`` value.
.. describe:: after
``file set``
@@ -138,8 +120,6 @@ Key Merge Behaviour (merging B into A)
name Not merged.
enabled Replaced by B's value.
group Replaced by B's value.
priority Replaced by B's value, unless that value is ``0`` and it was not explicitly set.
global_priority Replaced by B's value, unless that value is ``0`` and it was not explicitly set.
after Merged. If B's file set contains an item that is equal to one already present in A's file set, B's item is discarded.
req Merged. If B's file set contains an item that is equal to one already present in A's file set, B's item is discarded.
inc Merged. If B's file set contains an item that is equal to one already present in A's file set, B's item is discarded.
+6 -39
View File
@@ -36,7 +36,6 @@
#include "loot/metadata/location.h"
#include "loot/metadata/message.h"
#include "loot/metadata/plugin_cleaning_data.h"
#include "loot/metadata/priority.h"
#include "loot/metadata/tag.h"
namespace loot {
@@ -64,10 +63,9 @@ public:
* Merge metadata from the given PluginMetadata object into this object.
*
* If an equal metadata object already exists in this PluginMetadata object,
* it is not duplicated. This object's priorities are replaced if the given
* PluginMetadata object's priorities are explicit. This object's enabled
* state is replaced by the given object's state. This object's group is
* replaced by the given object's group if the latter is explicit.
* it is not duplicated. This object's enabled state is replaced by the given
* object's state. This object's group is replaced by the given object's group
* if the latter is explicit.
* @param plugin
* The plugin metadata to merge.
*/
@@ -80,10 +78,7 @@ public:
* The PluginMetadata object to compare against.
* @return A PluginMetadata object containing the metadata in this object that
* is not in the given object. The returned object inherits this
* object's enabled state and group. The returned object also inherits
* this plugin's priorities, unless a priority is equal to the given
* object's priority, in which case the returned object is given
* an implicit zero priority instead.
* object's enabled state and group.
*/
LOOT_API PluginMetadata NewMetadata(const PluginMetadata& plugin) const;
@@ -118,18 +113,6 @@ public:
*/
LOOT_API bool IsGroupExplicit() const;
/**
* Get the plugin's local priority metadata.
* @return The plugin's local priority metadata.
*/
LOOT_API Priority GetLocalPriority() const;
/**
* Get the plugin's global priority metadata.
* @return The plugin's global priority metadata.
*/
LOOT_API Priority GetGlobalPriority() const;
/**
* Get the plugins that the plugin must load after.
* @return The plugins that the plugin must load after.
@@ -201,20 +184,6 @@ public:
*/
LOOT_API void SetGroup(const std::string& group);
/**
* Set the plugin's local priority.
* @param priority
* The value to set.
*/
LOOT_API void SetLocalPriority(const Priority& priority);
/**
* Set the plugin's local priority.
* @param priority
* The value to set.
*/
LOOT_API void SetGlobalPriority(const Priority& priority);
/**
* Set the files that the plugin must load after.
* @param after
@@ -273,8 +242,8 @@ public:
/**
* Check if no plugin metadata is set.
* @return True if the group and local and global priorities are implicit and
* the metadata containers are all empty, false otherwise.
* @return True if the group is implicit and the metadata containers are all
* empty, false otherwise.
*/
LOOT_API bool HasNameOnly() const;
@@ -320,8 +289,6 @@ private:
bool enabled_;
std::string group_;
bool isGroupExplicit_;
Priority localPriority_;
Priority globalPriority_;
std::set<File> loadAfter_;
std::set<File> requirements_;
std::set<File> incompatibilities_;
-118
View File
@@ -1,118 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_METADATA_PRIORITY
#define LOOT_METADATA_PRIORITY
#include <cstdint>
#include "loot/api_decorator.h"
namespace loot {
/**
* Represents the priority of a plugin in the load order.
*
* Plugins have a default implicit priority of zero. Lower priority values cause
* plugins to be loaded earlier, and higher priority values cause plugins to be
* loaded later.
*/
class Priority {
public:
/**
* Construct a Priority object with an implicit value of zero.
* @return A Priority object.
*/
LOOT_API Priority();
// Take an int to prevent literals that are too large for one byte from
// wrapping around to negative values.
/**
* Construct a Priority object with the given priority value.
*
* If the given value is zero, it is marked as being set explicitly. This
* affects how priority metadata values get merged in PluginMetadata objects.
* @param value
* The priority value to set. The valid range of values is -127 to 127
* inclusive, and values passed to the constructor that lie outside
* this range are clamped. The input type is an int to avoid invalid
* values from implicitly wrapping around.
* @return A Priority object.
*/
LOOT_API explicit Priority(const int value);
/**
* Get the stored priority value.
* @return The priority value. While the valid value range fits in 8 bits,
* a short is returned to avoid interpreting the value as a character.
*/
LOOT_API short GetValue() const;
/**
* Check if the priority value is explicit or not.
* @return Returns true if the value is non-zero or was explicitly set to
* zero, and false otherwise.
*/
LOOT_API bool IsExplicit() const;
/**
* Check if this Priority object is less than another.
* @return True if this Priority object's value is less than the given
* Priority object's value.
*/
LOOT_API bool operator<(const Priority& rhs) const;
/**
* Check if this Priority object is greater than another.
* @return True if this Priority object's value is greater than the given
* Priority object's value, false otherwise.
*/
LOOT_API bool operator>(const Priority& rhs) const;
/**
* Check if this Priority object is greater than or equal to another.
* @return True if this Priority object's value is greater than or equal to
* the given Priority object's value, false otherwise.
*/
LOOT_API bool operator>=(const Priority& rhs) const;
/**
* Check if this Priority object is equal to another.
* @return True if this Priority object's value is equal to the given
* Priority object's value, false otherwise.
*/
LOOT_API bool operator==(const Priority& rhs) const;
/**
* Check if this Priority object is greater than a given priority value.
* @return True if this Priority object's value is greater than the given
* value, false otherwise.
*/
LOOT_API bool operator>(const uint8_t rhs) const;
private:
bool isExplicitZeroValue_;
int8_t value_;
};
}
#endif
-2
View File
@@ -108,8 +108,6 @@ PluginMetadata ConditionEvaluator::evaluateAll(
PluginMetadata evaluatedMetadata(pluginMetadata.GetName());
evaluatedMetadata.SetEnabled(pluginMetadata.IsEnabled());
evaluatedMetadata.SetLocalPriority(pluginMetadata.GetLocalPriority());
evaluatedMetadata.SetGlobalPriority(pluginMetadata.GetGlobalPriority());
evaluatedMetadata.SetLocations(pluginMetadata.GetLocations());
if (pluginMetadata.IsGroupExplicit()) {
+6 -27
View File
@@ -40,9 +40,9 @@ using std::set;
using std::vector;
namespace loot {
PluginMetadata::PluginMetadata() :
enabled_(true),
group_("default"),
PluginMetadata::PluginMetadata() :
enabled_(true),
group_("default"),
isGroupExplicit_(false) {}
PluginMetadata::PluginMetadata(const std::string& n) :
@@ -64,8 +64,8 @@ void PluginMetadata::MergeMetadata(const PluginMetadata& plugin) {
if (plugin.HasNameOnly())
return;
// For 'enabled' and 'priority' metadata, use the given plugin's values,
// but if the 'priority' user value is not explicit, ignore it.
// For 'enabled' and 'group' metadata, use the given plugin's values,
// but if the 'group' value is not explicit, ignore it.
enabled_ = plugin.IsEnabled();
if (plugin.IsGroupExplicit()) {
@@ -73,14 +73,6 @@ void PluginMetadata::MergeMetadata(const PluginMetadata& plugin) {
isGroupExplicit_ = true;
}
if (plugin.localPriority_.IsExplicit()) {
SetLocalPriority(plugin.localPriority_);
}
if (plugin.globalPriority_.IsExplicit()) {
SetGlobalPriority(plugin.globalPriority_);
}
// Merge the following. If any files in the source already exist in the
// destination, they will be skipped. Files have display strings and
// condition strings which aren't considered when comparing them, so
@@ -202,10 +194,6 @@ bool PluginMetadata::IsGroupExplicit() const {
return isGroupExplicit_;
}
Priority PluginMetadata::GetLocalPriority() const { return localPriority_; }
Priority PluginMetadata::GetGlobalPriority() const { return globalPriority_; }
std::set<File> PluginMetadata::GetLoadAfterFiles() const { return loadAfter_; }
std::set<File> PluginMetadata::GetRequirements() const { return requirements_; }
@@ -248,14 +236,6 @@ void PluginMetadata::SetGroup(const std::string& group) {
isGroupExplicit_ = true;
}
void PluginMetadata::SetLocalPriority(const Priority& priority) {
localPriority_ = priority;
}
void PluginMetadata::SetGlobalPriority(const Priority& priority) {
globalPriority_ = priority;
}
void PluginMetadata::SetLoadAfterFiles(const std::set<File>& l) {
loadAfter_ = l;
}
@@ -288,8 +268,7 @@ void PluginMetadata::SetLocations(const std::set<Location>& locations) {
}
bool PluginMetadata::HasNameOnly() const {
return !IsGroupExplicit() && !localPriority_.IsExplicit() &&
!globalPriority_.IsExplicit() &&
return !IsGroupExplicit() &&
loadAfter_.empty() && requirements_.empty() &&
incompatibilities_.empty() && messages_.empty() && tags_.empty() &&
dirtyInfo_.empty() && cleanInfo_.empty() && locations_.empty();
-63
View File
@@ -1,63 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#include "loot/metadata/priority.h"
namespace loot {
Priority::Priority() : value_(0), isExplicitZeroValue_(false) {}
Priority::Priority(const int value) : isExplicitZeroValue_(true) {
if (value > 127) {
value_ = 127;
} else if (value < -127) {
value_ = -127;
} else {
value_ = value;
}
}
short Priority::GetValue() const { return value_; }
bool Priority::IsExplicit() const {
return value_ != 0 || isExplicitZeroValue_;
}
bool Priority::operator<(const Priority& rhs) const {
return value_ < rhs.value_;
}
bool Priority::operator>(const Priority& rhs) const {
return value_ > rhs.value_;
}
bool Priority::operator>=(const Priority& rhs) const {
return value_ >= rhs.value_;
}
bool Priority::operator==(const Priority& rhs) const {
return value_ == rhs.value_;
}
bool Priority::operator>(const uint8_t rhs) const { return value_ > rhs; }
}
-25
View File
@@ -56,12 +56,6 @@ struct convert<loot::PluginMetadata> {
if (rhs.IsGroupExplicit())
node["group"] = rhs.GetGroup();
if (rhs.GetLocalPriority().IsExplicit())
node["priority"] = rhs.GetLocalPriority().GetValue();
if (rhs.GetGlobalPriority().IsExplicit())
node["global_priority"] = rhs.GetGlobalPriority().GetValue();
if (!rhs.GetLoadAfterFiles().empty())
node["after"] = rhs.GetLoadAfterFiles();
if (!rhs.GetRequirements().empty())
@@ -112,16 +106,6 @@ struct convert<loot::PluginMetadata> {
if (node["group"])
rhs.SetGroup(node["group"].as<std::string>());
// Read priority values as int to prevent values that are too large from
// being converted to -128.
if (node["priority"]) {
rhs.SetLocalPriority(loot::Priority(node["priority"].as<int>()));
}
if (node["global_priority"]) {
rhs.SetGlobalPriority(loot::Priority(node["global_priority"].as<int>()));
}
if (node["after"])
rhs.SetLoadAfterFiles(node["after"].as<std::set<loot::File>>());
if (node["req"])
@@ -170,15 +154,6 @@ inline Emitter& operator<<(Emitter& out, const loot::PluginMetadata& rhs) {
if (rhs.IsGroupExplicit())
out << Key << "group" << Value << YAML::SingleQuoted << rhs.GetGroup();
if (rhs.GetLocalPriority().IsExplicit()) {
out << Key << "priority" << Value << rhs.GetLocalPriority().GetValue();
}
if (rhs.GetGlobalPriority().IsExplicit()) {
out << Key << "global_priority" << Value
<< rhs.GetGlobalPriority().GetValue();
}
if (!rhs.GetLoadAfterFiles().empty())
out << Key << "after" << Value << rhs.GetLoadAfterFiles();
+1 -153
View File
@@ -134,13 +134,6 @@ std::vector<std::string> PluginSorter::Sort(Game& game) {
AddGroupEdges();
PropagatePriorities();
if (logger_) {
logger_->debug("Adding priority edges.");
}
AddPriorityEdges();
if (logger_) {
logger_->debug("Adding overlap edges.");
}
@@ -318,98 +311,6 @@ bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex,
return false;
}
void PluginSorter::PropagatePriorities() {
/* If a plugin has a priority value > 0, that value should be
inherited by all plugins that have edges coming from that
plugin, ie. those that load after it, unless the plugin being
compared itself has a larger value. */
// Find all vertices with priorities > 0.
std::vector<vertex_t> positivePriorityVertices;
vertex_it vit, vitend;
tie(vit, vitend) = boost::vertices(graph_);
std::copy_if(vit,
vitend,
std::back_inserter(positivePriorityVertices),
[&](const vertex_t& vertex) {
return graph_[vertex].GetLocalPriority() > 0 ||
graph_[vertex].GetGlobalPriority() > 0;
});
// To reduce the number of priorities that will need setting,
// sort the vertices in order of decreasing priority.
std::sort(begin(positivePriorityVertices),
end(positivePriorityVertices),
[&](const vertex_t& lhs, const vertex_t& rhs) {
return graph_[lhs].GetLocalPriority() >
graph_[rhs].GetLocalPriority() ||
graph_[lhs].GetGlobalPriority() >
graph_[rhs].GetGlobalPriority();
});
// Create a color map.
std::vector<boost::default_color_type> colorVec(num_vertices(graph_));
boost::iterator_property_map<boost::default_color_type*, vertex_map_t>
colorMap(&colorVec.front(), vertexIndexMap_);
// Now loop over the vertices. For each one, do a depth-first
// search, setting priorities until an equal or larger value is
// encountered.
for (const vertex_t& vertex : positivePriorityVertices) {
if (logger_) {
logger_->trace(
"Doing DFS for {} which has local priority {} and global priority {}",
graph_[vertex].GetName(),
graph_[vertex].GetLocalPriority().GetValue(),
graph_[vertex].GetGlobalPriority().GetValue());
}
boost::dfs_visitor<> visitor;
boost::depth_first_visit(
graph_,
vertex,
visitor,
colorMap,
[&](const vertex_t& currentVertex, const PluginGraph& graph) {
// depth_first_search takes a const graph, so cast it if modifying a
// vertex.
if (graph[currentVertex].GetLocalPriority() <
graph[vertex].GetLocalPriority()) {
if (logger_) {
logger_->trace("Overriding local priority for {} from {} to {}",
graph[currentVertex].GetName(),
graph[currentVertex].GetLocalPriority().GetValue(),
graph[vertex].GetLocalPriority().GetValue());
}
const_cast<PluginGraph&>(graph)[currentVertex].SetLocalPriority(
graph[vertex].GetLocalPriority());
return false;
}
if (graph[currentVertex].GetGlobalPriority() <
graph[vertex].GetGlobalPriority()) {
if (logger_) {
logger_->trace(
"Overriding global priority for {} from {} to {}",
graph[currentVertex].GetName(),
graph[currentVertex].GetGlobalPriority().GetValue(),
graph[vertex].GetGlobalPriority().GetValue());
}
const_cast<PluginGraph&>(graph)[currentVertex].SetGlobalPriority(
graph[vertex].GetGlobalPriority());
return false;
}
return currentVertex != vertex &&
graph[currentVertex].GetLocalPriority() >=
graph[vertex].GetLocalPriority() &&
graph[currentVertex].GetGlobalPriority() >=
graph[vertex].GetGlobalPriority();
});
}
}
void PluginSorter::AddEdge(const vertex_t& fromVertex,
const vertex_t& toVertex) {
if (!boost::edge(fromVertex, toVertex, graph_).second) {
@@ -424,8 +325,7 @@ void PluginSorter::AddEdge(const vertex_t& fromVertex,
}
void PluginSorter::AddSpecificEdges() {
// Add edges for all relationships that aren't overlaps or priority
// differences.
// Add edges for all relationships that aren't overlaps.
vertex_it vit, vitend;
for (tie(vit, vitend) = boost::vertices(graph_); vit != vitend; ++vit) {
if (logger_) {
@@ -514,58 +414,6 @@ void PluginSorter::AddGroupEdges() {
}
}
void PluginSorter::AddPriorityEdges() {
for (const auto& vertex :
boost::make_iterator_range(boost::vertices(graph_))) {
if (logger_) {
logger_->trace("Adding priority difference edges to vertex for \"{}\".",
graph_[vertex].GetName());
}
// If the plugin has a global priority of zero and doesn't load
// an archive and has no override records, skip it. Plugins without
// override records can only conflict with plugins that override
// the records they add, so any edge necessary will be added when
// evaluating that plugin.
if (graph_[vertex].GetGlobalPriority().GetValue() == 0 &&
graph_[vertex].NumOverrideFormIDs() == 0 &&
!graph_[vertex].LoadsArchive()) {
continue;
}
for (const auto& otherVertex :
boost::make_iterator_range(boost::vertices(graph_))) {
// If the plugins have equal priority, or have non-global
// priorities but don't conflict, don't add a priority edge.
if ((graph_[vertex].GetLocalPriority() ==
graph_[otherVertex].GetLocalPriority() &&
graph_[vertex].GetGlobalPriority() ==
graph_[otherVertex].GetGlobalPriority()) ||
(graph_[vertex].GetGlobalPriority().GetValue() == 0 &&
graph_[otherVertex].GetGlobalPriority().GetValue() == 0 &&
!graph_[vertex].DoFormIDsOverlap(graph_[otherVertex]))) {
continue;
}
vertex_t toVertex, fromVertex;
if (graph_[vertex].GetGlobalPriority() <
graph_[otherVertex].GetGlobalPriority() ||
(graph_[vertex].GetGlobalPriority() ==
graph_[otherVertex].GetGlobalPriority() &&
graph_[vertex].GetLocalPriority() <
graph_[otherVertex].GetLocalPriority())) {
fromVertex = vertex;
toVertex = otherVertex;
} else {
fromVertex = otherVertex;
toVertex = vertex;
}
if (!EdgeCreatesCycle(fromVertex, toVertex))
AddEdge(fromVertex, toVertex);
}
}
}
void PluginSorter::AddOverlapEdges() {
for (const auto& vertex :
boost::make_iterator_range(boost::vertices(graph_))) {
-3
View File
@@ -57,12 +57,9 @@ private:
int ComparePlugins(const std::string& plugin1,
const std::string& plugin2) const;
void PropagatePriorities();
void AddPluginVertices(Game& game);
void AddSpecificEdges();
void AddGroupEdges();
void AddPriorityEdges();
void AddOverlapEdges();
void AddTieBreakEdges();
-4
View File
@@ -43,13 +43,9 @@ public:
std::unordered_set<std::string> GetAfterGroupPlugins() const;
void SetAfterGroupPlugins(std::unordered_set<std::string> plugins);
using PluginMetadata::GetGlobalPriority;
using PluginMetadata::GetGroup;
using PluginMetadata::GetLoadAfterFiles;
using PluginMetadata::GetLocalPriority;
using PluginMetadata::GetRequirements;
using PluginMetadata::SetGlobalPriority;
using PluginMetadata::SetLocalPriority;
private:
const Plugin& plugin_;
-1
View File
@@ -42,7 +42,6 @@
#include "tests/api/internals/metadata/message_test.h"
#include "tests/api/internals/metadata/plugin_cleaning_data_test.h"
#include "tests/api/internals/metadata/plugin_metadata_test.h"
#include "tests/api/internals/metadata/priority_test.h"
#include "tests/api/internals/metadata/tag_test.h"
#include "tests/api/internals/metadata_list_test.h"
#include "tests/api/internals/sorting/group_sort_test.h"
@@ -133,7 +133,7 @@ TEST_P(PluginMetadataTest,
PluginMetadata plugin2;
plugin2.SetEnabled(false);
plugin2.SetLocalPriority(Priority(5));
plugin2.SetGroup("group1");
ASSERT_FALSE(plugin2.HasNameOnly());
plugin1.MergeMetadata(plugin2);
@@ -161,78 +161,6 @@ TEST_P(PluginMetadataTest, mergeMetadataShouldNotUseMergedGroupIfItIsImplicit) {
EXPECT_EQ("group1", plugin1.GetGroup());
}
TEST_P(PluginMetadataTest,
mergeMetadataShouldUseMergedNonZeroLocalPriorityValue) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetLocalPriority(Priority(5));
plugin2.SetLocalPriority(Priority(3));
plugin1.MergeMetadata(plugin2);
EXPECT_EQ(3, plugin1.GetLocalPriority().GetValue());
}
TEST_P(PluginMetadataTest,
mergeMetadataShouldUseMergedNonZeroGlobalPriorityValue) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetGlobalPriority(Priority(5));
plugin2.SetGlobalPriority(Priority(3));
plugin1.MergeMetadata(plugin2);
EXPECT_EQ(3, plugin1.GetGlobalPriority().GetValue());
}
TEST_P(PluginMetadataTest,
mergeMetadataShouldNotUseImplicitZeroLocalPriorityValue) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetLocalPriority(Priority(5));
plugin1.MergeMetadata(plugin2);
EXPECT_EQ(5, plugin1.GetLocalPriority().GetValue());
}
TEST_P(PluginMetadataTest,
mergeMetadataShouldNotUseImplicitZeroGlobalPriorityValue) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetGlobalPriority(Priority(5));
plugin1.MergeMetadata(plugin2);
EXPECT_EQ(5, plugin1.GetGlobalPriority().GetValue());
}
TEST_P(PluginMetadataTest,
mergeMetadataShouldMergeAnExplicitLocalPriorityValueOfZero) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetLocalPriority(Priority(5));
plugin2.SetLocalPriority(Priority(0));
plugin1.MergeMetadata(plugin2);
EXPECT_EQ(0, plugin1.GetLocalPriority().GetValue());
EXPECT_TRUE(plugin1.GetLocalPriority().IsExplicit());
}
TEST_P(PluginMetadataTest,
mergeMetadataShouldMergeAnExplicitGlobalPriorityValueOfZero) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetGlobalPriority(Priority(5));
plugin2.SetGlobalPriority(Priority(0));
plugin1.MergeMetadata(plugin2);
EXPECT_EQ(0, plugin1.GetGlobalPriority().GetValue());
EXPECT_TRUE(plugin1.GetGlobalPriority().IsExplicit());
}
TEST_P(PluginMetadataTest, mergeMetadataShouldMergeLoadAfterData) {
PluginMetadata plugin1;
PluginMetadata plugin2;
@@ -362,26 +290,6 @@ TEST_P(PluginMetadataTest, newMetadataShouldUseSourcePluginEnabledState) {
EXPECT_FALSE(newMetadata.IsEnabled());
}
TEST_P(PluginMetadataTest, newMetadataShouldUseSourcePluginLocalPriority) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetLocalPriority(Priority(5));
PluginMetadata newMetadata = plugin1.NewMetadata(plugin2);
EXPECT_EQ(5, newMetadata.GetLocalPriority().GetValue());
}
TEST_P(PluginMetadataTest, newMetadataShouldUseSourcePluginGlobalPriority) {
PluginMetadata plugin1;
PluginMetadata plugin2;
plugin1.SetGlobalPriority(Priority(5));
PluginMetadata newMetadata = plugin1.NewMetadata(plugin2);
EXPECT_EQ(5, newMetadata.GetGlobalPriority().GetValue());
}
TEST_P(PluginMetadataTest,
newMetadataShouldOutputLoadAfterDataThatAreNotCommonToBothInputPlugins) {
PluginMetadata plugin1;
@@ -560,22 +468,6 @@ TEST_P(PluginMetadataTest,
EXPECT_FALSE(plugin.HasNameOnly());
}
TEST_P(PluginMetadataTest,
hasNameOnlyShouldBeFalseIfTheLocalPriorityIsExplicit) {
PluginMetadata plugin(blankEsp);
plugin.SetLocalPriority(Priority(0));
EXPECT_FALSE(plugin.HasNameOnly());
}
TEST_P(PluginMetadataTest,
hasNameOnlyShouldBeFalseIfTheGlobalPriorityIsExplicit) {
PluginMetadata plugin(blankEsp);
plugin.SetGlobalPriority(Priority(0));
EXPECT_FALSE(plugin.HasNameOnly());
}
TEST_P(PluginMetadataTest, hasNameOnlyShouldBeFalseIfLoadAfterMetadataExists) {
PluginMetadata plugin(blankEsp);
plugin.SetLoadAfterFiles({File(blankEsm)});
@@ -694,7 +586,7 @@ TEST_P(PluginMetadataTest,
emittingAsYamlShouldOutputAPluginOmittingAnImplicitGroup) {
PluginMetadata plugin(blankEsm);
plugin.SetLoadAfterFiles({ File(blankEsm) });
YAML::Emitter emitter;
emitter << plugin;
@@ -719,39 +611,11 @@ TEST_P(PluginMetadataTest,
emitter.c_str());
}
TEST_P(PluginMetadataTest,
emittingAsYamlShouldOutputAPluginWithAnExplicitLocalPriorityCorrectly) {
PluginMetadata plugin(blankEsm);
plugin.SetLocalPriority(Priority(0));
YAML::Emitter emitter;
emitter << plugin;
EXPECT_STREQ(
"name: 'Blank.esm'\n"
"priority: 0",
emitter.c_str());
}
TEST_P(PluginMetadataTest,
emittingAsYamlShouldOutputAPluginWithAnExplicitGlobalPriorityCorrectly) {
PluginMetadata plugin(blankEsm);
plugin.SetGlobalPriority(Priority(0));
YAML::Emitter emitter;
emitter << plugin;
EXPECT_STREQ(
"name: 'Blank.esm'\n"
"global_priority: 0",
emitter.c_str());
}
TEST_P(
PluginMetadataTest,
emittingAsYamlShouldOutputAPluginThatIsDisabledAndIsNotNameOnlyCorrectly) {
PluginMetadata plugin(blankEsm);
plugin.SetGlobalPriority(Priority(0));
plugin.SetGroup("group1");
plugin.SetEnabled(false);
YAML::Emitter emitter;
@@ -760,7 +624,7 @@ TEST_P(
EXPECT_STREQ(
"name: 'Blank.esm'\n"
"enabled: false\n"
"global_priority: 0",
"group: 'group1'",
emitter.c_str());
}
@@ -908,7 +772,6 @@ TEST_P(PluginMetadataTest, encodingAsYamlShouldOmitAllUnsetFields) {
EXPECT_EQ(plugin.GetName(), node["name"].as<std::string>());
EXPECT_FALSE(node["enabled"]);
EXPECT_FALSE(node["priority"]);
EXPECT_FALSE(node["after"]);
EXPECT_FALSE(node["req"]);
EXPECT_FALSE(node["inc"]);
@@ -919,44 +782,6 @@ TEST_P(PluginMetadataTest, encodingAsYamlShouldOmitAllUnsetFields) {
EXPECT_FALSE(node["url"]);
}
TEST_P(PluginMetadataTest,
encodingAsYamlShouldSetPriorityFieldIfLocalPriorityIsExplicit) {
PluginMetadata plugin(blankEsp);
plugin.SetLocalPriority(Priority(0));
YAML::Node node;
node = plugin;
EXPECT_EQ(0, node["priority"].as<short>());
}
TEST_P(PluginMetadataTest,
encodingAsYamlShouldSetGlobalPriorityFieldIfGlobalPriorityIsExplicit) {
PluginMetadata plugin(blankEsp);
plugin.SetGlobalPriority(Priority(0));
YAML::Node node;
node = plugin;
EXPECT_EQ(0, node["global_priority"].as<short>());
}
TEST_P(PluginMetadataTest,
encodingAsYamlShouldNotSetPriorityFieldIfLocalPriorityIsImplicit) {
PluginMetadata plugin(blankEsp);
YAML::Node node;
node = plugin;
EXPECT_FALSE(node["priority"]);
}
TEST_P(PluginMetadataTest,
encodingAsYamlShouldNotSetPriorityFieldIfGlobalPriorityIsImplicit) {
PluginMetadata plugin(blankEsp);
YAML::Node node;
node = plugin;
EXPECT_FALSE(node["global_priority"]);
}
TEST_P(PluginMetadataTest, encodingAsYamlShouldSetEnabledFieldIfItIsFalse) {
PluginMetadata plugin(blankEsp);
plugin.SetEnabled(false);
@@ -1042,24 +867,10 @@ TEST_P(PluginMetadataTest, encodingAsYamlShouldSetUrlFieldIfLocationsExist) {
EXPECT_EQ(plugin.GetLocations(), node["url"].as<std::set<Location>>());
}
TEST_P(PluginMetadataTest,
decodingFromYamlShouldSetDefaultPriorityValuesIfNoneAreSpecified) {
YAML::Node node = YAML::Load("name: " + blankEsp);
PluginMetadata plugin = node.as<PluginMetadata>();
EXPECT_EQ(blankEsp, plugin.GetName());
EXPECT_EQ(0, plugin.GetLocalPriority().GetValue());
EXPECT_FALSE(plugin.GetLocalPriority().IsExplicit());
EXPECT_EQ(0, plugin.GetGlobalPriority().GetValue());
EXPECT_FALSE(plugin.GetGlobalPriority().IsExplicit());
}
TEST_P(PluginMetadataTest, decodingFromYamlShouldStoreAllGivenData) {
YAML::Node node = YAML::Load(
"name: 'Blank.esp'\n"
"enabled: false\n"
"priority: 5\n"
"global_priority: 3\n"
"after:\n"
" - 'Blank.esm'\n"
"req:\n"
@@ -1084,8 +895,6 @@ TEST_P(PluginMetadataTest, decodingFromYamlShouldStoreAllGivenData) {
PluginMetadata plugin = node.as<PluginMetadata>();
EXPECT_EQ("Blank.esp", plugin.GetName());
EXPECT_EQ(5, plugin.GetLocalPriority().GetValue());
EXPECT_EQ(3, plugin.GetGlobalPriority().GetValue());
EXPECT_EQ(std::set<File>({File("Blank.esm")}), plugin.GetLoadAfterFiles());
EXPECT_EQ(std::set<File>({File("Blank.esm")}), plugin.GetRequirements());
EXPECT_EQ(std::set<File>({File("Blank.esm")}), plugin.GetIncompatibilities());
@@ -1,112 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TESTS_API_INTERNALS_METADATA_PRIORITY_TEST
#define LOOT_TESTS_API_INTERNALS_METADATA_PRIORITY_TEST
#include "loot/metadata/priority.h"
#include <gtest/gtest.h>
namespace loot {
namespace test {
TEST(Priority, defaultConstructorShouldInitialiseAnImplicitZeroPriority) {
Priority priority;
EXPECT_EQ(0, priority.GetValue());
EXPECT_FALSE(priority.IsExplicit());
}
TEST(Priority, valueConstructorShouldInitialseAnExplicitValue) {
Priority priority(0);
EXPECT_EQ(0, priority.GetValue());
EXPECT_TRUE(priority.IsExplicit());
priority = Priority(5);
EXPECT_EQ(5, priority.GetValue());
EXPECT_TRUE(priority.IsExplicit());
}
TEST(Priority, valueConstructorTruncatesOutOfRangeValues) {
EXPECT_EQ(127, Priority(127).GetValue());
EXPECT_EQ(127, Priority(128).GetValue());
EXPECT_EQ(-127, Priority(-127).GetValue());
EXPECT_EQ(-127, Priority(-128).GetValue());
}
TEST(Priority, lessThanOperatorShouldCompareValues) {
Priority priority1(1);
Priority priority2(2);
EXPECT_TRUE(priority1 < priority2);
EXPECT_FALSE(priority2 < priority1);
EXPECT_FALSE(priority1 < priority1);
}
TEST(Priority, greaterThanOperatorShouldCompareValues) {
Priority priority1(1);
Priority priority2(2);
EXPECT_FALSE(priority1 > priority2);
EXPECT_TRUE(priority2 > priority1);
EXPECT_FALSE(priority1 > priority1);
}
TEST(Priority, greaterThanOrEqualToOperatorShouldCompareValues) {
Priority priority1(1);
Priority priority2(2);
EXPECT_FALSE(priority1 >= priority2);
EXPECT_TRUE(priority2 >= priority1);
EXPECT_TRUE(priority1 >= priority1);
}
TEST(Priority, equalityOperatorShouldCompareValues) {
Priority priority1(1);
Priority priority2(2);
EXPECT_FALSE(priority1 == priority2);
EXPECT_FALSE(priority2 == priority1);
EXPECT_TRUE(priority1 == priority1);
}
TEST(Priority, greaterThanUint8OperatorShouldCompareValue) {
Priority priority1(1);
Priority priority2(3);
uint8_t value = 2;
EXPECT_FALSE(priority1 > value);
EXPECT_TRUE(priority2 > value);
}
}
}
#endif
+4 -4
View File
@@ -285,13 +285,13 @@ TEST_P(MetadataListTest, addPluginShouldStoreGivenSpecificPluginMetadata) {
metadataList.FindPlugin(PluginMetadata(blankDifferentEsm)).HasNameOnly());
PluginMetadata plugin(blankDifferentEsm);
plugin.SetLocalPriority(Priority(100));
plugin.SetGroup("group1");
metadataList.AddPlugin(plugin);
plugin = metadataList.FindPlugin(plugin);
EXPECT_EQ(blankDifferentEsm, plugin.GetName());
EXPECT_EQ(100, plugin.GetLocalPriority().GetValue());
EXPECT_EQ("group1", plugin.GetGroup());
}
TEST_P(MetadataListTest, addPluginShouldStoreGivenRegexPluginMetadata) {
@@ -299,12 +299,12 @@ TEST_P(MetadataListTest, addPluginShouldStoreGivenRegexPluginMetadata) {
ASSERT_NO_THROW(metadataList.Load(metadataPath));
PluginMetadata plugin(".+Dependent\\.esp");
plugin.SetLocalPriority(Priority(-10));
plugin.SetGroup("group1");
metadataList.AddPlugin(plugin);
plugin = metadataList.FindPlugin(PluginMetadata(blankPluginDependentEsp));
EXPECT_EQ(-10, plugin.GetLocalPriority().GetValue());
EXPECT_EQ("group1", plugin.GetGroup());
}
TEST_P(MetadataListTest, addPluginShouldThrowIfAMatchingPluginAlreadyExists) {
@@ -266,91 +266,6 @@ TEST_P(PluginSorterTest, sortingShouldIgnoreAGroupEdgeIfItWouldCauseACycle) {
EXPECT_EQ(expectedSortedOrder, sorted);
}
TEST_P(PluginSorterTest, sortingShouldEvaluateRelativeGlobalPriorities) {
ASSERT_NO_THROW(loadInstalledPlugins(game_, false));
PluginMetadata plugin(blankDifferentMasterDependentEsp);
plugin.SetGlobalPriority(Priority(-100));
game_.GetDatabase()->SetPluginUserMetadata(plugin);
PluginSorter ps;
std::vector<std::string> expectedSortedOrder({
masterFile,
blankEsm,
blankDifferentEsm,
blankMasterDependentEsm,
blankDifferentMasterDependentEsm,
blankDifferentMasterDependentEsp,
blankEsp,
blankDifferentEsp,
blankMasterDependentEsp,
blankPluginDependentEsp,
blankDifferentPluginDependentEsp,
});
if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) {
expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl);
}
std::vector<std::string> sorted = ps.Sort(game_);
EXPECT_EQ(expectedSortedOrder, sorted);
}
TEST_P(
PluginSorterTest,
sortingWithGlobalPrioritiesShouldInheritRecursivelyRegardlessOfEvaluationOrder) {
ASSERT_NO_THROW(loadInstalledPlugins(game_, false));
// Set Blank.esp's priority.
PluginMetadata plugin(blankEsp);
plugin.SetGlobalPriority(Priority(2));
game_.GetDatabase()->SetPluginUserMetadata(plugin);
// Load Blank - Master Dependent.esp after Blank.esp so that it
// inherits Blank.esp's priority.
plugin = PluginMetadata(blankMasterDependentEsp);
plugin.SetLoadAfterFiles({
File(blankEsp),
});
game_.GetDatabase()->SetPluginUserMetadata(plugin);
// Load Blank - Different.esp after Blank - Master Dependent.esp, so
// that it inherits its inherited priority.
plugin = PluginMetadata(blankDifferentEsp);
plugin.SetLoadAfterFiles({
File(blankMasterDependentEsp),
});
game_.GetDatabase()->SetPluginUserMetadata(plugin);
// Set Blank - Different Master Dependent.esp to have a higher priority
// than 0 but lower than Blank.esp. Need to also make it a global priority
// because it doesn't otherwise conflict with the other plugins.
plugin = PluginMetadata(blankDifferentMasterDependentEsp);
plugin.SetGlobalPriority(Priority(1));
game_.GetDatabase()->SetPluginUserMetadata(plugin);
PluginSorter ps;
std::vector<std::string> expectedSortedOrder({
masterFile,
blankEsm,
blankDifferentEsm,
blankMasterDependentEsm,
blankDifferentMasterDependentEsm,
blankDifferentMasterDependentEsp,
blankEsp,
blankMasterDependentEsp,
blankDifferentEsp,
blankPluginDependentEsp,
blankDifferentPluginDependentEsp,
});
if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) {
expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl);
}
std::vector<std::string> sorted = ps.Sort(game_);
EXPECT_EQ(expectedSortedOrder, sorted);
}
TEST_P(PluginSorterTest,
sortingShouldUseLoadAfterMetadataWhenDecidingRelativePluginPositions) {
ASSERT_NO_THROW(loadInstalledPlugins(game_, false));