mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-09 03:39:14 +00:00
142 lines
3.9 KiB
C++
142 lines
3.9 KiB
C++
#include "infocollection.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "components/debug/debuglog.hpp"
|
|
#include "components/esm3/infoorder.hpp"
|
|
#include "components/esm3/loaddial.hpp"
|
|
#include "components/esm3/loadinfo.hpp"
|
|
|
|
#include "collection.hpp"
|
|
#include "info.hpp"
|
|
|
|
namespace CSMWorld
|
|
{
|
|
namespace
|
|
{
|
|
std::string_view getInfoTopicId(const ESM::RefId& infoId)
|
|
{
|
|
return parseInfoRefId(infoId).first;
|
|
}
|
|
}
|
|
|
|
ESM::RefId makeCompositeInfoRefId(const ESM::RefId& topicId, const ESM::RefId& infoId)
|
|
{
|
|
return ESM::RefId::stringRefId(topicId.getRefIdString() + '#' + infoId.getRefIdString());
|
|
}
|
|
}
|
|
|
|
void CSMWorld::InfoCollection::load(const Info& value, bool base)
|
|
{
|
|
const int index = searchId(value.mId);
|
|
|
|
if (index == -1)
|
|
{
|
|
// new record
|
|
auto record = std::make_unique<Record<Info>>();
|
|
record->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
|
(base ? record->mBase : record->mModified) = value;
|
|
|
|
insertRecord(std::move(record), getSize());
|
|
}
|
|
else
|
|
{
|
|
// old record
|
|
auto record = std::make_unique<Record<Info>>(getRecord(index));
|
|
|
|
if (base)
|
|
record->mBase = value;
|
|
else
|
|
record->setModified(value);
|
|
|
|
setRecord(index, std::move(record));
|
|
}
|
|
}
|
|
|
|
void CSMWorld::InfoCollection::load(
|
|
ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue, InfoOrderByTopic& infoOrders)
|
|
{
|
|
Info info;
|
|
bool isDeleted = false;
|
|
|
|
info.load(reader, isDeleted);
|
|
|
|
const ESM::RefId id = makeCompositeInfoRefId(dialogue.mId, info.mId);
|
|
|
|
if (isDeleted)
|
|
{
|
|
const int index = searchId(id);
|
|
|
|
if (index == -1)
|
|
{
|
|
Log(Debug::Warning) << "Trying to delete absent info \"" << info.mId << "\" from topic \"" << dialogue.mId
|
|
<< "\"";
|
|
return;
|
|
}
|
|
|
|
if (base)
|
|
{
|
|
infoOrders.at(dialogue.mId).removeInfo(info.mId);
|
|
removeRows(index, 1);
|
|
return;
|
|
}
|
|
|
|
auto record = std::make_unique<Record<Info>>(getRecord(index));
|
|
record->mState = RecordBase::State_Deleted;
|
|
setRecord(index, std::move(record));
|
|
|
|
return;
|
|
}
|
|
|
|
info.mTopicId = dialogue.mId;
|
|
info.mOriginalId = info.mId;
|
|
info.mId = id;
|
|
|
|
load(info, base);
|
|
|
|
infoOrders[dialogue.mId].insertInfo(OrderedInfo(info), isDeleted);
|
|
}
|
|
|
|
void CSMWorld::InfoCollection::sort(const InfoOrderByTopic& infoOrders)
|
|
{
|
|
std::vector<int> order;
|
|
order.reserve(getSize());
|
|
for (const auto& [topicId, infoOrder] : infoOrders)
|
|
for (const OrderedInfo& info : infoOrder.getOrderedInfo())
|
|
order.push_back(getIndex(makeCompositeInfoRefId(topicId, info.mId)));
|
|
reorderRowsImp(order);
|
|
}
|
|
|
|
CSMWorld::InfosRecordPtrByTopic CSMWorld::InfoCollection::getInfosByTopic() const
|
|
{
|
|
InfosRecordPtrByTopic result;
|
|
for (const std::unique_ptr<Record<Info>>& record : getRecords())
|
|
result[record->get().mTopicId].push_back(record.get());
|
|
return result;
|
|
}
|
|
|
|
int CSMWorld::InfoCollection::getAppendIndex(const ESM::RefId& id, UniversalId::Type /*type*/) const
|
|
{
|
|
const auto lessByTopicId
|
|
= [](std::string_view lhs, const std::unique_ptr<Record<Info>>& rhs) { return lhs < rhs->get().mTopicId; };
|
|
const auto it = std::upper_bound(getRecords().begin(), getRecords().end(), getInfoTopicId(id), lessByTopicId);
|
|
return static_cast<int>(it - getRecords().begin());
|
|
}
|
|
|
|
bool CSMWorld::InfoCollection::reorderRows(int baseIndex, const std::vector<int>& newOrder)
|
|
{
|
|
const int lastIndex = baseIndex + static_cast<int>(newOrder.size()) - 1;
|
|
|
|
if (lastIndex >= getSize())
|
|
return false;
|
|
|
|
if (getRecord(baseIndex).get().mTopicId != getRecord(lastIndex).get().mTopicId)
|
|
return false;
|
|
|
|
return reorderRowsImp(baseIndex, newOrder);
|
|
}
|