mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 07:53:53 +00:00
Merge branch 'cs_universal_id_ref_id' into 'master'
Fix verification error reporting in Editor (#7387) Closes #7387 See merge request OpenMW/openmw!3044
This commit is contained in:
commit
c939781cfd
6 changed files with 360 additions and 164 deletions
|
@ -59,10 +59,19 @@ QVariant CSMTools::ReportModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
CSMWorld::UniversalId id = mRows.at(index.row()).mId;
|
CSMWorld::UniversalId id = mRows.at(index.row()).mId;
|
||||||
|
|
||||||
if (id.getArgumentType() == CSMWorld::UniversalId::ArgumentType_Id)
|
switch (id.getArgumentType())
|
||||||
return QString::fromUtf8(id.getId().c_str());
|
{
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_None:
|
||||||
|
return QString("-");
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_Index:
|
||||||
|
return QString::number(id.getIndex());
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_Id:
|
||||||
|
return QString::fromStdString(id.getId());
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_RefId:
|
||||||
|
return QString::fromStdString(id.getRefId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
return QString("-");
|
return QString("unsupported");
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column_Hint:
|
case Column_Hint:
|
||||||
|
|
|
@ -106,7 +106,7 @@ void CSMTools::ScriptCheckStage::perform(int stage, CSMDoc::Messages& messages)
|
||||||
|
|
||||||
mId = mDocument.getData().getScripts().getId(stage);
|
mId = mDocument.getData().getScripts().getId(stage);
|
||||||
|
|
||||||
if (mDocument.isBlacklisted(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Script, mId)))
|
if (mDocument.isBlacklisted(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Script, mId.getRefIdString())))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Skip "Base" records (setting!) and "Deleted" records
|
// Skip "Base" records (setting!) and "Deleted" records
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <compare>
|
#include <compare>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <span>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -13,12 +16,12 @@ namespace
|
||||||
{
|
{
|
||||||
CSMWorld::UniversalId::Class mClass;
|
CSMWorld::UniversalId::Class mClass;
|
||||||
CSMWorld::UniversalId::Type mType;
|
CSMWorld::UniversalId::Type mType;
|
||||||
const char* mName;
|
std::string_view mName;
|
||||||
const char* mIcon;
|
std::string_view mIcon;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TypeData sNoArg[] = {
|
constexpr TypeData sNoArg[] = {
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", 0 },
|
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", ":placeholder" },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables",
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables",
|
||||||
":./global-variable.png" },
|
":./global-variable.png" },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":./gmst.png" },
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":./gmst.png" },
|
||||||
|
@ -80,11 +83,9 @@ namespace
|
||||||
":./start-script.png" },
|
":./start-script.png" },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata",
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata",
|
||||||
":./metadata.png" },
|
":./metadata.png" },
|
||||||
// end marker
|
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TypeData sIdArg[] = {
|
constexpr TypeData sIdArg[] = {
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable",
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable",
|
||||||
":./global-variable.png" },
|
":./global-variable.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./gmst.png" },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./gmst.png" },
|
||||||
|
@ -164,24 +165,63 @@ namespace
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script",
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script",
|
||||||
":./start-script.png" },
|
":./start-script.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":./metadata.png" },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":./metadata.png" },
|
||||||
// end marker
|
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TypeData sIndexArg[] = {
|
constexpr TypeData sIndexArg[] = {
|
||||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults,
|
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults,
|
||||||
"Verification Results", ":./menu-verify.png" },
|
"Verification Results", ":./menu-verify.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log",
|
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log",
|
||||||
":./error-log.png" },
|
":./error-log.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search",
|
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search",
|
||||||
":./menu-search.png" },
|
":./menu-search.png" },
|
||||||
// end marker
|
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WriteToStream
|
||||||
|
{
|
||||||
|
std::ostream& mStream;
|
||||||
|
|
||||||
|
void operator()(std::monostate /*value*/) const {}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void operator()(const T& value) const
|
||||||
|
{
|
||||||
|
mStream << ": " << value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetTypeData
|
||||||
|
{
|
||||||
|
std::span<const TypeData> operator()(std::monostate /*value*/) const { return sNoArg; }
|
||||||
|
|
||||||
|
std::span<const TypeData> operator()(int /*value*/) const { return sIndexArg; }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::span<const TypeData> operator()(const T& /*value*/) const
|
||||||
|
{
|
||||||
|
return sIdArg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string toString(CSMWorld::UniversalId::ArgumentType value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_None:
|
||||||
|
return "None";
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_Id:
|
||||||
|
return "Id";
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_Index:
|
||||||
|
return "Index";
|
||||||
|
case CSMWorld::UniversalId::ArgumentType_RefId:
|
||||||
|
return "RefId";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::to_string(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::UniversalId(const std::string& universalId)
|
CSMWorld::UniversalId::UniversalId(const std::string& universalId)
|
||||||
: mIndex(0)
|
: mValue(std::monostate{})
|
||||||
{
|
{
|
||||||
std::string::size_type index = universalId.find(':');
|
std::string::size_type index = universalId.find(':');
|
||||||
|
|
||||||
|
@ -189,39 +229,40 @@ CSMWorld::UniversalId::UniversalId(const std::string& universalId)
|
||||||
{
|
{
|
||||||
std::string type = universalId.substr(0, index);
|
std::string type = universalId.substr(0, index);
|
||||||
|
|
||||||
for (int i = 0; sIdArg[i].mName; ++i)
|
for (const TypeData& value : sIdArg)
|
||||||
if (type == sIdArg[i].mName)
|
if (type == value.mName)
|
||||||
{
|
{
|
||||||
mArgumentType = ArgumentType_Id;
|
mType = value.mType;
|
||||||
mType = sIdArg[i].mType;
|
mClass = value.mClass;
|
||||||
mClass = sIdArg[i].mClass;
|
mValue = universalId.substr(index + 2);
|
||||||
mId = universalId.substr(index + 2);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; sIndexArg[i].mName; ++i)
|
for (const TypeData& value : sIndexArg)
|
||||||
if (type == sIndexArg[i].mName)
|
if (type == value.mName)
|
||||||
{
|
{
|
||||||
mArgumentType = ArgumentType_Index;
|
mType = value.mType;
|
||||||
mType = sIndexArg[i].mType;
|
mClass = value.mClass;
|
||||||
mClass = sIndexArg[i].mClass;
|
|
||||||
|
|
||||||
std::istringstream stream(universalId.substr(index + 2));
|
std::istringstream stream(universalId.substr(index + 2));
|
||||||
|
|
||||||
if (stream >> mIndex)
|
int index = 0;
|
||||||
|
if (stream >> index)
|
||||||
|
{
|
||||||
|
mValue = index;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; sNoArg[i].mName; ++i)
|
for (const TypeData& value : sIndexArg)
|
||||||
if (universalId == sNoArg[i].mName)
|
if (universalId == value.mName)
|
||||||
{
|
{
|
||||||
mArgumentType = ArgumentType_None;
|
mType = value.mType;
|
||||||
mType = sNoArg[i].mType;
|
mClass = value.mClass;
|
||||||
mClass = sNoArg[i].mClass;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,30 +271,29 @@ CSMWorld::UniversalId::UniversalId(const std::string& universalId)
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::UniversalId(Type type)
|
CSMWorld::UniversalId::UniversalId(Type type)
|
||||||
: mArgumentType(ArgumentType_None)
|
: mType(type)
|
||||||
, mType(type)
|
, mValue(std::monostate{})
|
||||||
, mIndex(0)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; sNoArg[i].mName; ++i)
|
for (const TypeData& value : sNoArg)
|
||||||
if (type == sNoArg[i].mType)
|
if (type == value.mType)
|
||||||
{
|
{
|
||||||
mClass = sNoArg[i].mClass;
|
mClass = value.mClass;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; sIdArg[i].mName; ++i)
|
for (const TypeData& value : sIdArg)
|
||||||
if (type == sIdArg[i].mType)
|
if (type == value.mType)
|
||||||
{
|
{
|
||||||
mArgumentType = ArgumentType_Id;
|
mValue = std::string();
|
||||||
mClass = sIdArg[i].mClass;
|
mClass = value.mClass;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; sIndexArg[i].mName; ++i)
|
for (const TypeData& value : sIndexArg)
|
||||||
if (type == sIndexArg[i].mType)
|
if (type == value.mType)
|
||||||
{
|
{
|
||||||
mArgumentType = ArgumentType_Index;
|
mValue = int{};
|
||||||
mClass = sIndexArg[i].mClass;
|
mClass = value.mClass;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,38 +301,43 @@ CSMWorld::UniversalId::UniversalId(Type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::UniversalId(Type type, const std::string& id)
|
CSMWorld::UniversalId::UniversalId(Type type, const std::string& id)
|
||||||
: mArgumentType(ArgumentType_Id)
|
: mType(type)
|
||||||
, mType(type)
|
, mValue(id)
|
||||||
, mId(id)
|
|
||||||
, mIndex(0)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; sIdArg[i].mName; ++i)
|
for (const TypeData& value : sIdArg)
|
||||||
if (type == sIdArg[i].mType)
|
if (type == value.mType)
|
||||||
{
|
{
|
||||||
mClass = sIdArg[i].mClass;
|
mClass = value.mClass;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw std::logic_error("invalid ID argument UniversalId type");
|
throw std::logic_error("invalid ID argument UniversalId type: " + std::to_string(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::UniversalId(Type type, const ESM::RefId& id)
|
CSMWorld::UniversalId::UniversalId(Type type, ESM::RefId id)
|
||||||
|
: mType(type)
|
||||||
|
, mValue(id)
|
||||||
{
|
{
|
||||||
UniversalId(type, id.getRefIdString());
|
for (const TypeData& value : sIdArg)
|
||||||
|
if (type == value.mType)
|
||||||
|
{
|
||||||
|
mClass = value.mClass;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw std::logic_error("invalid RefId argument UniversalId type: " + std::to_string(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::UniversalId(Type type, int index)
|
CSMWorld::UniversalId::UniversalId(Type type, int index)
|
||||||
: mArgumentType(ArgumentType_Index)
|
: mType(type)
|
||||||
, mType(type)
|
, mValue(index)
|
||||||
, mIndex(index)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; sIndexArg[i].mName; ++i)
|
for (const TypeData& value : sIndexArg)
|
||||||
if (type == sIndexArg[i].mType)
|
if (type == value.mType)
|
||||||
{
|
{
|
||||||
mClass = sIndexArg[i].mClass;
|
mClass = value.mClass;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::logic_error("invalid index argument UniversalId type");
|
throw std::logic_error("invalid index argument UniversalId type: " + std::to_string(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const
|
CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const
|
||||||
|
@ -302,7 +347,7 @@ CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const
|
||||||
|
|
||||||
CSMWorld::UniversalId::ArgumentType CSMWorld::UniversalId::getArgumentType() const
|
CSMWorld::UniversalId::ArgumentType CSMWorld::UniversalId::getArgumentType() const
|
||||||
{
|
{
|
||||||
return mArgumentType;
|
return static_cast<CSMWorld::UniversalId::ArgumentType>(mValue.index());
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const
|
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const
|
||||||
|
@ -312,65 +357,35 @@ CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const
|
||||||
|
|
||||||
const std::string& CSMWorld::UniversalId::getId() const
|
const std::string& CSMWorld::UniversalId::getId() const
|
||||||
{
|
{
|
||||||
if (mArgumentType != ArgumentType_Id)
|
if (const std::string* result = std::get_if<std::string>(&mValue))
|
||||||
throw std::logic_error("invalid access to ID of non-ID UniversalId");
|
return *result;
|
||||||
|
|
||||||
return mId;
|
throw std::logic_error("invalid access to ID of " + ::toString(getArgumentType()) + " UniversalId");
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMWorld::UniversalId::getIndex() const
|
int CSMWorld::UniversalId::getIndex() const
|
||||||
{
|
{
|
||||||
if (mArgumentType != ArgumentType_Index)
|
if (const int* result = std::get_if<int>(&mValue))
|
||||||
throw std::logic_error("invalid access to index of non-index UniversalId");
|
return *result;
|
||||||
|
|
||||||
return mIndex;
|
throw std::logic_error("invalid access to index of " + ::toString(getArgumentType()) + " UniversalId");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMWorld::UniversalId::isEqual(const UniversalId& universalId) const
|
ESM::RefId CSMWorld::UniversalId::getRefId() const
|
||||||
{
|
{
|
||||||
if (mClass != universalId.mClass || mArgumentType != universalId.mArgumentType || mType != universalId.mType)
|
if (const ESM::RefId* result = std::get_if<ESM::RefId>(&mValue))
|
||||||
return false;
|
return *result;
|
||||||
|
|
||||||
switch (mArgumentType)
|
throw std::logic_error("invalid access to RefId of " + ::toString(getArgumentType()) + " UniversalId");
|
||||||
{
|
|
||||||
case ArgumentType_Id:
|
|
||||||
return mId == universalId.mId;
|
|
||||||
case ArgumentType_Index:
|
|
||||||
return mIndex == universalId.mIndex;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CSMWorld::UniversalId::isLess(const UniversalId& universalId) const
|
|
||||||
{
|
|
||||||
if (mType < universalId.mType)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (mType > universalId.mType)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (mArgumentType)
|
|
||||||
{
|
|
||||||
case ArgumentType_Id:
|
|
||||||
return mId < universalId.mId;
|
|
||||||
case ArgumentType_Index:
|
|
||||||
return mIndex < universalId.mIndex;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CSMWorld::UniversalId::getTypeName() const
|
std::string CSMWorld::UniversalId::getTypeName() const
|
||||||
{
|
{
|
||||||
const TypeData* typeData
|
const std::span<const TypeData> typeData = std::visit(GetTypeData{}, mValue);
|
||||||
= mArgumentType == ArgumentType_None ? sNoArg : (mArgumentType == ArgumentType_Id ? sIdArg : sIndexArg);
|
|
||||||
|
|
||||||
for (int i = 0; typeData[i].mName; ++i)
|
for (const TypeData& value : typeData)
|
||||||
if (typeData[i].mType == mType)
|
if (value.mType == mType)
|
||||||
return typeData[i].mName;
|
return std::string(value.mName);
|
||||||
|
|
||||||
throw std::logic_error("failed to retrieve UniversalId type name");
|
throw std::logic_error("failed to retrieve UniversalId type name");
|
||||||
}
|
}
|
||||||
|
@ -381,29 +396,18 @@ std::string CSMWorld::UniversalId::toString() const
|
||||||
|
|
||||||
stream << getTypeName();
|
stream << getTypeName();
|
||||||
|
|
||||||
switch (mArgumentType)
|
std::visit(WriteToStream{ stream }, mValue);
|
||||||
{
|
|
||||||
case ArgumentType_None:
|
|
||||||
break;
|
|
||||||
case ArgumentType_Id:
|
|
||||||
stream << ": " << mId;
|
|
||||||
break;
|
|
||||||
case ArgumentType_Index:
|
|
||||||
stream << ": " << mIndex;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CSMWorld::UniversalId::getIcon() const
|
std::string CSMWorld::UniversalId::getIcon() const
|
||||||
{
|
{
|
||||||
const TypeData* typeData
|
const std::span<const TypeData> typeData = std::visit(GetTypeData{}, mValue);
|
||||||
= mArgumentType == ArgumentType_None ? sNoArg : (mArgumentType == ArgumentType_Id ? sIdArg : sIndexArg);
|
|
||||||
|
|
||||||
for (int i = 0; typeData[i].mName; ++i)
|
for (const TypeData& value : typeData)
|
||||||
if (typeData[i].mType == mType)
|
if (value.mType == mType)
|
||||||
return typeData[i].mIcon ? typeData[i].mIcon : ":placeholder";
|
return std::string(value.mIcon);
|
||||||
|
|
||||||
throw std::logic_error("failed to retrieve UniversalId type icon");
|
throw std::logic_error("failed to retrieve UniversalId type icon");
|
||||||
}
|
}
|
||||||
|
@ -412,9 +416,9 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl
|
||||||
{
|
{
|
||||||
std::vector<CSMWorld::UniversalId::Type> list;
|
std::vector<CSMWorld::UniversalId::Type> list;
|
||||||
|
|
||||||
for (int i = 0; sIdArg[i].mName; ++i)
|
for (const TypeData& value : sIdArg)
|
||||||
if (sIdArg[i].mClass == Class_RefRecord)
|
if (value.mClass == Class_RefRecord)
|
||||||
list.push_back(sIdArg[i].mType);
|
list.push_back(value.mType);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -423,31 +427,30 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listTypes(int cl
|
||||||
{
|
{
|
||||||
std::vector<CSMWorld::UniversalId::Type> list;
|
std::vector<CSMWorld::UniversalId::Type> list;
|
||||||
|
|
||||||
for (int i = 0; sNoArg[i].mName; ++i)
|
for (const TypeData& value : sNoArg)
|
||||||
if (sNoArg[i].mClass & classes)
|
if (value.mClass & classes)
|
||||||
list.push_back(sNoArg[i].mType);
|
list.push_back(value.mType);
|
||||||
|
|
||||||
for (int i = 0; sIdArg[i].mName; ++i)
|
for (const TypeData& value : sIdArg)
|
||||||
if (sIdArg[i].mClass & classes)
|
if (value.mClass & classes)
|
||||||
list.push_back(sIdArg[i].mType);
|
list.push_back(value.mType);
|
||||||
|
|
||||||
for (int i = 0; sIndexArg[i].mName; ++i)
|
for (const TypeData& value : sIndexArg)
|
||||||
if (sIndexArg[i].mClass & classes)
|
if (value.mClass & classes)
|
||||||
list.push_back(sIndexArg[i].mType);
|
list.push_back(value.mType);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType(Type type)
|
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType(Type type)
|
||||||
{
|
{
|
||||||
for (int i = 0; sIdArg[i].mType; ++i)
|
for (const TypeData& value : sIdArg)
|
||||||
if (type == sIdArg[i].mType)
|
if (type == value.mType)
|
||||||
{
|
{
|
||||||
if (sIdArg[i].mClass == Class_RefRecord)
|
if (value.mClass == Class_RefRecord)
|
||||||
return Type_Referenceables;
|
return Type_Referenceables;
|
||||||
|
|
||||||
if (sIdArg[i].mClass == Class_SubRecord || sIdArg[i].mClass == Class_Record
|
if (value.mClass == Class_SubRecord || value.mClass == Class_Record || value.mClass == Class_Resource)
|
||||||
|| sIdArg[i].mClass == Class_Resource)
|
|
||||||
{
|
{
|
||||||
if (type == Type_Cell_Missing)
|
if (type == Type_Cell_Missing)
|
||||||
return Type_Cells;
|
return Type_Cells;
|
||||||
|
@ -463,15 +466,10 @@ CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType(Type type)
|
||||||
|
|
||||||
bool CSMWorld::operator==(const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
|
bool CSMWorld::operator==(const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
|
||||||
{
|
{
|
||||||
return left.isEqual(right);
|
return std::tie(left.mClass, left.mType, left.mValue) == std::tie(right.mClass, right.mType, right.mValue);
|
||||||
}
|
|
||||||
|
|
||||||
bool CSMWorld::operator!=(const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
|
|
||||||
{
|
|
||||||
return !left.isEqual(right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMWorld::operator<(const UniversalId& left, const UniversalId& right)
|
bool CSMWorld::operator<(const UniversalId& left, const UniversalId& right)
|
||||||
{
|
{
|
||||||
return left.isLess(right);
|
return std::tie(left.mClass, left.mType, left.mValue) < std::tie(right.mClass, right.mType, right.mValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CSM_WOLRD_UNIVERSALID_H
|
#define CSM_WOLRD_UNIVERSALID_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
@ -31,7 +32,8 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
ArgumentType_None,
|
ArgumentType_None,
|
||||||
ArgumentType_Id,
|
ArgumentType_Id,
|
||||||
ArgumentType_Index
|
ArgumentType_Index,
|
||||||
|
ArgumentType_RefId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \note A record list type must always be immediately followed by the matching
|
/// \note A record list type must always be immediately followed by the matching
|
||||||
|
@ -144,14 +146,6 @@ namespace CSMWorld
|
||||||
NumberOfTypes = Type_RunLog + 1
|
NumberOfTypes = Type_RunLog + 1
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
Class mClass;
|
|
||||||
ArgumentType mArgumentType;
|
|
||||||
Type mType;
|
|
||||||
std::string mId;
|
|
||||||
int mIndex;
|
|
||||||
|
|
||||||
public:
|
|
||||||
UniversalId(const std::string& universalId);
|
UniversalId(const std::string& universalId);
|
||||||
|
|
||||||
UniversalId(Type type = Type_None);
|
UniversalId(Type type = Type_None);
|
||||||
|
@ -159,7 +153,7 @@ namespace CSMWorld
|
||||||
UniversalId(Type type, const std::string& id);
|
UniversalId(Type type, const std::string& id);
|
||||||
///< Using a type for a non-ID-argument UniversalId will throw an exception.
|
///< Using a type for a non-ID-argument UniversalId will throw an exception.
|
||||||
|
|
||||||
UniversalId(Type type, const ESM::RefId& id);
|
UniversalId(Type type, ESM::RefId id);
|
||||||
|
|
||||||
UniversalId(Type type, int index);
|
UniversalId(Type type, int index);
|
||||||
///< Using a type for a non-index-argument UniversalId will throw an exception.
|
///< Using a type for a non-index-argument UniversalId will throw an exception.
|
||||||
|
@ -176,9 +170,7 @@ namespace CSMWorld
|
||||||
int getIndex() const;
|
int getIndex() const;
|
||||||
///< Calling this function for a non-index type will throw an exception.
|
///< Calling this function for a non-index type will throw an exception.
|
||||||
|
|
||||||
bool isEqual(const UniversalId& universalId) const;
|
ESM::RefId getRefId() const;
|
||||||
|
|
||||||
bool isLess(const UniversalId& universalId) const;
|
|
||||||
|
|
||||||
std::string getTypeName() const;
|
std::string getTypeName() const;
|
||||||
|
|
||||||
|
@ -195,10 +187,18 @@ namespace CSMWorld
|
||||||
/// that contains records of type \a type.
|
/// that contains records of type \a type.
|
||||||
/// Otherwise return Type_None.
|
/// Otherwise return Type_None.
|
||||||
static Type getParentType(Type type);
|
static Type getParentType(Type type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Class mClass;
|
||||||
|
Type mType;
|
||||||
|
std::variant<std::monostate, std::string, int, ESM::RefId> mValue;
|
||||||
|
|
||||||
|
friend bool operator==(const UniversalId& left, const UniversalId& right);
|
||||||
|
|
||||||
|
friend bool operator<(const UniversalId& left, const UniversalId& right);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const UniversalId& left, const UniversalId& right);
|
bool operator==(const UniversalId& left, const UniversalId& right);
|
||||||
bool operator!=(const UniversalId& left, const UniversalId& right);
|
|
||||||
|
|
||||||
bool operator<(const UniversalId& left, const UniversalId& right);
|
bool operator<(const UniversalId& left, const UniversalId& right);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
file(GLOB OPENCS_TESTS_SRC_FILES
|
file(GLOB OPENCS_TESTS_SRC_FILES
|
||||||
main.cpp
|
main.cpp
|
||||||
model/world/testinfocollection.cpp
|
model/world/testinfocollection.cpp
|
||||||
|
model/world/testuniversalid.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(apps\\openmw-cs-tests FILES ${OPENCS_TESTS_SRC_FILES})
|
source_group(apps\\openmw-cs-tests FILES ${OPENCS_TESTS_SRC_FILES})
|
||||||
|
|
188
apps/opencs_tests/model/world/testuniversalid.cpp
Normal file
188
apps/opencs_tests/model/world/testuniversalid.cpp
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#include "apps/opencs/model/world/universalid.hpp"
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace ::testing;
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, shouldFailToConstructFromNoneWithInvalidType)
|
||||||
|
{
|
||||||
|
EXPECT_THROW(
|
||||||
|
UniversalId{ static_cast<UniversalId::Type>(std::numeric_limits<int>::max()) }, std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, shouldFailToConstructFromStringWithInvalidType)
|
||||||
|
{
|
||||||
|
EXPECT_THROW(UniversalId(UniversalId::Type_Search, "invalid"), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, shouldFailToConstructFromIntWithInvalidType)
|
||||||
|
{
|
||||||
|
EXPECT_THROW(UniversalId(UniversalId::Type_Activator, 42), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, shouldFailToConstructFromRefIdWithInvalidType)
|
||||||
|
{
|
||||||
|
EXPECT_THROW(UniversalId(UniversalId::Type_Search, ESM::RefId()), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, shouldFailToConstructFromInvalidUniversalIdString)
|
||||||
|
{
|
||||||
|
EXPECT_THROW(UniversalId("invalid"), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getIndexShouldThrowExceptionForDefaultConstructed)
|
||||||
|
{
|
||||||
|
const UniversalId id;
|
||||||
|
EXPECT_THROW(id.getIndex(), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getIndexShouldThrowExceptionForConstructedFromString)
|
||||||
|
{
|
||||||
|
const UniversalId id(UniversalId::Type_Activator, "a");
|
||||||
|
EXPECT_THROW(id.getIndex(), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getIndexShouldReturnValueForConstructedFromInt)
|
||||||
|
{
|
||||||
|
const UniversalId id(UniversalId::Type_Search, 42);
|
||||||
|
EXPECT_EQ(id.getIndex(), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getIdShouldThrowExceptionForConstructedFromInt)
|
||||||
|
{
|
||||||
|
const UniversalId id(UniversalId::Type_Search, 42);
|
||||||
|
EXPECT_THROW(id.getId(), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getIdShouldReturnValueForConstructedFromString)
|
||||||
|
{
|
||||||
|
const UniversalId id(UniversalId::Type_Activator, "a");
|
||||||
|
EXPECT_EQ(id.getId(), "a");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getRefIdShouldThrowExceptionForDefaultConstructed)
|
||||||
|
{
|
||||||
|
const UniversalId id;
|
||||||
|
EXPECT_THROW(id.getRefId(), std::logic_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CSMWorldUniversalIdTest, getRefIdShouldReturnValueForConstructedFromRefId)
|
||||||
|
{
|
||||||
|
const UniversalId id(UniversalId::Type_Skill, ESM::IndexRefId(ESM::REC_SKIL, 42));
|
||||||
|
EXPECT_EQ(id.getRefId(), ESM::IndexRefId(ESM::REC_SKIL, 42));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Params
|
||||||
|
{
|
||||||
|
UniversalId mId;
|
||||||
|
UniversalId::Type mType;
|
||||||
|
UniversalId::Class mClass;
|
||||||
|
UniversalId::ArgumentType mArgumentType;
|
||||||
|
std::string mTypeName;
|
||||||
|
std::string mString;
|
||||||
|
std::string mIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const Params& value)
|
||||||
|
{
|
||||||
|
return stream << ".mType = " << value.mType << " .mClass = " << value.mClass
|
||||||
|
<< " .mArgumentType = " << value.mArgumentType << " .mTypeName = " << value.mTypeName
|
||||||
|
<< " .mString = " << value.mString << " .mIcon = " << value.mIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CSMWorldUniversalIdValidPerTypeTest : TestWithParam<Params>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, getTypeShouldReturnExpected)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId.getType(), GetParam().mType);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, getClassShouldReturnExpected)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId.getClass(), GetParam().mClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, getArgumentTypeShouldReturnExpected)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId.getArgumentType(), GetParam().mArgumentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, shouldBeEqualToCopy)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId, UniversalId(GetParam().mId));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, shouldNotBeLessThanCopy)
|
||||||
|
{
|
||||||
|
EXPECT_FALSE(GetParam().mId < UniversalId(GetParam().mId));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, getTypeNameShouldReturnExpected)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId.getTypeName(), GetParam().mTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, toStringShouldReturnExpected)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId.toString(), GetParam().mString);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CSMWorldUniversalIdValidPerTypeTest, getIconShouldReturnExpected)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(GetParam().mId.getIcon(), GetParam().mIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array validParams = {
|
||||||
|
Params{ UniversalId(), UniversalId::Type_None, UniversalId::Class_None, UniversalId::ArgumentType_None, "-",
|
||||||
|
"-", ":placeholder" },
|
||||||
|
|
||||||
|
Params{ UniversalId(UniversalId::Type_None), UniversalId::Type_None, UniversalId::Class_None,
|
||||||
|
UniversalId::ArgumentType_None, "-", "-", ":placeholder" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_RegionMap), UniversalId::Type_RegionMap, UniversalId::Class_NonRecord,
|
||||||
|
UniversalId::ArgumentType_None, "Region Map", "Region Map", ":./region-map.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_RunLog), UniversalId::Type_RunLog, UniversalId::Class_Transient,
|
||||||
|
UniversalId::ArgumentType_None, "Run Log", "Run Log", ":./run-log.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Lands), UniversalId::Type_Lands, UniversalId::Class_RecordList,
|
||||||
|
UniversalId::ArgumentType_None, "Lands", "Lands", ":./land-heightmap.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Icons), UniversalId::Type_Icons, UniversalId::Class_ResourceList,
|
||||||
|
UniversalId::ArgumentType_None, "Icons", "Icons", ":./resources-icon" },
|
||||||
|
|
||||||
|
Params{ UniversalId(UniversalId::Type_Activator, "a"), UniversalId::Type_Activator,
|
||||||
|
UniversalId::Class_RefRecord, UniversalId::ArgumentType_Id, "Activator", "Activator: a",
|
||||||
|
":./activator.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Gmst, "b"), UniversalId::Type_Gmst, UniversalId::Class_Record,
|
||||||
|
UniversalId::ArgumentType_Id, "Game Setting", "Game Setting: b", ":./gmst.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Mesh, "c"), UniversalId::Type_Mesh, UniversalId::Class_Resource,
|
||||||
|
UniversalId::ArgumentType_Id, "Mesh", "Mesh: c", ":./resources-mesh" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Scene, "d"), UniversalId::Type_Scene, UniversalId::Class_Collection,
|
||||||
|
UniversalId::ArgumentType_Id, "Scene", "Scene: d", ":./scene.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Reference, "e"), UniversalId::Type_Reference,
|
||||||
|
UniversalId::Class_SubRecord, UniversalId::ArgumentType_Id, "Instance", "Instance: e",
|
||||||
|
":./instance.png" },
|
||||||
|
|
||||||
|
Params{ UniversalId(UniversalId::Type_Search, 42), UniversalId::Type_Search, UniversalId::Class_Transient,
|
||||||
|
UniversalId::ArgumentType_Index, "Global Search", "Global Search: 42", ":./menu-search.png" },
|
||||||
|
|
||||||
|
Params{ UniversalId("Instance: f"), UniversalId::Type_Reference, UniversalId::Class_SubRecord,
|
||||||
|
UniversalId::ArgumentType_Id, "Instance", "Instance: f", ":./instance.png" },
|
||||||
|
|
||||||
|
Params{ UniversalId(UniversalId::Type_Reference, ESM::RefId::stringRefId("g")), UniversalId::Type_Reference,
|
||||||
|
UniversalId::Class_SubRecord, UniversalId::ArgumentType_RefId, "Instance", "Instance: \"g\"",
|
||||||
|
":./instance.png" },
|
||||||
|
Params{ UniversalId(UniversalId::Type_Reference, ESM::RefId::index(ESM::REC_SKIL, 42)),
|
||||||
|
UniversalId::Type_Reference, UniversalId::Class_SubRecord, UniversalId::ArgumentType_RefId, "Instance",
|
||||||
|
"Instance: Index:SKIL:0x2a", ":./instance.png" },
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ValidParams, CSMWorldUniversalIdValidPerTypeTest, ValuesIn(validParams));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue