summaryrefslogtreecommitdiff
path: root/src/categories.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/categories.cpp')
-rw-r--r--src/categories.cpp208
1 files changed, 115 insertions, 93 deletions
diff --git a/src/categories.cpp b/src/categories.cpp
index 70efd706..e64d35c3 100644
--- a/src/categories.cpp
+++ b/src/categories.cpp
@@ -29,6 +29,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QList>
#include <QObject>
+#include "nexusinterface.h"
+
using namespace MOBase;
CategoryFactory* CategoryFactory::s_Instance = nullptr;
@@ -38,6 +40,13 @@ QString CategoryFactory::categoriesFilePath()
return qApp->property("dataPath").toString() + "/categories.dat";
}
+
+QString CategoryFactory::nexusMappingFilePath()
+{
+ return qApp->property("dataPath").toString() + "/nexuscatmap.dat";
+}
+
+
CategoryFactory::CategoryFactory()
{
atexit(&cleanup);
@@ -48,20 +57,18 @@ void CategoryFactory::loadCategories()
reset();
QFile categoryFile(categoriesFilePath());
+ bool needLoad = false;
if (!categoryFile.open(QIODevice::ReadOnly)) {
- loadDefaultCategories();
+ needLoad = true;
} else {
int lineNum = 0;
while (!categoryFile.atEnd()) {
QByteArray line = categoryFile.readLine();
++lineNum;
QList<QByteArray> cells = line.split('|');
- if (cells.count() != 4) {
- log::error("invalid category line {}: {} ({} cells)", lineNum, line.constData(),
- cells.count());
- } else {
- std::vector<int> nexusIDs;
+ if (cells.count() == 4) {
+ std::vector<NexusCategory> nexusCats;
if (cells[2].length() > 0) {
QList<QByteArray> nexusIDStrings = cells[2].split(',');
for (QList<QByteArray>::iterator iter = nexusIDStrings.begin();
@@ -69,9 +76,9 @@ void CategoryFactory::loadCategories()
bool ok = false;
int temp = iter->toInt(&ok);
if (!ok) {
- log::error("invalid category id {}", iter->constData());
+ log::error(tr("invalid category id {}"), iter->constData());
}
- nexusIDs.push_back(temp);
+ nexusCats.push_back(NexusCategory("Unknown", temp));
}
}
bool cell0Ok = true;
@@ -79,23 +86,63 @@ void CategoryFactory::loadCategories()
int id = cells[0].toInt(&cell0Ok);
int parentID = cells[3].trimmed().toInt(&cell3Ok);
if (!cell0Ok || !cell3Ok) {
- log::error("invalid category line {}: {}", lineNum, line.constData());
+ log::error(tr("invalid category line {}: {}"), lineNum, line.constData());
}
- addCategory(id, QString::fromUtf8(cells[1].constData()), nexusIDs, parentID);
+ addCategory(id, QString::fromUtf8(cells[1].constData()), nexusCats, parentID);
+ } else if (cells.count() == 3) {
+ bool cell0Ok = true;
+ bool cell3Ok = true;
+ int id = cells[0].toInt(&cell0Ok);
+ int parentID = cells[2].trimmed().toInt(&cell3Ok);
+ if (!cell0Ok || !cell3Ok) {
+ log::error(tr("invalid category line {}: {}"), lineNum, line.constData());
+ }
+
+ addCategory(id, QString::fromUtf8(cells[1].constData()), std::vector<NexusCategory>(), parentID);
+ } else {
+ log::error(
+ tr("invalid category line {}: {} ({} cells)"),
+ lineNum, line.constData(), cells.count());
}
}
categoryFile.close();
+
+ QFile nexusMapFile(nexusMappingFilePath());
+ if (!nexusMapFile.open(QIODevice::ReadOnly)) {
+ needLoad = true;
+ } else {
+ int nexLineNum = 0;
+ while (!nexusMapFile.atEnd()) {
+ QByteArray nexLine = nexusMapFile.readLine();
+ ++nexLineNum;
+ QList<QByteArray> nexCells = nexLine.split('|');
+ std::vector<NexusCategory> nexusCats;
+ QString nexName = nexCells[1];
+ bool ok = false;
+ int nexID = nexCells[2].toInt(&ok);
+ if (!ok) {
+ log::error(tr("invalid nexus ID {}"), nexCells[2].constData());
+ }
+ int catID = nexCells[0].toInt(&ok);
+ if (!ok) {
+ log::error(tr("invalid category id {}"), nexCells[0].constData());
+ }
+ m_NexusMap[NexusCategory(nexName, nexID)] = catID;
+ }
+ }
+ nexusMapFile.close();
}
std::sort(m_Categories.begin(), m_Categories.end());
setParents();
+ if (needLoad) loadDefaultCategories();
}
-CategoryFactory& CategoryFactory::instance()
+CategoryFactory* CategoryFactory::instance()
{
if (s_Instance == nullptr) {
s_Instance = new CategoryFactory;
}
- return *s_Instance;
+ return s_Instance;
}
void CategoryFactory::reset()
@@ -106,7 +153,7 @@ void CategoryFactory::reset()
// 43 = Savegames (makes no sense to install them through MO)
// 45 = Videos and trailers
// 87 = Miscelanous
- addCategory(0, "None", {4, 28, 43, 45, 87}, 0);
+ addCategory(0, "None", std::vector<NexusCategory>(), 0);
}
void CategoryFactory::setParents()
@@ -139,7 +186,7 @@ void CategoryFactory::saveCategories()
QFile categoryFile(categoriesFilePath());
if (!categoryFile.open(QIODevice::WriteOnly)) {
- reportError(QObject::tr("Failed to save custom categories"));
+ reportError(tr("Failed to save custom categories"));
return;
}
@@ -154,13 +201,28 @@ void CategoryFactory::saveCategories()
.append("|")
.append(iter->m_Name.toUtf8())
.append("|")
- .append(VectorJoin(iter->m_NexusIDs, ",").toUtf8())
- .append("|")
.append(QByteArray::number(iter->m_ParentID))
.append("\n");
categoryFile.write(line);
}
categoryFile.close();
+
+ QFile nexusMapFile(nexusMappingFilePath());
+
+ if (!nexusMapFile.open(QIODevice::WriteOnly)) {
+ reportError(tr("Failed to save nexus category mappings"));
+ return;
+ }
+
+ nexusMapFile.resize(0);
+ QByteArray line;
+ for (auto iter = m_NexusMap.begin(); iter != m_NexusMap.end(); ++iter) {
+ line.append(iter->first.m_Name).append("|");
+ line.append(iter->first.m_ID).append("|");
+ line.append(iter->second).append("\n");
+ categoryFile.write(line);
+ }
+ categoryFile.close();
}
unsigned int
@@ -175,97 +237,55 @@ CategoryFactory::countCategories(std::function<bool(const Category& category)> f
return result;
}
-int CategoryFactory::addCategory(const QString& name, const std::vector<int>& nexusIDs,
- int parentID)
+int CategoryFactory::addCategory(const QString& name, const std::vector<NexusCategory>& nexusCats, int parentID)
{
int id = 1;
while (m_IDMap.find(id) != m_IDMap.end()) {
++id;
}
- addCategory(id, name, nexusIDs, parentID);
+ addCategory(id, name, nexusCats, parentID);
saveCategories();
return id;
}
-void CategoryFactory::addCategory(int id, const QString& name,
- const std::vector<int>& nexusIDs, int parentID)
+void CategoryFactory::addCategory(int id, const QString& name, int parentID)
{
int index = static_cast<int>(m_Categories.size());
- m_Categories.push_back(Category(index, id, name, nexusIDs, parentID));
- for (int nexusID : nexusIDs) {
- m_NexusMap[nexusID] = index;
- }
+ m_Categories.push_back(Category(index, id, name, parentID));
m_IDMap[id] = index;
}
+void CategoryFactory::addCategory(int id, const QString& name, const std::vector<NexusCategory>& nexusCats, int parentID)
+{
+ for (auto nexusCat : nexusCats) {
+ m_NexusMap[nexusCat] = id;
+ }
+ addCategory(id, name, parentID);
+}
+
+
void CategoryFactory::loadDefaultCategories()
{
// the order here is relevant as it defines the order in which the
// mods appear in the combo box
- addCategory(1, "Animations", {2, 4, 51}, 0);
- addCategory(52, "Poses", {1, 29}, 1);
- addCategory(2, "Armour", {2, 5, 54}, 0);
- addCategory(53, "Power Armor", {1, 53}, 2);
- addCategory(3, "Audio", {3, 33, 35, 106}, 0);
- addCategory(38, "Music", {2, 34, 61}, 0);
- addCategory(39, "Voice", {2, 36, 107}, 0);
- addCategory(5, "Clothing", {2, 9, 60}, 0);
- addCategory(41, "Jewelry", {1, 102}, 5);
- addCategory(42, "Backpacks", {1, 49}, 5);
- addCategory(6, "Collectables", {2, 10, 92}, 0);
- addCategory(28, "Companions", {3, 11, 66, 96}, 0);
- addCategory(7, "Creatures, Mounts, & Vehicles", {4, 12, 65, 83, 101}, 0);
- addCategory(8, "Factions", {2, 16, 25}, 0);
- addCategory(9, "Gameplay", {2, 15, 24}, 0);
- addCategory(27, "Combat", {1, 77}, 9);
- addCategory(43, "Crafting", {2, 50, 100}, 9);
- addCategory(48, "Overhauls", {2, 24, 79}, 9);
- addCategory(49, "Perks", {1, 27}, 9);
- addCategory(54, "Radio", {1, 31}, 9);
- addCategory(55, "Shouts", {1, 104}, 9);
- addCategory(22, "Skills & Levelling", {2, 46, 73}, 9);
- addCategory(58, "Weather & Lighting", {1, 56}, 9);
- addCategory(44, "Equipment", {1, 44}, 43);
- addCategory(45, "Home/Settlement", {1, 45}, 43);
- addCategory(10, "Body, Face, & Hair", {2, 17, 26}, 0);
- addCategory(56, "Tattoos", {1, 57}, 10);
- addCategory(40, "Character Presets", {1, 58}, 0);
- addCategory(11, "Items", {2, 27, 85}, 0);
- addCategory(32, "Mercantile", {2, 23, 69}, 0);
- addCategory(37, "Ammo", {1, 3}, 11);
- addCategory(19, "Weapons", {2, 41, 55}, 11);
- addCategory(36, "Weapon & Armour Sets", {1, 42}, 11);
- addCategory(23, "Player Homes", {2, 28, 67}, 0);
- addCategory(25, "Castles & Mansions", {1, 68}, 23);
- addCategory(51, "Settlements", {1, 48}, 23);
- addCategory(12, "Locations", {10, 20, 21, 22, 30, 47, 70, 88, 89, 90, 91}, 0);
- addCategory(4, "Cities", {1, 53}, 12);
- addCategory(31, "Landscape Changes", {1, 58}, 0);
- addCategory(29, "Environment", {2, 14, 74}, 0);
- addCategory(30, "Immersion", {2, 51, 78}, 0);
- addCategory(20, "Magic", {3, 75, 93, 94}, 0);
- addCategory(21, "Models & Textures", {2, 19, 29}, 0);
- addCategory(33, "Modders resources", {2, 18, 82}, 0);
- addCategory(13, "NPCs", {3, 22, 33, 99}, 0);
- addCategory(24, "Bugfixes", {2, 6, 95}, 0);
- addCategory(14, "Patches", {2, 25, 84}, 24);
- addCategory(35, "Utilities", {2, 38, 39}, 0);
- addCategory(26, "Cheats", {1, 8}, 0);
- addCategory(15, "Quests", {2, 30, 35}, 0);
- addCategory(16, "Races & Classes", {1, 34}, 0);
- addCategory(34, "Stealth", {1, 76}, 0);
- addCategory(17, "UI", {2, 37, 42}, 0);
- addCategory(18, "Visuals", {2, 40, 62}, 0);
- addCategory(50, "Pip-Boy", {1, 52}, 18);
- addCategory(46, "Shader Presets", {3, 13, 97, 105}, 0);
- addCategory(47, "Miscellaneous", {2, 2, 28}, 0);
+ if (QMessageBox::question(nullptr, tr("Load Nexus Categories?"),
+ tr("This is either a new or old instance which lacks modern Nexus category mappings. Would you like to import and map categories from Nexus now?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit requestNexusCategories();
+ }
+}
+
+
+void CategoryFactory::mapNexusCategories(QString, QVariant, QVariant result)
+{
+
}
int CategoryFactory::getParentID(unsigned int index) const
{
if (index >= m_Categories.size()) {
- throw MyException(QObject::tr("invalid category index: %1").arg(index));
+ throw MyException(tr("invalid category index: %1").arg(index));
}
return m_Categories[index].m_ParentID;
@@ -303,7 +323,7 @@ bool CategoryFactory::isDescendantOfImpl(int id, int parentID,
return isDescendantOfImpl(m_Categories[index].m_ParentID, parentID, seen);
}
} else {
- log::warn("{} is no valid category id", id);
+ log::warn(tr("{} is no valid category id"), id);
return false;
}
}
@@ -311,7 +331,7 @@ bool CategoryFactory::isDescendantOfImpl(int id, int parentID,
bool CategoryFactory::hasChildren(unsigned int index) const
{
if (index >= m_Categories.size()) {
- throw MyException(QObject::tr("invalid category index: %1").arg(index));
+ throw MyException(tr("invalid category index: %1").arg(index));
}
return m_Categories[index].m_HasChildren;
@@ -320,7 +340,7 @@ bool CategoryFactory::hasChildren(unsigned int index) const
QString CategoryFactory::getCategoryName(unsigned int index) const
{
if (index >= m_Categories.size()) {
- throw MyException(QObject::tr("invalid category index: %1").arg(index));
+ throw MyException(tr("invalid category index: %1").arg(index));
}
return m_Categories[index].m_Name;
@@ -388,7 +408,7 @@ QString CategoryFactory::getCategoryNameByID(int id) const
int CategoryFactory::getCategoryID(unsigned int index) const
{
if (index >= m_Categories.size()) {
- throw MyException(QObject::tr("invalid category index: %1").arg(index));
+ throw MyException(tr("invalid category index: %1").arg(index));
}
return m_Categories[index].m_ID;
@@ -398,7 +418,7 @@ int CategoryFactory::getCategoryIndex(int ID) const
{
std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(ID);
if (iter == m_IDMap.end()) {
- throw MyException(QObject::tr("invalid category id: %1").arg(ID));
+ throw MyException(tr("invalid category id: %1").arg(ID));
}
return iter->second;
}
@@ -419,12 +439,14 @@ int CategoryFactory::getCategoryID(const QString& name) const
unsigned int CategoryFactory::resolveNexusID(int nexusID) const
{
- std::map<int, unsigned int>::const_iterator iter = m_NexusMap.find(nexusID);
- if (iter != m_NexusMap.end()) {
- log::debug("nexus category id {} maps to internal {}", nexusID, iter->second);
- return iter->second;
+ auto result = std::find_if(m_NexusMap.begin(), m_NexusMap.end(), [nexusID](const std::pair<NexusCategory, unsigned int> el) {
+ return el.first.m_ID == nexusID;
+ });
+ if (result != m_NexusMap.end()) {
+ log::debug(tr("nexus category id {} maps to internal {}"), nexusID, result->second);
+ return result->second;
} else {
- log::debug("nexus category id {} not mapped", nexusID);
+ log::debug(tr("nexus category id {} not mapped"), nexusID);
return 0U;
}
}