diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index b2e4d4649a..ed785c38fe 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "../world/data.hpp" #include "../world/idcollection.hpp" @@ -52,6 +53,9 @@ CSMDoc::Saving::Saving(Document& document, const std::filesystem::path& projectP appendStage(new WriteCollectionStage>( mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project)); + appendStage(new WriteCollectionStage>( + mDocument.getData().getSelectionGroups(), mState, CSMWorld::Scope_Project)); + appendStage(new CloseSaveStage(mState)); // save content file diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 981ec5278d..89190023c6 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -333,6 +333,37 @@ namespace CSMWorld return true; } + SelectionGroupColumn::SelectionGroupColumn() + : Column(Columns::ColumnId_SelectionGroupObjects, ColumnBase::Display_None) + { + } + + QVariant SelectionGroupColumn::get(const Record& record) const + { + QVariant data; + QStringList selectionInfo; + const std::vector& instances = record.get().selectedInstances; + + for (std::string instance : instances) + selectionInfo << QString::fromStdString(instance); + data.setValue(selectionInfo); + + return data; + } + + void SelectionGroupColumn::set(Record& record, const QVariant& data) + { + ESM::SelectionGroup record2 = record.get(); + for (const auto& item : data.toStringList()) + record2.selectedInstances.push_back(item.toStdString()); + record.setModified(record2); + } + + bool SelectionGroupColumn::isEditable() const + { + return false; + } + std::optional getSkillIndex(std::string_view value) { int index = ESM::Skill::refIdToIndex(ESM::RefId::stringRefId(value)); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da805d5c6d..74b81cebc1 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -2391,6 +2392,17 @@ namespace CSMWorld void set(Record& record, const QVariant& data) override; bool isEditable() const override; }; + + struct SelectionGroupColumn : public Column + { + SelectionGroupColumn(); + + QVariant get(const Record& record) const override; + + void set(Record& record, const QVariant& data) override; + + bool isEditable() const override; + }; } // This is required to access the type as a QVariant. diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 92f41a2f20..dff8b2d7dd 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -347,6 +347,8 @@ namespace CSMWorld ColumnId_LevelledCreatureId = 315, + ColumnId_SelectionGroupObjects = 316, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index e8fd138ab4..9b137a6602 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -620,6 +620,10 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data mDebugProfiles.addColumn(new DescriptionColumn); mDebugProfiles.addColumn(new ScriptColumn(ScriptColumn::Type_Lines)); + mSelectionGroups.addColumn(new StringIdColumn); + mSelectionGroups.addColumn(new RecordStateColumn); + mSelectionGroups.addColumn(new SelectionGroupColumn); + mMetaData.appendBlankRecord(ESM::RefId::stringRefId("sys::meta")); mMetaData.addColumn(new StringIdColumn(true)); @@ -664,6 +668,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Textures)), UniversalId::Type_Texture); addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Videos)), UniversalId::Type_Video); addModel(new IdTable(&mMetaData), UniversalId::Type_MetaData); + addModel(new IdTable(&mSelectionGroups), UniversalId::Type_SelectionGroup); mActorAdapter = std::make_unique(*this); @@ -908,6 +913,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getDebugProfiles() return mDebugProfiles; } +CSMWorld::IdCollection& CSMWorld::Data::getSelectionGroups() +{ + return mSelectionGroups; +} + +const CSMWorld::IdCollection& CSMWorld::Data::getSelectionGroups() const +{ + return mSelectionGroups; +} + const CSMWorld::IdCollection& CSMWorld::Data::getLand() const { return mLand; @@ -1369,6 +1384,17 @@ bool CSMWorld::Data::continueLoading(CSMDoc::Messages& messages) mDebugProfiles.load(*mReader, mBase); break; + case ESM::REC_SELG: + + if (!mProject) + { + unhandledRecord = true; + break; + } + + mSelectionGroups.load(*mReader, mBase); + break; + default: unhandledRecord = true; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 1b63986eac..8e01452f3b 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -105,6 +106,7 @@ namespace CSMWorld IdCollection mBodyParts; IdCollection mMagicEffects; IdCollection mDebugProfiles; + IdCollection mSelectionGroups; IdCollection mSoundGens; IdCollection mStartScripts; NestedInfoCollection mTopicInfos; @@ -251,6 +253,10 @@ namespace CSMWorld IdCollection& getDebugProfiles(); + const IdCollection& getSelectionGroups() const; + + IdCollection& getSelectionGroups(); + const IdCollection& getLand() const; IdCollection& getLand(); diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index dec533b015..0a6b9c8e7c 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -68,6 +68,7 @@ namespace ":./resources-video" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", ":./debug-profile.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SelectionGroup, "Selection Groups", "" }, { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":./run-log.png" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", ":./sound-generator.png" }, diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 2d3385bcb4..6bee62cf93 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -133,6 +133,7 @@ namespace CSMWorld Type_LandTexture, Type_Pathgrids, Type_Pathgrid, + Type_SelectionGroup, Type_StartScripts, Type_StartScript, Type_Search, diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 6254830f63..cbc70582c0 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -170,6 +170,8 @@ namespace ESM // format 1 REC_FILT = esm3Recname("FILT"), REC_DBGP = esm3Recname("DBGP"), ///< only used in project files + REC_SELG = esm3Recname("SELG"), + REC_LUAL = esm3Recname("LUAL"), // LuaScriptsCfg (only in omwgame or omwaddon) // format 16 - Lua scripts in saved games