1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 03:40:14 +00:00

Merge branch 'fix_dialogue_title' into 'master'

Show original dialogue name

See merge request OpenMW/openmw!2862
This commit is contained in:
psi29a 2023-03-26 21:44:45 +00:00
commit cd6413c060
16 changed files with 241 additions and 135 deletions

View File

@ -741,6 +741,7 @@ namespace EsmTool
template <> template <>
void Record<ESM::Dialogue>::print() void Record<ESM::Dialogue>::print()
{ {
std::cout << " StringId: " << mData.mStringId << std::endl;
std::cout << " Type: " << dialogTypeLabel(mData.mType) << " (" << (int)mData.mType << ")" << std::endl; std::cout << " Type: " << dialogTypeLabel(mData.mType) << " (" << (int)mData.mType << ")" << std::endl;
std::cout << " Deleted: " << mIsDeleted << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl;
// Sadly, there are no DialInfos, because the loader dumps as it // Sadly, there are no DialInfos, because the loader dumps as it

View File

@ -7,6 +7,7 @@
#include <type_traits> #include <type_traits>
#include <components/esm/esmcommon.hpp> #include <components/esm/esmcommon.hpp>
#include <components/esm/typetraits.hpp>
#include <components/esm4/reader.hpp> #include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp> #include <components/esm4/readerutils.hpp>
#include <components/esm4/records.hpp> #include <components/esm4/records.hpp>
@ -93,7 +94,7 @@ namespace EsmTool
std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView(); std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView();
if constexpr (ESM4::hasFormId<T>) if constexpr (ESM4::hasFormId<T>)
std::cout << "\n FormId: " << value.mFormId; std::cout << "\n FormId: " << value.mFormId;
if constexpr (ESM4::hasId<T>) if constexpr (ESM::hasId<T>)
std::cout << "\n Id: " << value.mId; std::cout << "\n Id: " << value.mId;
if constexpr (ESM4::hasFlags<T>) if constexpr (ESM4::hasFlags<T>)
std::cout << "\n Record flags: " << recordFlags(value.mFlags); std::cout << "\n Record flags: " << recordFlags(value.mFlags);
@ -103,7 +104,7 @@ namespace EsmTool
std::cout << "\n Parent: " << value.mParent; std::cout << "\n Parent: " << value.mParent;
if constexpr (ESM4::hasEditorId<T>) if constexpr (ESM4::hasEditorId<T>)
std::cout << "\n EditorId: " << value.mEditorId; std::cout << "\n EditorId: " << value.mEditorId;
if constexpr (ESM4::hasModel<T>) if constexpr (ESM::hasModel<T>)
std::cout << "\n Model: " << value.mModel; std::cout << "\n Model: " << value.mModel;
if constexpr (ESM4::hasNif<T>) if constexpr (ESM4::hasNif<T>)
std::cout << "\n Nif:" << WriteArray("\n - ", value.mNif); std::cout << "\n Nif:" << WriteArray("\n - ", value.mNif);

View File

@ -107,17 +107,16 @@ void CSMDoc::Document::addOptionalGmsts()
void CSMDoc::Document::addOptionalGlobals() void CSMDoc::Document::addOptionalGlobals()
{ {
static const char* sGlobals[] = { static constexpr std::string_view globals[] = {
"DaysPassed", "DaysPassed",
"PCWerewolf", "PCWerewolf",
"PCYear", "PCYear",
nullptr,
}; };
for (int i = 0; sGlobals[i]; ++i) for (std::size_t i = 0; i < std::size(globals); ++i)
{ {
ESM::Global global; ESM::Global global;
global.mId = ESM::RefId::stringRefId(sGlobals[i]); global.mId = ESM::RefId::stringRefId(globals[i]);
global.blank(); global.blank();
global.mValue.setType(ESM::VT_Long); global.mValue.setType(ESM::VT_Long);
@ -176,7 +175,7 @@ void CSMDoc::Document::addOptionalMagicEffect(const ESM::MagicEffect& magicEffec
void CSMDoc::Document::createBase() void CSMDoc::Document::createBase()
{ {
static const char* sGlobals[] = { static constexpr std::string_view globals[] = {
"Day", "Day",
"DaysPassed", "DaysPassed",
"GameHour", "GameHour",
@ -185,13 +184,12 @@ void CSMDoc::Document::createBase()
"PCVampire", "PCVampire",
"PCWerewolf", "PCWerewolf",
"PCYear", "PCYear",
nullptr,
}; };
for (int i = 0; sGlobals[i]; ++i) for (std::size_t i = 0; i < std::size(globals); ++i)
{ {
ESM::Global record; ESM::Global record;
record.mId = ESM::RefId::stringRefId(sGlobals[i]); record.mId = ESM::RefId::stringRefId(globals[i]);
record.mRecordFlags = 0; record.mRecordFlags = 0;
record.mValue.setType(i == 2 ? ESM::VT_Float : ESM::VT_Long); record.mValue.setType(i == 2 ? ESM::VT_Float : ESM::VT_Long);
@ -213,7 +211,7 @@ void CSMDoc::Document::createBase()
getData().getSkills().add(record); getData().getSkills().add(record);
} }
static const char* sVoice[] = { static constexpr std::string_view voices[] = {
"Intruder", "Intruder",
"Attack", "Attack",
"Hello", "Hello",
@ -222,20 +220,20 @@ void CSMDoc::Document::createBase()
"Idle", "Idle",
"Flee", "Flee",
"Hit", "Hit",
nullptr,
}; };
for (int i = 0; sVoice[i]; ++i) for (const std::string_view voice : voices)
{ {
ESM::Dialogue record; ESM::Dialogue record;
record.mId = ESM::RefId::stringRefId(sVoice[i]); record.mId = ESM::RefId::stringRefId(voice);
record.mStringId = voice;
record.mType = ESM::Dialogue::Voice; record.mType = ESM::Dialogue::Voice;
record.blank(); record.blank();
getData().getTopics().add(record); getData().getTopics().add(record);
} }
static const char* sGreetings[] = { static constexpr std::string_view greetings[] = {
"Greeting 0", "Greeting 0",
"Greeting 1", "Greeting 1",
"Greeting 2", "Greeting 2",
@ -246,20 +244,20 @@ void CSMDoc::Document::createBase()
"Greeting 7", "Greeting 7",
"Greeting 8", "Greeting 8",
"Greeting 9", "Greeting 9",
nullptr,
}; };
for (int i = 0; sGreetings[i]; ++i) for (const std::string_view greeting : greetings)
{ {
ESM::Dialogue record; ESM::Dialogue record;
record.mId = ESM::RefId::stringRefId(sGreetings[i]); record.mId = ESM::RefId::stringRefId(greeting);
record.mStringId = greeting;
record.mType = ESM::Dialogue::Greeting; record.mType = ESM::Dialogue::Greeting;
record.blank(); record.blank();
getData().getTopics().add(record); getData().getTopics().add(record);
} }
static const char* sPersuasion[] = { static constexpr std::string_view persuasions[] = {
"Intimidate Success", "Intimidate Success",
"Intimidate Fail", "Intimidate Fail",
"Service Refusal", "Service Refusal",
@ -270,13 +268,13 @@ void CSMDoc::Document::createBase()
"Admire Fail", "Admire Fail",
"Taunt Fail", "Taunt Fail",
"Bribe Fail", "Bribe Fail",
nullptr,
}; };
for (int i = 0; sPersuasion[i]; ++i) for (const std::string_view persuasion : persuasions)
{ {
ESM::Dialogue record; ESM::Dialogue record;
record.mId = ESM::RefId::stringRefId(sPersuasion[i]); record.mId = ESM::RefId::stringRefId(persuasion);
record.mStringId = persuasion;
record.mType = ESM::Dialogue::Persuasion; record.mType = ESM::Dialogue::Persuasion;
record.blank(); record.blank();

View File

@ -14,6 +14,7 @@
#include <QVariant> #include <QVariant>
#include <components/esm3/loaddial.hpp>
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include "collectionbase.hpp" #include "collectionbase.hpp"
@ -278,6 +279,11 @@ namespace CSMWorld
} }
} }
if constexpr (std::is_same_v<ESXRecordT, ESM::Dialogue>)
{
copy->mModified.mStringId = copy->mModified.mId.getRefIdString();
}
const int index = getAppendIndex(destination, type); const int index = getAppendIndex(destination, type);
insertRecord(std::move(copy), getAppendIndex(destination, type)); insertRecord(std::move(copy), getAppendIndex(destination, type));
@ -489,6 +495,11 @@ namespace CSMWorld
setRecordId(id, record); setRecordId(id, record);
record.blank(); record.blank();
if constexpr (std::is_same_v<ESXRecordT, ESM::Dialogue>)
{
record.mStringId = record.mId.getRefIdString();
}
auto record2 = std::make_unique<Record<ESXRecordT>>(); auto record2 = std::make_unique<Record<ESXRecordT>>();
record2->mState = Record<ESXRecordT>::State_ModifiedOnly; record2->mState = Record<ESXRecordT>::State_ModifiedOnly;
record2->mModified = record; record2->mModified = record;

View File

@ -12,6 +12,7 @@
#include <apps/opencs/model/world/cell.hpp> #include <apps/opencs/model/world/cell.hpp>
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm3/loadbody.hpp> #include <components/esm3/loadbody.hpp>
#include <components/esm3/loaddial.hpp>
#include <components/esm3/loadinfo.hpp> #include <components/esm3/loadinfo.hpp>
#include <components/esm3/loadrace.hpp> #include <components/esm3/loadrace.hpp>
#include <components/esm3/loadskil.hpp> #include <components/esm3/loadskil.hpp>
@ -1342,7 +1343,7 @@ namespace CSMWorld
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
record2.mType = data.toInt(); record2.mType = static_cast<ESM::Dialogue::Type>(data.toInt());
record.setModified(record2); record.setModified(record2);
} }

View File

@ -41,12 +41,13 @@ namespace CSMWorld
}; };
DialogueData<ESM::DialInfo> generateDialogueWithInfos( DialogueData<ESM::DialInfo> generateDialogueWithInfos(
std::size_t infoCount, const ESM::RefId& dialogueId = ESM::RefId::stringRefId("dialogue")) std::size_t infoCount, std::string_view dialogueId = "dialogue")
{ {
DialogueData<ESM::DialInfo> result; DialogueData<ESM::DialInfo> result;
result.mDialogue.blank(); result.mDialogue.blank();
result.mDialogue.mId = dialogueId; result.mDialogue.mId = ESM::RefId::stringRefId(dialogueId);
result.mDialogue.mStringId = dialogueId;
for (std::size_t i = 0; i < infoCount; ++i) for (std::size_t i = 0; i < infoCount; ++i)
{ {
@ -133,6 +134,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
ESM::DialInfo info; ESM::DialInfo info;
info.blank(); info.blank();
@ -157,6 +159,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
ESM::DialInfo info; ESM::DialInfo info;
info.blank(); info.blank();
@ -181,6 +184,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
ESM::DialInfo info; ESM::DialInfo info;
info.blank(); info.blank();
@ -207,6 +211,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
ESM::DialInfo info; ESM::DialInfo info;
info.blank(); info.blank();
@ -233,6 +238,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
DialInfoData info; DialInfoData info;
info.mValue.blank(); info.mValue.blank();
@ -252,6 +258,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
DialInfoData info; DialInfoData info;
info.mValue.blank(); info.mValue.blank();
@ -275,6 +282,7 @@ namespace CSMWorld
ESM::Dialogue dialogue; ESM::Dialogue dialogue;
dialogue.blank(); dialogue.blank();
dialogue.mId = ESM::RefId::stringRefId("dialogue"); dialogue.mId = ESM::RefId::stringRefId("dialogue");
dialogue.mStringId = "Dialogue";
DialInfoData info; DialInfoData info;
info.mValue.blank(); info.mValue.blank();
@ -535,12 +543,9 @@ namespace CSMWorld
InfoOrderByTopic infoOrder; InfoOrderByTopic infoOrder;
InfoCollection collection; InfoCollection collection;
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue2"), base, collection, infoOrder);
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue2")), base, collection, infoOrder); saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue0"), base, collection, infoOrder);
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue1"), base, collection, infoOrder);
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue0")), base, collection, infoOrder);
saveAndLoadDialogueWithInfos(
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue1")), base, collection, infoOrder);
collection.sort(infoOrder); collection.sort(infoOrder);
@ -558,10 +563,8 @@ namespace CSMWorld
InfoOrderByTopic infoOrder; InfoOrderByTopic infoOrder;
InfoCollection collection; InfoCollection collection;
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue0"), base, collection, infoOrder);
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue0")), base, collection, infoOrder); saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue1"), base, collection, infoOrder);
saveAndLoadDialogueWithInfos(
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue1")), base, collection, infoOrder);
collection.sort(infoOrder); collection.sort(infoOrder);
@ -574,10 +577,8 @@ namespace CSMWorld
InfoOrderByTopic infoOrder; InfoOrderByTopic infoOrder;
InfoCollection collection; InfoCollection collection;
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue0"), base, collection, infoOrder);
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue0")), base, collection, infoOrder); saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue1"), base, collection, infoOrder);
saveAndLoadDialogueWithInfos(
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue1")), base, collection, infoOrder);
EXPECT_FALSE(collection.reorderRows(5, {})); EXPECT_FALSE(collection.reorderRows(5, {}));
} }
@ -588,10 +589,8 @@ namespace CSMWorld
InfoOrderByTopic infoOrder; InfoOrderByTopic infoOrder;
InfoCollection collection; InfoCollection collection;
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue0"), base, collection, infoOrder);
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue0")), base, collection, infoOrder); saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "dialogue1"), base, collection, infoOrder);
saveAndLoadDialogueWithInfos(
generateDialogueWithInfos(2, ESM::RefId::stringRefId("dialogue1")), base, collection, infoOrder);
EXPECT_FALSE(collection.reorderRows(0, { 0, 1, 2 })); EXPECT_FALSE(collection.reorderRows(0, { 0, 1, 2 }));
} }
@ -602,10 +601,8 @@ namespace CSMWorld
InfoOrderByTopic infoOrder; InfoOrderByTopic infoOrder;
InfoCollection collection; InfoCollection collection;
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(3, "dialogue0"), base, collection, infoOrder);
generateDialogueWithInfos(3, ESM::RefId::stringRefId("dialogue0")), base, collection, infoOrder); saveAndLoadDialogueWithInfos(generateDialogueWithInfos(3, "dialogue1"), base, collection, infoOrder);
saveAndLoadDialogueWithInfos(
generateDialogueWithInfos(3, ESM::RefId::stringRefId("dialogue1")), base, collection, infoOrder);
EXPECT_EQ(collection.searchId(ESM::RefId::stringRefId("dialogue0#info0")), 0); EXPECT_EQ(collection.searchId(ESM::RefId::stringRefId("dialogue0#info0")), 0);
EXPECT_EQ(collection.searchId(ESM::RefId::stringRefId("dialogue0#info1")), 1); EXPECT_EQ(collection.searchId(ESM::RefId::stringRefId("dialogue0#info1")), 1);
@ -629,10 +626,8 @@ namespace CSMWorld
InfoOrderByTopic infoOrder; InfoOrderByTopic infoOrder;
InfoCollection collection; InfoCollection collection;
saveAndLoadDialogueWithInfos( saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "d0"), base, collection, infoOrder);
generateDialogueWithInfos(2, ESM::RefId::stringRefId("d0")), base, collection, infoOrder); saveAndLoadDialogueWithInfos(generateDialogueWithInfos(2, "d1"), base, collection, infoOrder);
saveAndLoadDialogueWithInfos(
generateDialogueWithInfos(2, ESM::RefId::stringRefId("d1")), base, collection, infoOrder);
collection.sort(infoOrder); collection.sort(infoOrder);

View File

@ -297,7 +297,7 @@ namespace MWDialogue
if (info) if (info)
{ {
ESM::RefId title; std::string title;
if (dialogue.mType == ESM::Dialogue::Persuasion) if (dialogue.mType == ESM::Dialogue::Persuasion)
{ {
// Determine GMST from dialogue topic. GMSTs are: // Determine GMST from dialogue topic. GMSTs are:
@ -310,14 +310,13 @@ namespace MWDialogue
const MWWorld::Store<ESM::GameSetting>& gmsts const MWWorld::Store<ESM::GameSetting>& gmsts
= MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
title = ESM::RefId::stringRefId(gmsts.find(modifiedTopic)->mValue.getString()); title = gmsts.find(modifiedTopic)->mValue.getString();
} }
else else
title = topic; title = dialogue.mStringId;
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(), mActor); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(), mActor);
callback->addResponse( callback->addResponse(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
title.getRefIdString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
if (dialogue.mType == ESM::Dialogue::Topic) if (dialogue.mType == ESM::Dialogue::Topic)
{ {

View File

@ -2,6 +2,7 @@
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp> #include <components/esm3/esmwriter.hpp>
#include <components/esm3/loadcont.hpp> #include <components/esm3/loadcont.hpp>
#include <components/esm3/loaddial.hpp>
#include <components/esm3/loadregn.hpp> #include <components/esm3/loadregn.hpp>
#include <components/esm3/loadscpt.hpp> #include <components/esm3/loadscpt.hpp>
#include <components/esm3/player.hpp> #include <components/esm3/player.hpp>
@ -71,11 +72,16 @@ namespace ESM
{ {
using namespace ::testing; using namespace ::testing;
constexpr std::array formats = { std::vector<ESM::FormatVersion> getFormats()
{
std::vector<ESM::FormatVersion> result({
MaxLimitedSizeStringsFormatVersion, MaxLimitedSizeStringsFormatVersion,
MaxStringRefIdFormatVersion, MaxStringRefIdFormatVersion,
CurrentSaveGameFormatVersion, });
}; for (ESM::FormatVersion v = result.back() + 1; v <= ESM::CurrentSaveGameFormatVersion; ++v)
result.push_back(v);
return result;
}
constexpr std::uint32_t fakeRecordId = fourCC("FAKE"); constexpr std::uint32_t fakeRecordId = fourCC("FAKE");
@ -327,6 +333,18 @@ namespace ESM
EXPECT_EQ(result.mKeys, record.mKeys); EXPECT_EQ(result.mKeys, record.mKeys);
} }
INSTANTIATE_TEST_SUITE_P(FormatVersions, Esm3SaveLoadRecordTest, ValuesIn(formats)); TEST_P(Esm3SaveLoadRecordTest, dialogueShouldNotChange)
{
Dialogue record;
record.blank();
record.mStringId = generateRandomString(32);
record.mId = ESM::RefId::stringRefId(record.mStringId);
Dialogue result;
saveAndLoadRecord(record, GetParam(), result);
EXPECT_EQ(result.mId, record.mId);
EXPECT_EQ(result.mStringId, record.mStringId);
}
INSTANTIATE_TEST_SUITE_P(FormatVersions, Esm3SaveLoadRecordTest, ValuesIn(getFormats()));
} }
} }

View File

@ -11,8 +11,10 @@
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include <components/esm/typetraits.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp> #include <components/esm3/esmwriter.hpp>
#include <components/esm3/typetraits.hpp>
#include <components/esm4/common.hpp> #include <components/esm4/common.hpp>
#include <components/esm4/loadcell.hpp> #include <components/esm4/loadcell.hpp>
#include <components/esm4/loadligh.hpp> #include <components/esm4/loadligh.hpp>
@ -20,7 +22,6 @@
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/esm4/reader.hpp> #include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp> #include <components/esm4/readerutils.hpp>
#include <components/esm4/typetraits.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp> #include <components/files/conversion.hpp>
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
@ -268,7 +269,9 @@ std::unique_ptr<std::istream> getEsmFile(T record, bool deleted, ESM::FormatVers
namespace namespace
{ {
constexpr std::array formats = { std::vector<ESM::FormatVersion> getFormats()
{
std::vector<ESM::FormatVersion> result({
ESM::DefaultFormatVersion, ESM::DefaultFormatVersion,
ESM::CurrentContentFormatVersion, ESM::CurrentContentFormatVersion,
ESM::MaxOldWeatherFormatVersion, ESM::MaxOldWeatherFormatVersion,
@ -282,8 +285,11 @@ namespace
ESM::MaxOldSkillsAndAttributesFormatVersion, ESM::MaxOldSkillsAndAttributesFormatVersion,
ESM::MaxOldCreatureStatsFormatVersion, ESM::MaxOldCreatureStatsFormatVersion,
ESM::MaxStringRefIdFormatVersion, ESM::MaxStringRefIdFormatVersion,
ESM::CurrentSaveGameFormatVersion, });
}; for (ESM::FormatVersion v = result.back() + 1; v <= ESM::CurrentSaveGameFormatVersion; ++v)
result.push_back(v);
return result;
}
template <class T, class = std::void_t<>> template <class T, class = std::void_t<>>
struct HasBlankFunction : std::false_type struct HasBlankFunction : std::false_type
@ -304,7 +310,7 @@ TYPED_TEST_P(StoreTest, delete_test)
{ {
using RecordType = TypeParam; using RecordType = TypeParam;
for (const ESM::FormatVersion formatVersion : formats) for (const ESM::FormatVersion formatVersion : getFormats())
{ {
SCOPED_TRACE("FormatVersion: " + std::to_string(formatVersion)); SCOPED_TRACE("FormatVersion: " + std::to_string(formatVersion));
const ESM::RefId recordId = ESM::RefId::stringRefId("foobar"); const ESM::RefId recordId = ESM::RefId::stringRefId("foobar");
@ -382,7 +388,7 @@ TYPED_TEST_P(StoreTest, overwrite_test)
{ {
using RecordType = TypeParam; using RecordType = TypeParam;
for (const ESM::FormatVersion formatVersion : formats) for (const ESM::FormatVersion formatVersion : getFormats())
{ {
SCOPED_TRACE("FormatVersion: " + std::to_string(formatVersion)); SCOPED_TRACE("FormatVersion: " + std::to_string(formatVersion));
@ -428,19 +434,6 @@ namespace
{ {
}; };
template <class T, class = std::void_t<>>
struct HasIndex : std::false_type
{
};
template <class T>
struct HasIndex<T, std::void_t<decltype(T::mIndex)>> : std::true_type
{
};
template <class T>
constexpr bool hasIndex = HasIndex<T>::value;
TYPED_TEST_SUITE_P(StoreSaveLoadTest); TYPED_TEST_SUITE_P(StoreSaveLoadTest);
TYPED_TEST_P(StoreSaveLoadTest, shouldNotChangeRefId) TYPED_TEST_P(StoreSaveLoadTest, shouldNotChangeRefId)
@ -448,13 +441,14 @@ namespace
using RecordType = TypeParam; using RecordType = TypeParam;
const int index = 3; const int index = 3;
const std::string stringId = "foobar";
decltype(RecordType::mId) refId; decltype(RecordType::mId) refId;
if constexpr (hasIndex<RecordType> && !std::is_same_v<RecordType, ESM::LandTexture>) if constexpr (ESM::hasIndex<RecordType> && !std::is_same_v<RecordType, ESM::LandTexture>)
refId = RecordType::indexToRefId(index); refId = RecordType::indexToRefId(index);
else else
refId = ESM::StringRefId("foobar"); refId = ESM::StringRefId(stringId);
for (const ESM::FormatVersion formatVersion : formats) for (const ESM::FormatVersion formatVersion : getFormats())
{ {
SCOPED_TRACE("FormatVersion: " + std::to_string(formatVersion)); SCOPED_TRACE("FormatVersion: " + std::to_string(formatVersion));
@ -465,7 +459,10 @@ namespace
record.mId = refId; record.mId = refId;
if constexpr (hasIndex<RecordType>) if constexpr (ESM::hasStringId<RecordType>)
record.mStringId = stringId;
if constexpr (ESM::hasIndex<RecordType>)
record.mIndex = index; record.mIndex = index;
if constexpr (std::is_same_v<RecordType, ESM::Global>) if constexpr (std::is_same_v<RecordType, ESM::Global>)
@ -482,7 +479,7 @@ namespace
const RecordType* result = nullptr; const RecordType* result = nullptr;
if constexpr (std::is_same_v<RecordType, ESM::LandTexture>) if constexpr (std::is_same_v<RecordType, ESM::LandTexture>)
result = esmStore.get<RecordType>().search(index, 0); result = esmStore.get<RecordType>().search(index, 0);
else if constexpr (hasIndex<RecordType>) else if constexpr (ESM::hasIndex<RecordType>)
result = esmStore.get<RecordType>().search(index); result = esmStore.get<RecordType>().search(index);
else else
result = esmStore.get<RecordType>().search(refId); result = esmStore.get<RecordType>().search(refId);
@ -492,7 +489,8 @@ namespace
} }
} }
static_assert(hasIndex<ESM::MagicEffect>); static_assert(ESM::hasIndex<ESM::MagicEffect>);
static_assert(ESM::hasStringId<ESM::Dialogue>);
template <class T, class = std::void_t<>> template <class T, class = std::void_t<>>
struct HasSaveFunction : std::false_type struct HasSaveFunction : std::false_type
@ -558,9 +556,9 @@ namespace
}; };
using RecordTypes = typename ToRecordTypes<MWWorld::ESMStore::StoreTuple>::Type; using RecordTypes = typename ToRecordTypes<MWWorld::ESMStore::StoreTuple>::Type;
using RecordTypesWithId = typename FilterTypes<ESM4::HasId, RecordTypes>::Type; using RecordTypesWithId = typename FilterTypes<ESM::HasId, RecordTypes>::Type;
using RecordTypesWithSave = typename FilterTypes<HasSaveFunction, RecordTypesWithId>::Type; using RecordTypesWithSave = typename FilterTypes<HasSaveFunction, RecordTypesWithId>::Type;
using RecordTypesWithModel = typename FilterTypes<ESM4::HasModel, RecordTypesWithSave>::Type; using RecordTypesWithModel = typename FilterTypes<ESM::HasModel, RecordTypesWithSave>::Type;
REGISTER_TYPED_TEST_SUITE_P(StoreSaveLoadTest, shouldNotChangeRefId); REGISTER_TYPED_TEST_SUITE_P(StoreSaveLoadTest, shouldNotChangeRefId);
@ -600,6 +598,7 @@ namespace
result.mDialogue.blank(); result.mDialogue.blank();
result.mDialogue.mId = ESM::RefId::stringRefId("dialogue"); result.mDialogue.mId = ESM::RefId::stringRefId("dialogue");
result.mDialogue.mStringId = "Dialogue";
for (std::size_t i = 0; i < infoCount; ++i) for (std::size_t i = 0; i < infoCount; ++i)
{ {

View File

@ -0,0 +1,35 @@
#ifndef OPENMW_COMPONENTS_ESM_TYPETRAITS
#define OPENMW_COMPONENTS_ESM_TYPETRAITS
#include <type_traits>
namespace ESM
{
template <class T, class = std::void_t<>>
struct HasId : std::false_type
{
};
template <class T>
struct HasId<T, std::void_t<decltype(T::mId)>> : std::true_type
{
};
template <class T>
inline constexpr bool hasId = HasId<T>::value;
template <class T, class = std::void_t<>>
struct HasModel : std::false_type
{
};
template <class T>
struct HasModel<T, std::void_t<decltype(T::mModel)>> : std::true_type
{
};
template <class T>
inline constexpr bool hasModel = HasModel<T>::value;
}
#endif // OPENMW_COMPONENTS_ESM_TYPETRAITS

View File

@ -21,8 +21,9 @@ namespace ESM
inline constexpr FormatVersion MaxOldCreatureStatsFormatVersion = 19; inline constexpr FormatVersion MaxOldCreatureStatsFormatVersion = 19;
inline constexpr FormatVersion MaxLimitedSizeStringsFormatVersion = 22; inline constexpr FormatVersion MaxLimitedSizeStringsFormatVersion = 22;
inline constexpr FormatVersion MaxStringRefIdFormatVersion = 23; inline constexpr FormatVersion MaxStringRefIdFormatVersion = 23;
inline constexpr FormatVersion MaxSavedGameCellNameAsRefId = 24; inline constexpr FormatVersion MaxSavedGameCellNameAsRefIdFormatVersion = 24;
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 25; inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25;
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 26;
} }
#endif #endif

View File

@ -3,6 +3,8 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include <stdexcept>
namespace ESM namespace ESM
{ {
@ -13,8 +15,21 @@ namespace ESM
} }
void Dialogue::loadId(ESMReader& esm) void Dialogue::loadId(ESMReader& esm)
{
if (esm.getFormatVersion() <= MaxStringRefIdFormatVersion)
{
mStringId = esm.getHNString("NAME");
mId = ESM::RefId::stringRefId(mStringId);
return;
}
if (esm.getFormatVersion() <= MaxNameIsRefIdOnlyFormatVersion)
{ {
mId = esm.getHNRefId("NAME"); mId = esm.getHNRefId("NAME");
return;
}
mId = esm.getHNRefId("ID__");
} }
void Dialogue::loadData(ESMReader& esm, bool& isDeleted) void Dialogue::loadData(ESMReader& esm, bool& isDeleted)
@ -37,6 +52,7 @@ namespace ESM
else else
{ {
esm.skip(size); esm.skip(size);
mType = Unknown;
} }
break; break;
} }
@ -45,28 +61,49 @@ namespace ESM
mType = Unknown; mType = Unknown;
isDeleted = true; isDeleted = true;
break; break;
case SREC_NAME:
mStringId = esm.getHString();
break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break; break;
} }
} }
if (!isDeleted && MaxStringRefIdFormatVersion < esm.getFormatVersion()
&& esm.getFormatVersion() <= MaxNameIsRefIdOnlyFormatVersion)
mStringId = mId.toString();
} }
void Dialogue::save(ESMWriter& esm, bool isDeleted) const void Dialogue::save(ESMWriter& esm, bool isDeleted) const
{ {
esm.writeHNCRefId("NAME", mId); if (esm.getFormatVersion() <= MaxStringRefIdFormatVersion)
{
if (mId != mStringId)
throw std::runtime_error("Trying to save Dialogue record with name \"" + mStringId
+ "\" not maching id " + mId.toDebugString());
esm.writeHNString("NAME", mStringId);
}
else if (esm.getFormatVersion() <= MaxNameIsRefIdOnlyFormatVersion)
esm.writeHNRefId("NAME", mId);
else
esm.writeHNRefId("ID__", mId);
if (isDeleted) if (isDeleted)
{ {
esm.writeHNString("DELE", "", 3); esm.writeHNString("DELE", "", 3);
} }
else else
{ {
if (esm.getFormatVersion() > MaxNameIsRefIdOnlyFormatVersion)
esm.writeHNString("NAME", mStringId);
esm.writeHNT("DATA", mType); esm.writeHNT("DATA", mType);
} }
} }
void Dialogue::blank() void Dialogue::blank()
{ {
mType = Unknown;
mInfo.clear(); mInfo.clear();
} }

