mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
@@ -241,6 +241,18 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
|
||||
data.crc = parseInt(data.crc, 16);
|
||||
});
|
||||
plugin.userlist.dirty = rowsData;
|
||||
} else if (tables[j].id == 'locations') {
|
||||
rowsData.forEach(function(data){
|
||||
/* User metadata can only specify one version, but it should be a list. */
|
||||
if (data.ver.length > 0) {
|
||||
data.ver = [
|
||||
data.ver
|
||||
];
|
||||
} else {
|
||||
delete data.ver;
|
||||
}
|
||||
});
|
||||
plugin.userlist.url = rowsData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,6 +490,28 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
} else if (tables[j].id == 'locations') {
|
||||
|
||||
if (loot.game.plugins[i].masterlist && loot.game.plugins[i].masterlist.url) {
|
||||
loot.game.plugins[i].masterlist.url.forEach(function(location) {
|
||||
var temp = location;
|
||||
if (temp.ver) {
|
||||
temp.ver = temp.ver[0];
|
||||
}
|
||||
var row = tables[j].addRow(temp);
|
||||
tables[j].setReadOnly(row);
|
||||
});
|
||||
}
|
||||
if (loot.game.plugins[i].userlist && loot.game.plugins[i].userlist.url) {
|
||||
loot.game.plugins[i].userlist.url.forEach(function(location) {
|
||||
var temp = location;
|
||||
if (temp.ver) {
|
||||
temp.ver = temp.ver[0];
|
||||
}
|
||||
tables[j].addRow(temp);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -909,7 +943,7 @@ var EditableTableProto = Object.create(HTMLTableElement.prototype, {
|
||||
/* Data is an object with keys that match element class names. */
|
||||
for (var key in tableData) {
|
||||
var elems = row.getElementsByClassName(key);
|
||||
if (elems.length == 1) {
|
||||
if (tableData[key] != undefined && elems.length == 1) {
|
||||
elems[0].value = tableData[key];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
<span data-for="message">Messages</span>
|
||||
<span data-for="tags">Bash Tags</span>
|
||||
<span data-for="dirty">Dirty Info</span>
|
||||
<span data-for="locations">Locations</span>
|
||||
|
||||
<table is="editable-table" id="loadAfter" data-template="fileRow">
|
||||
<thead>
|
||||
@@ -276,6 +277,15 @@
|
||||
<tr><td colspan="4">Add new row...</td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table is="editable-table" id="locations" class="hidden" data-template="locationRow">
|
||||
<thead>
|
||||
<tr><th>URL</th><th>Version</th><th></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Location rows go here. -->
|
||||
<tr><td colspan="3">Add new row...</td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr>
|
||||
<div id="buttons">
|
||||
@@ -373,6 +383,12 @@
|
||||
<td><input class="util" type="text" required>
|
||||
<td class="fa fa-trash-o fa-fw">
|
||||
</template>
|
||||
<template id="locationRow">
|
||||
<tr>
|
||||
<td><input class="link" type="text" required>
|
||||
<td><input class="ver" type="text">
|
||||
<td class="fa fa-trash-o fa-fw">
|
||||
</template>
|
||||
<template id="gameRow">
|
||||
<tr>
|
||||
<td><input class="name" type="text" required>
|
||||
|
||||
@@ -143,6 +143,18 @@ namespace YAML {
|
||||
return out;
|
||||
}
|
||||
|
||||
Emitter& operator << (Emitter& out, const loot::Location& rhs) {
|
||||
if (rhs.Versions().empty())
|
||||
out << rhs.URL();
|
||||
else {
|
||||
out << BeginMap
|
||||
<< Key << "link" << Value << rhs.URL()
|
||||
<< Key << "ver" << Value << rhs.Versions()
|
||||
<< EndMap;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Emitter& operator << (Emitter& out, const loot::Plugin& rhs) {
|
||||
if (!rhs.HasNameOnly()) {
|
||||
out << BeginMap
|
||||
@@ -172,6 +184,9 @@ namespace YAML {
|
||||
if (!rhs.DirtyInfo().empty())
|
||||
out << Key << "dirty" << Value << rhs.DirtyInfo();
|
||||
|
||||
if (!rhs.Locations().empty())
|
||||
out << Key << "url" << Value << rhs.Locations();
|
||||
|
||||
out << EndMap;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
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_GENERATORS__
|
||||
#define __LOOT_GENERATORS__
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace YAML {
|
||||
template<class T, class Compare>
|
||||
Emitter& operator << (Emitter& out, const std::set<T, Compare>& rhs) {
|
||||
out << BeginSeq;
|
||||
for (const auto &element: rhs) {
|
||||
for (const auto &element : rhs) {
|
||||
out << element;
|
||||
}
|
||||
out << EndSeq;
|
||||
@@ -68,6 +68,8 @@ namespace YAML {
|
||||
|
||||
Emitter& operator << (Emitter& out, const loot::Tag& rhs);
|
||||
|
||||
Emitter& operator << (Emitter& out, const loot::Location& rhs);
|
||||
|
||||
Emitter& operator << (Emitter& out, const loot::Plugin& rhs);
|
||||
}
|
||||
|
||||
|
||||
@@ -330,6 +330,24 @@ namespace loot {
|
||||
return _name;
|
||||
}
|
||||
|
||||
Location::Location() {}
|
||||
|
||||
Location::Location(const std::string& url) : _url(url) {}
|
||||
|
||||
Location::Location(const std::string& url, const std::vector<std::string>& versions) : _url(url), _versions(versions) {}
|
||||
|
||||
bool Location::operator < (const Location& rhs) const {
|
||||
return boost::ilexicographical_compare(_url, rhs.URL());
|
||||
}
|
||||
|
||||
std::string Location::URL() const {
|
||||
return _url;
|
||||
}
|
||||
|
||||
std::vector<std::string> Location::Versions() const {
|
||||
return _versions;
|
||||
}
|
||||
|
||||
Plugin::Plugin() : enabled(true), _isPriorityExplicit(false), priority(0), isMaster(false), crc(0), numOverrideRecords(0) {}
|
||||
Plugin::Plugin(const std::string& n) : name(n), enabled(true), _isPriorityExplicit(false), priority(0), isMaster(false), crc(0), numOverrideRecords(0) {
|
||||
//If the name passed ends in '.ghost', that should be trimmed.
|
||||
@@ -465,6 +483,9 @@ namespace loot {
|
||||
set<PluginDirtyInfo> dirtyInfo = plugin.DirtyInfo();
|
||||
_dirtyInfo.insert(dirtyInfo.begin(), dirtyInfo.end());
|
||||
|
||||
set<Location> locations = plugin.Locations();
|
||||
_locations.insert(locations.begin(), locations.end());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -511,6 +532,11 @@ namespace loot {
|
||||
set_symmetric_difference(_dirtyInfo.begin(), _dirtyInfo.end(), dirtyInfo.begin(), dirtyInfo.end(), inserter(dirtDiff, dirtDiff.begin()));
|
||||
p.DirtyInfo(dirtDiff);
|
||||
|
||||
set<Location> locations = plugin.Locations();
|
||||
set<Location> locationsDiff;
|
||||
set_symmetric_difference(_locations.begin(), _locations.end(), locations.begin(), locations.end(), inserter(locationsDiff, locationsDiff.begin()));
|
||||
p.Locations(locationsDiff);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -552,6 +578,11 @@ namespace loot {
|
||||
set_difference(_dirtyInfo.begin(), _dirtyInfo.end(), dirtyInfo.begin(), dirtyInfo.end(), inserter(dirtDiff, dirtDiff.begin()));
|
||||
p.DirtyInfo(dirtDiff);
|
||||
|
||||
set<Location> locations = plugin.Locations();
|
||||
set<Location> locationsDiff;
|
||||
set_difference(_locations.begin(), _locations.end(), locations.begin(), locations.end(), inserter(locationsDiff, locationsDiff.begin()));
|
||||
p.Locations(locationsDiff);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -591,6 +622,10 @@ namespace loot {
|
||||
return _dirtyInfo;
|
||||
}
|
||||
|
||||
std::set<Location> Plugin::Locations() const {
|
||||
return _locations;
|
||||
}
|
||||
|
||||
void Plugin::Name(const std::string& n) {
|
||||
name = n;
|
||||
}
|
||||
@@ -631,6 +666,10 @@ namespace loot {
|
||||
_dirtyInfo = dirtyInfo;
|
||||
}
|
||||
|
||||
void Plugin::Locations(const std::set<Location>& locations) {
|
||||
_locations = locations;
|
||||
}
|
||||
|
||||
Plugin& Plugin::EvalAllConditions(Game& game, const unsigned int language) {
|
||||
for (auto it = loadAfter.begin(); it != loadAfter.end();) {
|
||||
if (!it->EvalCondition(game))
|
||||
@@ -712,7 +751,7 @@ namespace loot {
|
||||
}
|
||||
|
||||
bool Plugin::HasNameOnly() const {
|
||||
return !IsPriorityExplicit() && loadAfter.empty() && requirements.empty() && incompatibilities.empty() && messages.empty() && tags.empty() && _dirtyInfo.empty();
|
||||
return !IsPriorityExplicit() && loadAfter.empty() && requirements.empty() && incompatibilities.empty() && messages.empty() && tags.empty() && _dirtyInfo.empty() && _locations.empty();
|
||||
}
|
||||
|
||||
bool Plugin::IsRegexPlugin() const {
|
||||
|
||||
@@ -161,6 +161,21 @@ namespace loot {
|
||||
bool addTag;
|
||||
};
|
||||
|
||||
class Location {
|
||||
public:
|
||||
Location();
|
||||
Location(const std::string& url);
|
||||
Location(const std::string& url, const std::vector<std::string>& versions);
|
||||
|
||||
bool operator < (const Location& rhs) const;
|
||||
|
||||
std::string URL() const;
|
||||
std::vector<std::string> Versions() const;
|
||||
private:
|
||||
std::string _url;
|
||||
std::vector<std::string> _versions;
|
||||
};
|
||||
|
||||
class Plugin {
|
||||
public:
|
||||
Plugin();
|
||||
@@ -190,6 +205,7 @@ namespace loot {
|
||||
std::list<Message> Messages() const;
|
||||
std::set<Tag> Tags() const;
|
||||
std::set<PluginDirtyInfo> DirtyInfo() const;
|
||||
std::set<Location> Locations() const;
|
||||
|
||||
const std::set<FormID>& FormIDs() const;
|
||||
std::vector<std::string> Masters() const;
|
||||
@@ -207,6 +223,7 @@ namespace loot {
|
||||
void Messages(const std::list<Message>& messages);
|
||||
void Tags(const std::set<Tag>& tags);
|
||||
void DirtyInfo(const std::set<PluginDirtyInfo>& info);
|
||||
void Locations(const std::set<Location>& locations);
|
||||
|
||||
Plugin& EvalAllConditions(Game& game, const unsigned int language);
|
||||
void ParseAllConditions(Game& game) const;
|
||||
@@ -239,6 +256,7 @@ namespace loot {
|
||||
std::list<Message> messages;
|
||||
std::set<Tag> tags;
|
||||
std::set<PluginDirtyInfo> _dirtyInfo;
|
||||
std::set<Location> _locations;
|
||||
|
||||
std::vector<std::string> masters;
|
||||
std::set<FormID> formIDs;
|
||||
|
||||
@@ -293,6 +293,36 @@ namespace YAML {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert < loot::Location > {
|
||||
static Node encode(const loot::Location& rhs) {
|
||||
Node node;
|
||||
|
||||
node["link"] = rhs.URL();
|
||||
node["ver"] = rhs.Versions();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, loot::Location& rhs) {
|
||||
std::string url;
|
||||
std::vector<std::string> versions;
|
||||
|
||||
if (node.IsMap()) {
|
||||
if (node["link"])
|
||||
url = node["link"].as<std::string>();
|
||||
if (node["ver"])
|
||||
versions = node["ver"].as<std::vector<std::string>>();
|
||||
}
|
||||
else if (node.IsScalar())
|
||||
url = node.as<std::string>();
|
||||
|
||||
rhs = loot::Location(url, versions);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, class Compare>
|
||||
struct convert < std::set<T, Compare> > {
|
||||
static Node encode(const std::set<T, Compare>& rhs) {
|
||||
@@ -350,6 +380,7 @@ namespace YAML {
|
||||
node["msg"] = rhs.Messages();
|
||||
node["tag"] = rhs.Tags();
|
||||
node["dirty"] = rhs.DirtyInfo();
|
||||
node["url"] = rhs.Locations();
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -380,6 +411,8 @@ namespace YAML {
|
||||
rhs.Tags(node["tag"].as< std::set<loot::Tag> >());
|
||||
if (node["dirty"])
|
||||
rhs.DirtyInfo(node["dirty"].as< std::set<loot::PluginDirtyInfo> >());
|
||||
if (node["url"])
|
||||
rhs.Locations(node["url"].as< std::set<loot::Location> >());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -484,8 +484,11 @@ namespace loot {
|
||||
newUserlistEntry.Tags(pluginMetadata["userlist"]["tag"].as<set<Tag>>());
|
||||
if (pluginMetadata["userlist"]["dirty"])
|
||||
newUserlistEntry.DirtyInfo(pluginMetadata["userlist"]["dirty"].as<set<PluginDirtyInfo>>());
|
||||
if (pluginMetadata["userlist"]["url"])
|
||||
newUserlistEntry.Locations(pluginMetadata["userlist"]["url"].as<set<Location>>());
|
||||
|
||||
// For cleanliness, only data that does not duplicate masterlist and plugin data should be retained, so diff that.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Removing any user metadata that duplicates masterlist metadata.";
|
||||
auto pluginIt = g_app_state.CurrentGame().plugins.find(boost::locale::to_lower(newUserlistEntry.Name()));
|
||||
if (pluginIt != g_app_state.CurrentGame().plugins.end()) {
|
||||
Plugin tempPlugin(pluginIt->second);
|
||||
@@ -689,6 +692,7 @@ namespace loot {
|
||||
pluginNode["masterlist"]["msg"] = mlistPlugin.Messages();
|
||||
pluginNode["masterlist"]["tag"] = mlistPlugin.Tags();
|
||||
pluginNode["masterlist"]["dirty"] = mlistPlugin.DirtyInfo();
|
||||
pluginNode["masterlist"]["url"] = mlistPlugin.Locations();
|
||||
}
|
||||
|
||||
if (!ulistPlugin.HasNameOnly()) {
|
||||
@@ -700,6 +704,7 @@ namespace loot {
|
||||
pluginNode["userlist"]["msg"] = ulistPlugin.Messages();
|
||||
pluginNode["userlist"]["tag"] = ulistPlugin.Tags();
|
||||
pluginNode["userlist"]["dirty"] = ulistPlugin.DirtyInfo();
|
||||
pluginNode["userlist"]["url"] = ulistPlugin.Locations();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,6 +817,7 @@ namespace loot {
|
||||
pluginNode["masterlist"]["msg"] = mlistPlugin.Messages();
|
||||
pluginNode["masterlist"]["tag"] = mlistPlugin.Tags();
|
||||
pluginNode["masterlist"]["dirty"] = mlistPlugin.DirtyInfo();
|
||||
pluginNode["masterlist"]["url"] = mlistPlugin.Locations();
|
||||
}
|
||||
|
||||
// Now merge masterlist and userlist metadata and evaluate,
|
||||
|
||||
Reference in New Issue
Block a user