1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-22 04:23:53 +00:00
openmw/apps/opencs/model/world/refiddata.hpp
fteppe 20da0892ef openMW_test_suite compiles and runs
Slowly moving through the open-cs errors

Good progress in openCS

Very good progress on openCS

Getting closer with openCS

OpenCS compiles and runs! Didn't have time to test it all though

ix openMW

everything compiles on windows??

Fix gcc

Fix Clang
2022-12-27 19:15:55 +01:00

334 lines
11 KiB
C++

#ifndef CSM_WOLRD_REFIDDATA_H
#define CSM_WOLRD_REFIDDATA_H
#include <algorithm>
#include <cassert>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <components/esm3/esmwriter.hpp>
#include <components/esm3/loadacti.hpp>
#include <components/esm3/loadalch.hpp>
#include <components/esm3/loadappa.hpp>
#include <components/esm3/loadarmo.hpp>
#include <components/esm3/loadbook.hpp>
#include <components/esm3/loadclot.hpp>
#include <components/esm3/loadcont.hpp>
#include <components/esm3/loadcrea.hpp>
#include <components/esm3/loaddoor.hpp>
#include <components/esm3/loadingr.hpp>
#include <components/esm3/loadlevlist.hpp>
#include <components/esm3/loadligh.hpp>
#include <components/esm3/loadlock.hpp>
#include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadnpc.hpp>
#include <components/esm3/loadprob.hpp>
#include <components/esm3/loadrepa.hpp>
#include <components/esm3/loadstat.hpp>
#include <components/esm3/loadweap.hpp>
#include <components/misc/strings/algorithm.hpp>
#include "record.hpp"
#include "universalid.hpp"
namespace ESM
{
class ESMReader;
}
namespace CSMWorld
{
struct RefIdDataContainerBase
{
virtual ~RefIdDataContainerBase();
virtual int getSize() const = 0;
virtual const RecordBase& getRecord(int index) const = 0;
virtual RecordBase& getRecord(int index) = 0;
virtual unsigned int getRecordFlags(int index) const = 0;
virtual void appendRecord(const ESM::RefId& id, bool base) = 0;
virtual void insertRecord(std::unique_ptr<RecordBase> record) = 0;
virtual int load(ESM::ESMReader& reader, bool base) = 0;
///< \return index of a loaded record or -1 if no record was loaded
virtual void erase(int index, int count) = 0;
virtual ESM::RefId getId(int index) const = 0;
virtual void save(int index, ESM::ESMWriter& writer) const = 0;
};
template <typename RecordT>
struct RefIdDataContainer : public RefIdDataContainerBase
{
std::vector<std::unique_ptr<Record<RecordT>>> mContainer;
int getSize() const override;
const RecordBase& getRecord(int index) const override;
RecordBase& getRecord(int index) override;
unsigned int getRecordFlags(int index) const override;
void appendRecord(const ESM::RefId& id, bool base) override;
void insertRecord(std::unique_ptr<RecordBase> record) override;
int load(ESM::ESMReader& reader, bool base) override;
///< \return index of a loaded record or -1 if no record was loaded
void erase(int index, int count) override;
ESM::RefId getId(int index) const override;
void save(int index, ESM::ESMWriter& writer) const override;
};
template <typename RecordT>
void RefIdDataContainer<RecordT>::insertRecord(std::unique_ptr<RecordBase> record)
{
assert(record != nullptr);
// convert base pointer to record type pointer
std::unique_ptr<Record<RecordT>> typedRecord(&dynamic_cast<Record<RecordT>&>(*record));
record.release();
mContainer.push_back(std::move(typedRecord));
}
template <typename RecordT>
int RefIdDataContainer<RecordT>::getSize() const
{
return static_cast<int>(mContainer.size());
}
template <typename RecordT>
const RecordBase& RefIdDataContainer<RecordT>::getRecord(int index) const
{
return *mContainer.at(index);
}
template <typename RecordT>
RecordBase& RefIdDataContainer<RecordT>::getRecord(int index)
{
return *mContainer.at(index);
}
template <typename RecordT>
unsigned int RefIdDataContainer<RecordT>::getRecordFlags(int index) const
{
return mContainer.at(index)->get().mRecordFlags;
}
template <typename RecordT>
void RefIdDataContainer<RecordT>::appendRecord(const ESM::RefId& id, bool base)
{
auto record = std::make_unique<Record<RecordT>>();
record->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
record->mBase.mId = id;
record->mModified.mId = id;
(base ? record->mBase : record->mModified).blank();
mContainer.push_back(std::move(record));
}
template <typename RecordT>
int RefIdDataContainer<RecordT>::load(ESM::ESMReader& reader, bool base)
{
RecordT record;
bool isDeleted = false;
record.load(reader, isDeleted);
int index = 0;
int numRecords = static_cast<int>(mContainer.size());
for (; index < numRecords; ++index)
{
if ((mContainer[index]->get().mId == record.mId))
{
break;
}
}
if (isDeleted)
{
if (index == numRecords)
{
// deleting a record that does not exist
// ignore it for now
/// \todo report the problem to the user
return -1;
}
// Flag the record as Deleted even for a base content file.
// RefIdData is responsible for its erasure.
mContainer[index]->mState = RecordBase::State_Deleted;
}
else
{
if (index == numRecords)
{
appendRecord(record.mId, base);
if (base)
{
mContainer.back()->mBase = record;
}
else
{
mContainer.back()->mModified = record;
}
}
else if (!base)
{
mContainer[index]->setModified(record);
}
else
{
// Overwrite
mContainer[index]->setModified(record);
mContainer[index]->merge();
}
}
return index;
}
template <typename RecordT>
void RefIdDataContainer<RecordT>::erase(int index, int count)
{
if (index < 0 || index + count > getSize())
throw std::runtime_error("invalid RefIdDataContainer index");
mContainer.erase(mContainer.begin() + index, mContainer.begin() + index + count);
}
template <typename RecordT>
ESM::RefId RefIdDataContainer<RecordT>::getId(int index) const
{
return mContainer.at(index)->get().mId;
}
template <typename RecordT>
void RefIdDataContainer<RecordT>::save(int index, ESM::ESMWriter& writer) const
{
const Record<RecordT>& record = *mContainer.at(index);
if (record.isModified() || record.mState == RecordBase::State_Deleted)
{
RecordT esmRecord = record.get();
writer.startRecord(esmRecord.sRecordId, esmRecord.mRecordFlags);
esmRecord.save(writer, record.mState == RecordBase::State_Deleted);
writer.endRecord(esmRecord.sRecordId);
}
}
class RefIdData
{
public:
typedef std::pair<int, UniversalId::Type> LocalIndex;
private:
RefIdDataContainer<ESM::Activator> mActivators;
RefIdDataContainer<ESM::Potion> mPotions;
RefIdDataContainer<ESM::Apparatus> mApparati;
RefIdDataContainer<ESM::Armor> mArmors;
RefIdDataContainer<ESM::Book> mBooks;
RefIdDataContainer<ESM::Clothing> mClothing;
RefIdDataContainer<ESM::Container> mContainers;
RefIdDataContainer<ESM::Creature> mCreatures;
RefIdDataContainer<ESM::Door> mDoors;
RefIdDataContainer<ESM::Ingredient> mIngredients;
RefIdDataContainer<ESM::CreatureLevList> mCreatureLevelledLists;
RefIdDataContainer<ESM::ItemLevList> mItemLevelledLists;
RefIdDataContainer<ESM::Light> mLights;
RefIdDataContainer<ESM::Lockpick> mLockpicks;
RefIdDataContainer<ESM::Miscellaneous> mMiscellaneous;
RefIdDataContainer<ESM::NPC> mNpcs;
RefIdDataContainer<ESM::Probe> mProbes;
RefIdDataContainer<ESM::Repair> mRepairs;
RefIdDataContainer<ESM::Static> mStatics;
RefIdDataContainer<ESM::Weapon> mWeapons;
std::map<ESM::RefId, LocalIndex> mIndex;
std::map<UniversalId::Type, RefIdDataContainerBase*> mRecordContainers;
void erase(const LocalIndex& index, int count);
///< Must not spill over into another type.
ESM::RefId getRecordId(const LocalIndex& index) const;
public:
RefIdData();
LocalIndex globalToLocalIndex(int index) const;
int localToGlobalIndex(const LocalIndex& index) const;
LocalIndex searchId(const ESM::RefId& id) const;
void erase(int index, int count);
void insertRecord(std::unique_ptr<RecordBase> record, CSMWorld::UniversalId::Type type, const ESM::RefId& id);
const RecordBase& getRecord(const LocalIndex& index) const;
RecordBase& getRecord(const LocalIndex& index);
unsigned int getRecordFlags(const ESM::RefId& id) const;
void appendRecord(UniversalId::Type type, const ESM::RefId& id, bool base);
int getAppendIndex(UniversalId::Type type) const;
void load(ESM::ESMReader& reader, bool base, UniversalId::Type type);
int getSize() const;
std::vector<ESM::RefId> getIds(bool listDeleted = true) const;
///< Return a sorted collection of all IDs
///
/// \param listDeleted include deleted record in the list
void save(int index, ESM::ESMWriter& writer) const;
// RECORD CONTAINERS ACCESS METHODS
const RefIdDataContainer<ESM::Book>& getBooks() const;
const RefIdDataContainer<ESM::Activator>& getActivators() const;
const RefIdDataContainer<ESM::Potion>& getPotions() const;
const RefIdDataContainer<ESM::Apparatus>& getApparati() const;
const RefIdDataContainer<ESM::Armor>& getArmors() const;
const RefIdDataContainer<ESM::Clothing>& getClothing() const;
const RefIdDataContainer<ESM::Container>& getContainers() const;
const RefIdDataContainer<ESM::Creature>& getCreatures() const;
const RefIdDataContainer<ESM::Door>& getDoors() const;
const RefIdDataContainer<ESM::Ingredient>& getIngredients() const;
const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const;
const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const;
const RefIdDataContainer<ESM::Light>& getLights() const;
const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const;
const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const;
const RefIdDataContainer<ESM::NPC>& getNPCs() const;
const RefIdDataContainer<ESM::Weapon>& getWeapons() const;
const RefIdDataContainer<ESM::Probe>& getProbes() const;
const RefIdDataContainer<ESM::Repair>& getRepairs() const;
const RefIdDataContainer<ESM::Static>& getStatics() const;
void copyTo(int index, RefIdData& target) const;
};
}
#endif