#include "data.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../doc/messages.hpp" #include "columnimp.hpp" #include "columns.hpp" #include "idtable.hpp" #include "idtree.hpp" #include "nestedcoladapterimp.hpp" #include "regionmap.hpp" #include "resourcesmanager.hpp" #include "resourcetable.hpp" void CSMWorld::Data::addModel(QAbstractItemModel* model, UniversalId::Type type, bool update) { mModels.push_back(model); mModelIndex.insert(std::make_pair(type, model)); UniversalId::Type type2 = UniversalId::getParentType(type); if (type2 != UniversalId::Type_None) mModelIndex.insert(std::make_pair(type2, model)); if (update) { connect(model, &QAbstractItemModel::dataChanged, this, &Data::dataChanged); connect(model, &QAbstractItemModel::rowsInserted, this, &Data::rowsChanged); connect(model, &QAbstractItemModel::rowsRemoved, this, &Data::rowsChanged); } } void CSMWorld::Data::appendIds(std::vector& ids, const CollectionBase& collection, bool listDeleted) { std::vector ids2 = collection.getIds(listDeleted); ids.insert(ids.end(), ids2.begin(), ids2.end()); } int CSMWorld::Data::count(RecordBase::State state, const CollectionBase& collection) { int number = 0; for (int i = 0; i < collection.getSize(); ++i) if (collection.getRecord(i).mState == state) ++number; return number; } CSMWorld::Data::Data(ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives, const std::filesystem::path& resDir) : mEncoder(encoding) , mPathgrids(mCells) , mRefs(mCells) , mReader(nullptr) , mDialogue(nullptr) , mReaderIndex(1) , mFsStrict(fsStrict) , mDataPaths(dataPaths) , mArchives(archives) { mVFS = std::make_unique(mFsStrict); VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); mResourcesManager.setVFS(mVFS.get()); mResourceSystem = std::make_unique(mVFS.get()); Shader::ShaderManager::DefineMap defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); Shader::ShaderManager::DefineMap shadowDefines = SceneUtil::ShadowManager::getShadowsDisabledDefines(); defines["forcePPL"] = "0"; // Don't force per-pixel lighting defines["clamp"] = "1"; // Clamp lighting defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind defines["radialFog"] = "0"; defines["lightingModel"] = "0"; defines["reverseZ"] = "0"; defines["refraction_enabled"] = "0"; for (const auto& define : shadowDefines) defines[define.first] = define.second; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); mResourceSystem->getSceneManager()->setShaderPath(resDir / "shaders"); int index = 0; mGlobals.addColumn(new StringIdColumn); mGlobals.addColumn(new RecordStateColumn); mGlobals.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Global)); mGlobals.addColumn(new VarTypeColumn(ColumnBase::Display_GlobalVarType)); mGlobals.addColumn(new VarValueColumn); mGmsts.addColumn(new StringIdColumn); mGmsts.addColumn(new RecordStateColumn); mGmsts.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Gmst)); mGmsts.addColumn(new VarTypeColumn(ColumnBase::Display_GmstVarType)); mGmsts.addColumn(new VarValueColumn); mSkills.addColumn(new StringIdColumn); mSkills.addColumn(new RecordStateColumn); mSkills.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Skill)); mSkills.addColumn(new AttributeColumn); mSkills.addColumn(new SpecialisationColumn); for (int i = 0; i < 4; ++i) mSkills.addColumn(new UseValueColumn(i)); mSkills.addColumn(new DescriptionColumn); mClasses.addColumn(new StringIdColumn); mClasses.addColumn(new RecordStateColumn); mClasses.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Class)); mClasses.addColumn(new NameColumn); mClasses.addColumn(new AttributesColumn(0)); mClasses.addColumn(new AttributesColumn(1)); mClasses.addColumn(new SpecialisationColumn); for (int i = 0; i < 5; ++i) mClasses.addColumn(new SkillsColumn(i, true, true)); for (int i = 0; i < 5; ++i) mClasses.addColumn(new SkillsColumn(i, true, false)); mClasses.addColumn(new PlayableColumn); mClasses.addColumn(new DescriptionColumn); mFactions.addColumn(new StringIdColumn); mFactions.addColumn(new RecordStateColumn); mFactions.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Faction)); mFactions.addColumn(new NameColumn(ColumnBase::Display_String32)); mFactions.addColumn(new AttributesColumn(0)); mFactions.addColumn(new AttributesColumn(1)); mFactions.addColumn(new HiddenColumn); for (int i = 0; i < 7; ++i) mFactions.addColumn(new SkillsColumn(i)); // Faction Reactions mFactions.addColumn(new NestedParentColumn(Columns::ColumnId_FactionReactions)); index = mFactions.getColumns() - 1; mFactions.addAdapter(std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter())); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Faction, ColumnBase::Display_Faction)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); // Faction Ranks mFactions.addColumn(new NestedParentColumn(Columns::ColumnId_FactionRanks)); index = mFactions.getColumns() - 1; mFactions.addAdapter(std::make_pair(&mFactions.getColumn(index), new FactionRanksAdapter())); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_RankName, ColumnBase::Display_Rank)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FactionAttrib1, ColumnBase::Display_Integer)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FactionAttrib2, ColumnBase::Display_Integer)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FactionPrimSkill, ColumnBase::Display_Integer)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FactionFavSkill, ColumnBase::Display_Integer)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FactionRep, ColumnBase::Display_Integer)); mRaces.addColumn(new StringIdColumn); mRaces.addColumn(new RecordStateColumn); mRaces.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Race)); mRaces.addColumn(new NameColumn); mRaces.addColumn(new DescriptionColumn); mRaces.addColumn(new FlagColumn(Columns::ColumnId_Playable, 0x1)); mRaces.addColumn(new FlagColumn(Columns::ColumnId_BeastRace, 0x2)); mRaces.addColumn(new WeightHeightColumn(true, true)); mRaces.addColumn(new WeightHeightColumn(true, false)); mRaces.addColumn(new WeightHeightColumn(false, true)); mRaces.addColumn(new WeightHeightColumn(false, false)); // Race spells mRaces.addColumn(new NestedParentColumn(Columns::ColumnId_PowerList)); index = mRaces.getColumns() - 1; mRaces.addAdapter(std::make_pair(&mRaces.getColumn(index), new SpellListAdapter())); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); // Race attributes mRaces.addColumn(new NestedParentColumn( Columns::ColumnId_RaceAttributes, ColumnBase::Flag_Dialogue, true)); // fixed rows table index = mRaces.getColumns() - 1; mRaces.addAdapter(std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn(new NestedChildColumn( Columns::ColumnId_Attribute, ColumnBase::Display_Attribute, ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Male, ColumnBase::Display_Integer)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Female, ColumnBase::Display_Integer)); // Race skill bonus mRaces.addColumn(new NestedParentColumn( Columns::ColumnId_RaceSkillBonus, ColumnBase::Flag_Dialogue, true)); // fixed rows table index = mRaces.getColumns() - 1; mRaces.addAdapter(std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); mSounds.addColumn(new StringIdColumn); mSounds.addColumn(new RecordStateColumn); mSounds.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Sound)); mSounds.addColumn(new SoundParamColumn(SoundParamColumn::Type_Volume)); mSounds.addColumn(new SoundParamColumn(SoundParamColumn::Type_MinRange)); mSounds.addColumn(new SoundParamColumn(SoundParamColumn::Type_MaxRange)); mSounds.addColumn(new SoundFileColumn); mScripts.addColumn(new StringIdColumn); mScripts.addColumn(new RecordStateColumn); mScripts.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Script)); mScripts.addColumn(new ScriptColumn(ScriptColumn::Type_File)); mRegions.addColumn(new StringIdColumn); mRegions.addColumn(new RecordStateColumn); mRegions.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Region)); mRegions.addColumn(new NameColumn); mRegions.addColumn(new MapColourColumn); mRegions.addColumn(new SleepListColumn); // Region Weather mRegions.addColumn(new NestedParentColumn(Columns::ColumnId_RegionWeather)); index = mRegions.getColumns() - 1; mRegions.addAdapter(std::make_pair(&mRegions.getColumn(index), new RegionWeatherAdapter())); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_WeatherName, ColumnBase::Display_String, false)); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_WeatherChance, ColumnBase::Display_UnsignedInteger8)); // Region Sounds mRegions.addColumn(new NestedParentColumn(Columns::ColumnId_RegionSounds)); index = mRegions.getColumns() - 1; mRegions.addAdapter(std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter())); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_SoundName, ColumnBase::Display_Sound)); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_SoundChance, ColumnBase::Display_UnsignedInteger8)); mBirthsigns.addColumn(new StringIdColumn); mBirthsigns.addColumn(new RecordStateColumn); mBirthsigns.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Birthsign)); mBirthsigns.addColumn(new NameColumn); mBirthsigns.addColumn(new TextureColumn); mBirthsigns.addColumn(new DescriptionColumn); // Birthsign spells mBirthsigns.addColumn(new NestedParentColumn(Columns::ColumnId_PowerList)); index = mBirthsigns.getColumns() - 1; mBirthsigns.addAdapter(std::make_pair(&mBirthsigns.getColumn(index), new SpellListAdapter())); mBirthsigns.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); mSpells.addColumn(new StringIdColumn); mSpells.addColumn(new RecordStateColumn); mSpells.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Spell)); mSpells.addColumn(new NameColumn); mSpells.addColumn(new SpellTypeColumn); mSpells.addColumn(new CostColumn); mSpells.addColumn(new FlagColumn(Columns::ColumnId_AutoCalc, 0x1)); mSpells.addColumn(new FlagColumn(Columns::ColumnId_StarterSpell, 0x2)); mSpells.addColumn(new FlagColumn(Columns::ColumnId_AlwaysSucceeds, 0x4)); // Spell effects mSpells.addColumn(new NestedParentColumn(Columns::ColumnId_EffectList)); index = mSpells.getColumns() - 1; mSpells.addAdapter(std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter())); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mTopics.addColumn(new StringIdColumn); mTopics.addColumn(new RecordStateColumn); mTopics.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Topic)); mTopics.addColumn(new DialogueTypeColumn); mJournals.addColumn(new StringIdColumn); mJournals.addColumn(new RecordStateColumn); mJournals.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Journal)); mJournals.addColumn(new DialogueTypeColumn(true)); mTopicInfos.addColumn(new StringIdColumn(true)); mTopicInfos.addColumn(new RecordStateColumn); mTopicInfos.addColumn(new FixedRecordTypeColumn(UniversalId::Type_TopicInfo)); mTopicInfos.addColumn(new TopicColumn(false)); mTopicInfos.addColumn(new ActorColumn); mTopicInfos.addColumn(new RaceColumn); mTopicInfos.addColumn(new ClassColumn); mTopicInfos.addColumn(new FactionColumn); mTopicInfos.addColumn(new CellColumn); mTopicInfos.addColumn(new DispositionColumn); mTopicInfos.addColumn(new RankColumn); mTopicInfos.addColumn(new GenderColumn); mTopicInfos.addColumn(new PcFactionColumn); mTopicInfos.addColumn(new PcRankColumn); mTopicInfos.addColumn(new SoundFileColumn); mTopicInfos.addColumn(new ResponseColumn); // Result script mTopicInfos.addColumn(new NestedParentColumn( Columns::ColumnId_InfoList, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); index = mTopicInfos.getColumns() - 1; mTopicInfos.addAdapter(std::make_pair(&mTopicInfos.getColumn(index), new InfoListAdapter())); mTopicInfos.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_ScriptText, ColumnBase::Display_ScriptLines)); // Special conditions mTopicInfos.addColumn(new NestedParentColumn(Columns::ColumnId_InfoCondition)); index = mTopicInfos.getColumns() - 1; mTopicInfos.addAdapter(std::make_pair(&mTopicInfos.getColumn(index), new InfoConditionAdapter())); mTopicInfos.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_InfoCondFunc, ColumnBase::Display_InfoCondFunc)); // FIXME: don't have dynamic value enum delegate, use Display_String for now mTopicInfos.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_InfoCondVar, ColumnBase::Display_InfoCondVar)); mTopicInfos.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_InfoCondComp, ColumnBase::Display_InfoCondComp)); mTopicInfos.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Value, ColumnBase::Display_Var)); mJournalInfos.addColumn(new StringIdColumn(true)); mJournalInfos.addColumn(new RecordStateColumn); mJournalInfos.addColumn(new FixedRecordTypeColumn(UniversalId::Type_JournalInfo)); mJournalInfos.addColumn(new TopicColumn(true)); mJournalInfos.addColumn(new QuestStatusTypeColumn); mJournalInfos.addColumn(new QuestIndexColumn); mJournalInfos.addColumn(new QuestDescriptionColumn); mCells.addColumn(new StringIdColumn); mCells.addColumn(new RecordStateColumn); mCells.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Cell)); mCells.addColumn(new NameColumn(ColumnBase::Display_String64)); mCells.addColumn(new FlagColumn(Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); mCells.addColumn(new FlagColumn(Columns::ColumnId_InteriorWater, ESM::Cell::HasWater, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); mCells.addColumn(new FlagColumn(Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); mCells.addColumn(new RegionColumn); mCells.addColumn(new RefNumCounterColumn); // Misc Cell data mCells.addColumn(new NestedParentColumn( Columns::ColumnId_Cell, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); index = mCells.getColumns() - 1; mCells.addAdapter(std::make_pair(&mCells.getColumn(index), new CellListAdapter())); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Interior, ColumnBase::Display_Boolean, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Ambient, ColumnBase::Display_Colour)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Sunlight, ColumnBase::Display_Colour)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Fog, ColumnBase::Display_Colour)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_FogDensity, ColumnBase::Display_Float)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_WaterLevel, ColumnBase::Display_Float)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_MapColor, ColumnBase::Display_Colour)); mEnchantments.addColumn(new StringIdColumn); mEnchantments.addColumn(new RecordStateColumn); mEnchantments.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Enchantment)); mEnchantments.addColumn(new EnchantmentTypeColumn); mEnchantments.addColumn(new CostColumn); mEnchantments.addColumn(new ChargesColumn2); mEnchantments.addColumn(new FlagColumn(Columns::ColumnId_AutoCalc, ESM::Enchantment::Autocalc)); // Enchantment effects mEnchantments.addColumn(new NestedParentColumn(Columns::ColumnId_EffectList)); index = mEnchantments.getColumns() - 1; mEnchantments.addAdapter( std::make_pair(&mEnchantments.getColumn(index), new EffectsListAdapter())); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mBodyParts.addColumn(new StringIdColumn); mBodyParts.addColumn(new RecordStateColumn); mBodyParts.addColumn(new FixedRecordTypeColumn(UniversalId::Type_BodyPart)); mBodyParts.addColumn(new BodyPartTypeColumn); mBodyParts.addColumn(new VampireColumn); mBodyParts.addColumn(new GenderNpcColumn); mBodyParts.addColumn(new FlagColumn(Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true)); int meshTypeFlags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh; MeshTypeColumn* meshTypeColumn = new MeshTypeColumn(meshTypeFlags); mBodyParts.addColumn(meshTypeColumn); mBodyParts.addColumn(new ModelColumn); mBodyParts.addColumn(new BodyPartRaceColumn(meshTypeColumn)); mSoundGens.addColumn(new StringIdColumn); mSoundGens.addColumn(new RecordStateColumn); mSoundGens.addColumn(new FixedRecordTypeColumn(UniversalId::Type_SoundGen)); mSoundGens.addColumn(new CreatureColumn); mSoundGens.addColumn(new SoundColumn); mSoundGens.addColumn(new SoundGeneratorTypeColumn); mMagicEffects.addColumn(new StringIdColumn); mMagicEffects.addColumn(new RecordStateColumn); mMagicEffects.addColumn(new FixedRecordTypeColumn(UniversalId::Type_MagicEffect)); mMagicEffects.addColumn(new SchoolColumn); mMagicEffects.addColumn(new BaseCostColumn); mMagicEffects.addColumn(new EffectTextureColumn(Columns::ColumnId_Icon)); mMagicEffects.addColumn(new EffectTextureColumn(Columns::ColumnId_Particle)); mMagicEffects.addColumn(new EffectObjectColumn(Columns::ColumnId_CastingObject)); mMagicEffects.addColumn(new EffectObjectColumn(Columns::ColumnId_HitObject)); mMagicEffects.addColumn(new EffectObjectColumn(Columns::ColumnId_AreaObject)); mMagicEffects.addColumn(new EffectObjectColumn(Columns::ColumnId_BoltObject)); mMagicEffects.addColumn(new EffectSoundColumn(Columns::ColumnId_CastingSound)); mMagicEffects.addColumn(new EffectSoundColumn(Columns::ColumnId_HitSound)); mMagicEffects.addColumn(new EffectSoundColumn(Columns::ColumnId_AreaSound)); mMagicEffects.addColumn(new EffectSoundColumn(Columns::ColumnId_BoltSound)); mMagicEffects.addColumn( new FlagColumn(Columns::ColumnId_AllowSpellmaking, ESM::MagicEffect::AllowSpellmaking)); mMagicEffects.addColumn( new FlagColumn(Columns::ColumnId_AllowEnchanting, ESM::MagicEffect::AllowEnchanting)); mMagicEffects.addColumn( new FlagColumn(Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight)); mMagicEffects.addColumn(new DescriptionColumn); mLand.addColumn(new StringIdColumn); mLand.addColumn(new RecordStateColumn); mLand.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn(new LandPluginIndexColumn); mLand.addColumn(new LandNormalsColumn); mLand.addColumn(new LandHeightsColumn); mLand.addColumn(new LandColoursColumn); mLand.addColumn(new LandTexturesColumn); mLandTextures.addColumn(new StringIdColumn(true)); mLandTextures.addColumn(new RecordStateColumn); mLandTextures.addColumn(new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); mLandTextures.addColumn(new LandTextureNicknameColumn); mLandTextures.addColumn(new LandTexturePluginIndexColumn); mLandTextures.addColumn(new LandTextureIndexColumn); mLandTextures.addColumn(new TextureColumn); mPathgrids.addColumn(new StringIdColumn); mPathgrids.addColumn(new RecordStateColumn); mPathgrids.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Pathgrid)); // new object deleted in dtor of Collection mPathgrids.addColumn(new NestedParentColumn(Columns::ColumnId_PathgridPoints)); index = mPathgrids.getColumns() - 1; // new object deleted in dtor of NestedCollection mPathgrids.addAdapter(std::make_pair(&mPathgrids.getColumn(index), new PathgridPointListAdapter())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter mPathgrids.getNestableColumn(index)->addColumn(new NestedChildColumn( Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue, false)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_PathgridPosX, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_PathgridPosY, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_PathgridPosZ, ColumnBase::Display_Integer)); mPathgrids.addColumn(new NestedParentColumn(Columns::ColumnId_PathgridEdges)); index = mPathgrids.getColumns() - 1; mPathgrids.addAdapter(std::make_pair(&mPathgrids.getColumn(index), new PathgridEdgeListAdapter())); mPathgrids.getNestableColumn(index)->addColumn(new NestedChildColumn( Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue, false)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_PathgridEdge0, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn(Columns::ColumnId_PathgridEdge1, ColumnBase::Display_Integer)); mStartScripts.addColumn(new StringIdColumn); mStartScripts.addColumn(new RecordStateColumn); mStartScripts.addColumn(new FixedRecordTypeColumn(UniversalId::Type_StartScript)); mRefs.addColumn(new StringIdColumn(true)); mRefs.addColumn(new RecordStateColumn); mRefs.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Reference)); mRefs.addColumn(new CellColumn(true)); mRefs.addColumn(new OriginalCellColumn); mRefs.addColumn(new IdColumn); mRefs.addColumn(new PosColumn(&CellRef::mPos, 0, false)); mRefs.addColumn(new PosColumn(&CellRef::mPos, 1, false)); mRefs.addColumn(new PosColumn(&CellRef::mPos, 2, false)); mRefs.addColumn(new RotColumn(&CellRef::mPos, 0, false)); mRefs.addColumn(new RotColumn(&CellRef::mPos, 1, false)); mRefs.addColumn(new RotColumn(&CellRef::mPos, 2, false)); mRefs.addColumn(new ScaleColumn); mRefs.addColumn(new OwnerColumn); mRefs.addColumn(new SoulColumn); mRefs.addColumn(new FactionColumn); mRefs.addColumn(new FactionIndexColumn); mRefs.addColumn(new ChargesColumn); mRefs.addColumn(new EnchantmentChargesColumn); mRefs.addColumn(new GoldValueColumn); mRefs.addColumn(new TeleportColumn); mRefs.addColumn(new TeleportCellColumn); mRefs.addColumn(new PosColumn(&CellRef::mDoorDest, 0, true)); mRefs.addColumn(new PosColumn(&CellRef::mDoorDest, 1, true)); mRefs.addColumn(new PosColumn(&CellRef::mDoorDest, 2, true)); mRefs.addColumn(new RotColumn(&CellRef::mDoorDest, 0, true)); mRefs.addColumn(new RotColumn(&CellRef::mDoorDest, 1, true)); mRefs.addColumn(new RotColumn(&CellRef::mDoorDest, 2, true)); mRefs.addColumn(new LockLevelColumn); mRefs.addColumn(new KeyColumn); mRefs.addColumn(new TrapColumn); mRefs.addColumn(new OwnerGlobalColumn); mRefs.addColumn(new RefNumColumn); mFilters.addColumn(new StringIdColumn); mFilters.addColumn(new RecordStateColumn); mFilters.addColumn(new FixedRecordTypeColumn(UniversalId::Type_Filter)); mFilters.addColumn(new FilterColumn); mFilters.addColumn(new DescriptionColumn); mDebugProfiles.addColumn(new StringIdColumn); mDebugProfiles.addColumn(new RecordStateColumn); mDebugProfiles.addColumn(new FixedRecordTypeColumn(UniversalId::Type_DebugProfile)); mDebugProfiles.addColumn( new FlagColumn2(Columns::ColumnId_DefaultProfile, ESM::DebugProfile::Flag_Default)); mDebugProfiles.addColumn( new FlagColumn2(Columns::ColumnId_BypassNewGame, ESM::DebugProfile::Flag_BypassNewGame)); mDebugProfiles.addColumn( new FlagColumn2(Columns::ColumnId_GlobalProfile, ESM::DebugProfile::Flag_Global)); mDebugProfiles.addColumn(new DescriptionColumn); mDebugProfiles.addColumn(new ScriptColumn(ScriptColumn::Type_Lines)); mMetaData.appendBlankRecord(ESM::RefId::stringRefId("sys::meta")); mMetaData.addColumn(new StringIdColumn(true)); mMetaData.addColumn(new RecordStateColumn); mMetaData.addColumn(new FixedRecordTypeColumn(UniversalId::Type_MetaData)); mMetaData.addColumn(new FormatColumn); mMetaData.addColumn(new AuthorColumn); mMetaData.addColumn(new FileDescriptionColumn); addModel(new IdTable(&mGlobals), UniversalId::Type_Global); addModel(new IdTable(&mGmsts), UniversalId::Type_Gmst); addModel(new IdTable(&mSkills), UniversalId::Type_Skill); addModel(new IdTable(&mClasses), UniversalId::Type_Class); addModel(new IdTree(&mFactions, &mFactions), UniversalId::Type_Faction); addModel(new IdTree(&mRaces, &mRaces), UniversalId::Type_Race); addModel(new IdTable(&mSounds), UniversalId::Type_Sound); addModel(new IdTable(&mScripts), UniversalId::Type_Script); addModel(new IdTree(&mRegions, &mRegions), UniversalId::Type_Region); addModel(new IdTree(&mBirthsigns, &mBirthsigns), UniversalId::Type_Birthsign); addModel(new IdTree(&mSpells, &mSpells), UniversalId::Type_Spell); addModel(new IdTable(&mTopics), UniversalId::Type_Topic); addModel(new IdTable(&mJournals), UniversalId::Type_Journal); addModel(new IdTree(&mTopicInfos, &mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); addModel(new IdTable(&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); addModel(new IdTree(&mCells, &mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); addModel(new IdTree(&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); addModel(new IdTable(&mBodyParts), UniversalId::Type_BodyPart); addModel(new IdTable(&mSoundGens), UniversalId::Type_SoundGen); addModel(new IdTable(&mMagicEffects), UniversalId::Type_MagicEffect); addModel(new IdTable(&mLand, IdTable::Feature_AllowTouch), UniversalId::Type_Land); addModel(new LandTextureIdTable(&mLandTextures), UniversalId::Type_LandTexture); addModel(new IdTree(&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel(new IdTable(&mStartScripts), UniversalId::Type_StartScript); addModel(new IdTree(&mReferenceables, &mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel(new IdTable(&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel(new IdTable(&mFilters), UniversalId::Type_Filter); addModel(new IdTable(&mDebugProfiles), UniversalId::Type_DebugProfile); addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Meshes)), UniversalId::Type_Mesh); addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Icons)), UniversalId::Type_Icon); addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Musics)), UniversalId::Type_Music); addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_SoundsRes)), UniversalId::Type_SoundRes); 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); mActorAdapter = std::make_unique(*this); mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files } CSMWorld::Data::~Data() { for (std::vector::iterator iter(mModels.begin()); iter != mModels.end(); ++iter) delete *iter; delete mReader; } std::shared_ptr CSMWorld::Data::getResourceSystem() { return mResourceSystem; } std::shared_ptr CSMWorld::Data::getResourceSystem() const { return mResourceSystem; } const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const { return mGlobals; } CSMWorld::IdCollection& CSMWorld::Data::getGlobals() { return mGlobals; } const CSMWorld::IdCollection& CSMWorld::Data::getGmsts() const { return mGmsts; } CSMWorld::IdCollection& CSMWorld::Data::getGmsts() { return mGmsts; } const CSMWorld::IdCollection& CSMWorld::Data::getSkills() const { return mSkills; } CSMWorld::IdCollection& CSMWorld::Data::getSkills() { return mSkills; } const CSMWorld::IdCollection& CSMWorld::Data::getClasses() const { return mClasses; } CSMWorld::IdCollection& CSMWorld::Data::getClasses() { return mClasses; } const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const { return mFactions; } CSMWorld::IdCollection& CSMWorld::Data::getFactions() { return mFactions; } const CSMWorld::IdCollection& CSMWorld::Data::getRaces() const { return mRaces; } CSMWorld::IdCollection& CSMWorld::Data::getRaces() { return mRaces; } const CSMWorld::IdCollection& CSMWorld::Data::getSounds() const { return mSounds; } CSMWorld::IdCollection& CSMWorld::Data::getSounds() { return mSounds; } const CSMWorld::IdCollection& CSMWorld::Data::getScripts() const { return mScripts; } CSMWorld::IdCollection& CSMWorld::Data::getScripts() { return mScripts; } const CSMWorld::IdCollection& CSMWorld::Data::getRegions() const { return mRegions; } CSMWorld::IdCollection& CSMWorld::Data::getRegions() { return mRegions; } const CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() const { return mBirthsigns; } CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() { return mBirthsigns; } const CSMWorld::IdCollection& CSMWorld::Data::getSpells() const { return mSpells; } CSMWorld::IdCollection& CSMWorld::Data::getSpells() { return mSpells; } const CSMWorld::IdCollection& CSMWorld::Data::getTopics() const { return mTopics; } CSMWorld::IdCollection& CSMWorld::Data::getTopics() { return mTopics; } const CSMWorld::IdCollection& CSMWorld::Data::getJournals() const { return mJournals; } CSMWorld::IdCollection& CSMWorld::Data::getJournals() { return mJournals; } const CSMWorld::InfoCollection& CSMWorld::Data::getTopicInfos() const { return mTopicInfos; } CSMWorld::InfoCollection& CSMWorld::Data::getTopicInfos() { return mTopicInfos; } const CSMWorld::InfoCollection& CSMWorld::Data::getJournalInfos() const { return mJournalInfos; } CSMWorld::InfoCollection& CSMWorld::Data::getJournalInfos() { return mJournalInfos; } const CSMWorld::IdCollection& CSMWorld::Data::getCells() const { return mCells; } CSMWorld::IdCollection& CSMWorld::Data::getCells() { return mCells; } const CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables() const { return mReferenceables; } CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables() { return mReferenceables; } const CSMWorld::RefCollection& CSMWorld::Data::getReferences() const { return mRefs; } CSMWorld::RefCollection& CSMWorld::Data::getReferences() { return mRefs; } const CSMWorld::IdCollection& CSMWorld::Data::getFilters() const { return mFilters; } CSMWorld::IdCollection& CSMWorld::Data::getFilters() { return mFilters; } const CSMWorld::IdCollection& CSMWorld::Data::getEnchantments() const { return mEnchantments; } CSMWorld::IdCollection& CSMWorld::Data::getEnchantments() { return mEnchantments; } const CSMWorld::IdCollection& CSMWorld::Data::getBodyParts() const { return mBodyParts; } CSMWorld::IdCollection& CSMWorld::Data::getBodyParts() { return mBodyParts; } const CSMWorld::IdCollection& CSMWorld::Data::getDebugProfiles() const { return mDebugProfiles; } CSMWorld::IdCollection& CSMWorld::Data::getDebugProfiles() { return mDebugProfiles; } const CSMWorld::IdCollection& CSMWorld::Data::getLand() const { return mLand; } CSMWorld::IdCollection& CSMWorld::Data::getLand() { return mLand; } const CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() const { return mLandTextures; } CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() { return mLandTextures; } const CSMWorld::IdCollection& CSMWorld::Data::getSoundGens() const { return mSoundGens; } CSMWorld::IdCollection& CSMWorld::Data::getSoundGens() { return mSoundGens; } const CSMWorld::IdCollection& CSMWorld::Data::getMagicEffects() const { return mMagicEffects; } CSMWorld::IdCollection& CSMWorld::Data::getMagicEffects() { return mMagicEffects; } const CSMWorld::SubCellCollection& CSMWorld::Data::getPathgrids() const { return mPathgrids; } CSMWorld::SubCellCollection& CSMWorld::Data::getPathgrids() { return mPathgrids; } const CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() const { return mStartScripts; } CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() { return mStartScripts; } const CSMWorld::Resources& CSMWorld::Data::getResources(const UniversalId& id) const { return mResourcesManager.get(id.getType()); } const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const { return mMetaData.getRecord(0).get(); } void CSMWorld::Data::setMetaData(const MetaData& metaData) { mMetaData.setRecord( 0, std::make_unique>(Record(RecordBase::State_ModifiedOnly, nullptr, &metaData))); } QAbstractItemModel* CSMWorld::Data::getTableModel(const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find(id.getType()); if (iter == mModelIndex.end()) { // try creating missing (secondary) tables on the fly // // Note: We create these tables here so we don't have to deal with them during load/initial // construction of the ESX data where no update signals are available. if (id.getType() == UniversalId::Type_RegionMap) { RegionMap* table = nullptr; addModel(table = new RegionMap(*this), UniversalId::Type_RegionMap, false); return table; } throw std::logic_error("No table model available for " + id.toString()); } return iter->second; } const CSMWorld::ActorAdapter* CSMWorld::Data::getActorAdapter() const { return mActorAdapter.get(); } CSMWorld::ActorAdapter* CSMWorld::Data::getActorAdapter() { return mActorAdapter.get(); } void CSMWorld::Data::merge() { mGlobals.merge(); } int CSMWorld::Data::getTotalRecords(const std::vector& files) { int records = 0; std::unique_ptr reader = std::make_unique(); for (unsigned int i = 0; i < files.size(); ++i) { if (!std::filesystem::exists(files[i])) continue; reader->open(files[i]); records += reader->getRecordCount(); reader->close(); } return records; } int CSMWorld::Data::startLoading(const std::filesystem::path& path, bool base, bool project) { // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading std::shared_ptr ptr(mReader); mReaders.push_back(ptr); mReader = nullptr; mDialogue = nullptr; mReader = new ESM::ESMReader; mReader->setEncoder(&mEncoder); mReader->setIndex((project || !base) ? 0 : mReaderIndex++); mReader->open(path); mBase = base; mProject = project; if (!mProject && !mBase) { MetaData metaData; metaData.mId = ESM::RefId::stringRefId("sys::meta"); metaData.load(*mReader); mMetaData.setRecord(0, std::make_unique>(Record(RecordBase::State_ModifiedOnly, nullptr, &metaData))); } return mReader->getRecordCount(); } void CSMWorld::Data::loadFallbackEntries() { // Load default marker definitions, if game files do not have them for some reason std::pair staticMarkers[] = { std::make_pair("DivineMarker", "marker_divine.nif"), std::make_pair("DoorMarker", "marker_arrow.nif"), std::make_pair("NorthMarker", "marker_north.nif"), std::make_pair("TempleMarker", "marker_temple.nif"), std::make_pair("TravelMarker", "marker_travel.nif") }; std::pair doorMarkers[] = { std::make_pair("PrisonMarker", "marker_prison.nif") }; for (const auto& marker : staticMarkers) { if (mReferenceables.searchId(marker.first) == -1) { ESM::Static newMarker; newMarker.mId = ESM::RefId::stringRefId(marker.first); newMarker.mModel = marker.second; newMarker.mRecordFlags = 0; auto record = std::make_unique>(); record->mBase = newMarker; record->mState = CSMWorld::RecordBase::State_BaseOnly; mReferenceables.appendRecord(std::move(record), CSMWorld::UniversalId::Type_Static); } } for (const auto& marker : doorMarkers) { if (mReferenceables.searchId(marker.first) == -1) { ESM::Door newMarker; newMarker.mId = ESM::RefId::stringRefId(marker.first); newMarker.mModel = marker.second; newMarker.mRecordFlags = 0; auto record = std::make_unique>(); record->mBase = newMarker; record->mState = CSMWorld::RecordBase::State_BaseOnly; mReferenceables.appendRecord(std::move(record), CSMWorld::UniversalId::Type_Door); } } } bool CSMWorld::Data::continueLoading(CSMDoc::Messages& messages) { if (!mReader) throw std::logic_error("can't continue loading, because no load has been started"); if (!mReader->hasMoreRecs()) { if (mBase) { // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand // loading. We don't store non-base reader, because everything going into modified will be fully loaded // during the initial loading process. std::shared_ptr ptr(mReader); mReaders.push_back(ptr); } else delete mReader; mReader = nullptr; mDialogue = nullptr; loadFallbackEntries(); return true; } ESM::NAME n = mReader->getRecName(); mReader->getRecHeader(); bool unhandledRecord = false; switch (n.toInt()) { case ESM::REC_GLOB: mGlobals.load(*mReader, mBase); break; case ESM::REC_GMST: mGmsts.load(*mReader, mBase); break; case ESM::REC_SKIL: mSkills.load(*mReader, mBase); break; case ESM::REC_CLAS: mClasses.load(*mReader, mBase); break; case ESM::REC_FACT: mFactions.load(*mReader, mBase); break; case ESM::REC_RACE: mRaces.load(*mReader, mBase); break; case ESM::REC_SOUN: mSounds.load(*mReader, mBase); break; case ESM::REC_SCPT: mScripts.load(*mReader, mBase); break; case ESM::REC_REGN: mRegions.load(*mReader, mBase); break; case ESM::REC_BSGN: mBirthsigns.load(*mReader, mBase); break; case ESM::REC_SPEL: mSpells.load(*mReader, mBase); break; case ESM::REC_ENCH: mEnchantments.load(*mReader, mBase); break; case ESM::REC_BODY: mBodyParts.load(*mReader, mBase); break; case ESM::REC_SNDG: mSoundGens.load(*mReader, mBase); break; case ESM::REC_MGEF: mMagicEffects.load(*mReader, mBase); break; case ESM::REC_PGRD: mPathgrids.load(*mReader, mBase); break; case ESM::REC_SSCR: mStartScripts.load(*mReader, mBase); break; case ESM::REC_LTEX: mLandTextures.load(*mReader, mBase); break; case ESM::REC_LAND: mLand.load(*mReader, mBase); break; case ESM::REC_CELL: { int index = mCells.load(*mReader, mBase); if (index < 0 || index >= mCells.getSize()) { // log an error and continue loading the refs to the last loaded cell CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_None); messages.add(id, "Logic error: cell index out of bounds", "", CSMDoc::Message::Severity_Error); index = mCells.getSize() - 1; } std::string cellId = mCells.getId(index).getRefIdString();; mRefs.load(*mReader, index, mBase, mRefLoadCache[cellId], messages); break; } case ESM::REC_ACTI: mReferenceables.load(*mReader, mBase, UniversalId::Type_Activator); break; case ESM::REC_ALCH: mReferenceables.load(*mReader, mBase, UniversalId::Type_Potion); break; case ESM::REC_APPA: mReferenceables.load(*mReader, mBase, UniversalId::Type_Apparatus); break; case ESM::REC_ARMO: mReferenceables.load(*mReader, mBase, UniversalId::Type_Armor); break; case ESM::REC_BOOK: mReferenceables.load(*mReader, mBase, UniversalId::Type_Book); break; case ESM::REC_CLOT: mReferenceables.load(*mReader, mBase, UniversalId::Type_Clothing); break; case ESM::REC_CONT: mReferenceables.load(*mReader, mBase, UniversalId::Type_Container); break; case ESM::REC_CREA: mReferenceables.load(*mReader, mBase, UniversalId::Type_Creature); break; case ESM::REC_DOOR: mReferenceables.load(*mReader, mBase, UniversalId::Type_Door); break; case ESM::REC_INGR: mReferenceables.load(*mReader, mBase, UniversalId::Type_Ingredient); break; case ESM::REC_LEVC: mReferenceables.load(*mReader, mBase, UniversalId::Type_CreatureLevelledList); break; case ESM::REC_LEVI: mReferenceables.load(*mReader, mBase, UniversalId::Type_ItemLevelledList); break; case ESM::REC_LIGH: mReferenceables.load(*mReader, mBase, UniversalId::Type_Light); break; case ESM::REC_LOCK: mReferenceables.load(*mReader, mBase, UniversalId::Type_Lockpick); break; case ESM::REC_MISC: mReferenceables.load(*mReader, mBase, UniversalId::Type_Miscellaneous); break; case ESM::REC_NPC_: mReferenceables.load(*mReader, mBase, UniversalId::Type_Npc); break; case ESM::REC_PROB: mReferenceables.load(*mReader, mBase, UniversalId::Type_Probe); break; case ESM::REC_REPA: mReferenceables.load(*mReader, mBase, UniversalId::Type_Repair); break; case ESM::REC_STAT: mReferenceables.load(*mReader, mBase, UniversalId::Type_Static); break; case ESM::REC_WEAP: mReferenceables.load(*mReader, mBase, UniversalId::Type_Weapon); break; case ESM::REC_DIAL: { ESM::Dialogue record; std::string recordIdString = record.mId.getRefIdString(); bool isDeleted = false; record.load(*mReader, isDeleted); if (isDeleted) { // record vector can be shuffled around which would make pointer to record invalid mDialogue = nullptr; if (mJournals.tryDelete(recordIdString)) { mJournalInfos.removeDialogueInfos(recordIdString); } else if (mTopics.tryDelete(recordIdString)) { mTopicInfos.removeDialogueInfos(recordIdString); } else { messages.add(UniversalId::Type_None, "Trying to delete dialogue record " + recordIdString + " which does not exist", "", CSMDoc::Message::Severity_Warning); } } else { if (record.mType == ESM::Dialogue::Journal) { mJournals.load(record, mBase); mDialogue = &mJournals.getRecord(record.mId).get(); } else { mTopics.load(record, mBase); mDialogue = &mTopics.getRecord(record.mId).get(); } } break; } case ESM::REC_INFO: { if (!mDialogue) { messages.add(UniversalId::Type_None, "Found info record not following a dialogue record", "", CSMDoc::Message::Severity_Error); mReader->skipRecord(); break; } if (mDialogue->mType == ESM::Dialogue::Journal) mJournalInfos.load(*mReader, mBase, *mDialogue); else mTopicInfos.load(*mReader, mBase, *mDialogue); break; } case ESM::REC_FILT: if (!mProject) { unhandledRecord = true; break; } mFilters.load(*mReader, mBase); break; case ESM::REC_DBGP: if (!mProject) { unhandledRecord = true; break; } mDebugProfiles.load(*mReader, mBase); break; default: unhandledRecord = true; } if (unhandledRecord) { messages.add( UniversalId::Type_None, "Unsupported record type: " + n.toString(), "", CSMDoc::Message::Severity_Error); mReader->skipRecord(); } return false; } bool CSMWorld::Data::hasId(const std::string& id) const { return getGlobals().searchId(id) != -1 || getGmsts().searchId(id) != -1 || getSkills().searchId(id) != -1 || getClasses().searchId(id) != -1 || getFactions().searchId(id) != -1 || getRaces().searchId(id) != -1 || getSounds().searchId(id) != -1 || getScripts().searchId(id) != -1 || getRegions().searchId(id) != -1 || getBirthsigns().searchId(id) != -1 || getSpells().searchId(id) != -1 || getTopics().searchId(id) != -1 || getJournals().searchId(id) != -1 || getCells().searchId(id) != -1 || getEnchantments().searchId(id) != -1 || getBodyParts().searchId(id) != -1 || getSoundGens().searchId(id) != -1 || getMagicEffects().searchId(id) != -1 || getReferenceables().searchId(id) != -1; } int CSMWorld::Data::count(RecordBase::State state) const { return count(state, mGlobals) + count(state, mGmsts) + count(state, mSkills) + count(state, mClasses) + count(state, mFactions) + count(state, mRaces) + count(state, mSounds) + count(state, mScripts) + count(state, mRegions) + count(state, mBirthsigns) + count(state, mSpells) + count(state, mCells) + count(state, mEnchantments) + count(state, mBodyParts) + count(state, mLand) + count(state, mLandTextures) + count(state, mSoundGens) + count(state, mMagicEffects) + count(state, mReferenceables) + count(state, mPathgrids); } std::vector CSMWorld::Data::getIds(bool listDeleted) const { std::vector ids; appendIds(ids, mGlobals, listDeleted); appendIds(ids, mGmsts, listDeleted); appendIds(ids, mClasses, listDeleted); appendIds(ids, mFactions, listDeleted); appendIds(ids, mRaces, listDeleted); appendIds(ids, mSounds, listDeleted); appendIds(ids, mScripts, listDeleted); appendIds(ids, mRegions, listDeleted); appendIds(ids, mBirthsigns, listDeleted); appendIds(ids, mSpells, listDeleted); appendIds(ids, mTopics, listDeleted); appendIds(ids, mJournals, listDeleted); appendIds(ids, mCells, listDeleted); appendIds(ids, mEnchantments, listDeleted); appendIds(ids, mBodyParts, listDeleted); appendIds(ids, mSoundGens, listDeleted); appendIds(ids, mMagicEffects, listDeleted); appendIds(ids, mReferenceables, listDeleted); std::sort(ids.begin(), ids.end()); return ids; } void CSMWorld::Data::assetsChanged() { mVFS.get()->reset(); VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics, UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos }; size_t numAssetTables = sizeof(assetTableIds) / sizeof(UniversalId); for (size_t i = 0; i < numAssetTables; ++i) { ResourceTable* table = static_cast(getTableModel(assetTableIds[i])); table->beginReset(); } // Trigger recreation mResourcesManager.recreateResources(); for (size_t i = 0; i < numAssetTables; ++i) { ResourceTable* table = static_cast(getTableModel(assetTableIds[i])); table->endReset(); } // Get rid of potentially old cached assets mResourceSystem->clearCache(); emit assetTablesChanged(); } void CSMWorld::Data::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (topLeft.column() <= 0) emit idListChanged(); } void CSMWorld::Data::rowsChanged(const QModelIndex& parent, int start, int end) { emit idListChanged(); } const VFS::Manager* CSMWorld::Data::getVFS() const { return mVFS.get(); }