View File

@ -30,7 +30,7 @@ namespace ESM
/// Return a string descriptor for this record type. Currently used for debugging / error logs only. /// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string_view getRecordType() { return "Dialogue"; } static std::string_view getRecordType() { return "Dialogue"; }
enum Type enum Type : std::int8_t
{ {
Topic = 0, Topic = 0,
Voice = 1, Voice = 1,
@ -41,7 +41,8 @@ namespace ESM
}; };
RefId mId; RefId mId;
signed char mType; std::string mStringId;
Type mType;
InfoContainer mInfo; InfoContainer mInfo;
InfoOrder<DialInfo> mInfoOrder; InfoOrder<DialInfo> mInfoOrder;

View File

@ -13,7 +13,7 @@ namespace ESM
mPlayerClassId = esm.getHNORefId("PLCL"); mPlayerClassId = esm.getHNORefId("PLCL");
mPlayerClassName = esm.getHNOString("PLCN"); mPlayerClassName = esm.getHNOString("PLCN");
if (esm.getFormatVersion() <= ESM::MaxSavedGameCellNameAsRefId) if (esm.getFormatVersion() <= ESM::MaxSavedGameCellNameAsRefIdFormatVersion)
mPlayerCellName = esm.getHNRefId("PLCE").toString(); mPlayerCellName = esm.getHNRefId("PLCE").toString();
else else
mPlayerCellName = esm.getHNString("PLCE"); mPlayerCellName = esm.getHNString("PLCE");

View File

@ -0,0 +1,35 @@
#ifndef OPENMW_COMPONENTS_ESM3_TYPETRAITS
#define OPENMW_COMPONENTS_ESM3_TYPETRAITS
#include <type_traits>
namespace ESM
{
template <class T, class = std::void_t<>>
struct HasIndex : std::false_type
{
};
template <class T>
struct HasIndex<T, std::void_t<decltype(T::mIndex)>> : std::true_type
{
};
template <class T>
inline constexpr bool hasIndex = HasIndex<T>::value;
template <class T, class = std::void_t<>>
struct HasStringId : std::false_type
{
};
template <class T>
struct HasStringId<T, std::void_t<decltype(T::mStringId)>> : std::true_type
{
};
template <class T>
inline constexpr bool hasStringId = HasStringId<T>::value;
}
#endif // OPENMW_COMPONENTS_ESM3_TYPETRAITS

View File

@ -18,19 +18,6 @@ namespace ESM4
template <class T> template <class T>
inline constexpr bool hasFormId = HasFormId<T>::value; inline constexpr bool hasFormId = HasFormId<T>::value;
template <class T, class = std::void_t<>>
struct HasId : std::false_type
{
};
template <class T>
struct HasId<T, std::void_t<decltype(T::mId)>> : std::true_type
{
};
template <class T>
inline constexpr bool hasId = HasId<T>::value;
template <class T, class = std::void_t<>> template <class T, class = std::void_t<>>
struct HasParentFormId : std::false_type struct HasParentFormId : std::false_type
{ {
@ -83,19 +70,6 @@ namespace ESM4
template <class T> template <class T>
inline constexpr bool hasEditorId = HasEditorId<T>::value; inline constexpr bool hasEditorId = HasEditorId<T>::value;
template <class T, class = std::void_t<>>
struct HasModel : std::false_type
{
};
template <class T>
struct HasModel<T, std::void_t<decltype(T::mModel)>> : std::true_type
{
};
template <class T>
inline constexpr bool hasModel = HasModel<T>::value;
template <class T, class = std::void_t<>> template <class T, class = std::void_t<>>
struct HasNif : std::false_type struct HasNif : std::false_type
{ {