Пример #1
0
void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, UniversalId::Type type)
{
    std::string id = reader.getHNOString ("NAME");

    int index = searchId (id);

    if (reader.isNextSub ("DELE"))
    {
        reader.skipRecord();

        if (index==-1)
        {
            // deleting a record that does not exist

            // ignore it for now

            /// \todo report the problem to the user
        }
        else if (base)
        {
            mData.erase (index, 1);
        }
        else
        {
            mData.getRecord (mData.globalToLocalIndex (index)).mState = RecordBase::State_Deleted;
        }
    }
    else
    {
        if (index==-1)
        {
            // new record
            int index = mData.getAppendIndex (type);
            mData.appendRecord (type, id);

            RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);

            mData.load (localIndex, reader, base);

            mData.getRecord (localIndex).mState =
                base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
        }
        else
        {
            // old record
            RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);

            if (!base)
                if (mData.getRecord (localIndex).mState==RecordBase::State_Erased)
                    throw std::logic_error ("attempt to access a deleted record");

            mData.load (localIndex, reader, base);

            if (!base)
                mData.getRecord (localIndex).mState = RecordBase::State_Modified;
        }
    }
}
Пример #2
0
    void IdCollection<ESXRecordT>::load (ESM::ESMReader& reader, bool base)
    {
        std::string id = reader.getHNOString ("NAME");

        if (reader.isNextSub ("DELE"))
        {
            int index = searchId (id);

            reader.skipRecord();

            if (index==-1)
            {
                // deleting a record that does not exist

                // ignore it for now

                /// \todo report the problem to the user
            }
            else if (base)
            {
                removeRows (index, 1);
            }
            else
            {
                mRecords[index].mState = RecordBase::State_Deleted;
            }
        }
        else
        {
            ESXRecordT record;
            record.mId = id;
            record.load (reader);

            int index = searchId (record.mId);

            if (index==-1)
            {
                // new record
                Record<ESXRecordT> record2;
                record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
                (base ? record2.mBase : record2.mModified) = record;

                appendRecord (record2);
            }
            else
            {
                // old record
                Record<ESXRecordT>& record2 = mRecords[index];

                if (base)
                    record2.mBase = record;
                else
                    record2.setModified (record);
            }
        }
    }
Пример #3
0
    void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
    {
        std::string id = reader.getHNOString ("NAME");

        if (reader.isNextSub ("DELE"))
        {
            int index = Collection<ESXRecordT, IdAccessorT>::searchId (id);

            reader.skipRecord();

            if (index==-1)
            {
                // deleting a record that does not exist

                // ignore it for now

                /// \todo report the problem to the user
            }
            else if (base)
            {
                Collection<ESXRecordT, IdAccessorT>::removeRows (index, 1);
            }
            else
            {
                Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
                record.mState = RecordBase::State_Deleted;
                this->setRecord (index, record);
            }
        }
        else
        {
            ESXRecordT record;

            int index = this->searchId (id);

            if (index==-1)
                IdAccessorT().getId (record) = id;
            else
            {
                record = this->getRecord (index).get();
            }

            record.load (reader);

            load (record, base, index);
        }
    }
Пример #4
0
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
{
    std::string id = Misc::StringUtils::lowerCase (dialogue.mId) + "#" +
        reader.getHNOString ("INAM");

    if (reader.isNextSub ("DELE"))
    {
        int index = searchId (id);

        reader.skipRecord();

        if (index==-1)
        {
            // deleting a record that does not exist

            // ignore it for now

            /// \todo report the problem to the user
        }
        else if (base)
        {
            removeRows (index, 1);
        }
        else
        {
            Record<Info> record = getRecord (index);
            record.mState = RecordBase::State_Deleted;
            setRecord (index, record);
        }
    }
    else
    {
        Info record;
        record.mTopicId = dialogue.mId;
        record.mId = id;
        record.load (reader);

        load (record, base);
    }
}
Пример #5
0
    void PCDT::load(ESM::ESMReader &esm)
    {
        while (esm.isNextSub("DNAM"))
        {
            mKnownDialogueTopics.push_back(esm.getHString());
        }

        mHasMark = false;
        if (esm.isNextSub("MNAM"))
        {
            mHasMark = true;
            mMNAM = esm.getHString();
        }

        esm.getHNT(mPNAM, "PNAM");

        if (esm.isNextSub("SNAM"))
            esm.skipHSub();
        if (esm.isNextSub("NAM9"))
            esm.skipHSub();

        // Rest state. You shouldn't even be able to save during rest, but skip just in case.
        if (esm.isNextSub("RNAM"))
            /*
                int hoursLeft;
                float x, y, z; // resting position
            */
            esm.skipHSub(); // 16 bytes

        mBounty = 0;
        esm.getHNOT(mBounty, "CNAM");

        mBirthsign = esm.getHNOString("BNAM");

        // Holds the names of the last used Alchemy apparatus. Don't need to import this ATM,
        // because our GUI auto-selects the best apparatus.
        if (esm.isNextSub("NAM0"))
            esm.skipHSub();
        if (esm.isNextSub("NAM1"))
            esm.skipHSub();
        if (esm.isNextSub("NAM2"))
            esm.skipHSub();
        if (esm.isNextSub("NAM3"))
            esm.skipHSub();

        mHasENAM = false;
        if (esm.isNextSub("ENAM"))
        {
            mHasENAM = true;
            esm.getHT(mENAM);
        }

        if (esm.isNextSub("LNAM"))
            esm.skipHSub();

        while (esm.isNextSub("FNAM"))
        {
            FNAM fnam;
            esm.getHT(fnam);
            mFactions.push_back(fnam);
        }

        mHasAADT = false;
        if (esm.isNextSub("AADT")) // Attack animation data?
        {
            mHasAADT = true;
            esm.getHT(mAADT);
        }

        if (esm.isNextSub("KNAM"))
            esm.skipHSub(); // assigned Quick Keys, I think

        if (esm.isNextSub("ANIS"))
            esm.skipHSub(); // 16 bytes

        if (esm.isNextSub("WERE"))
        {
            // some werewolf data, 152 bytes
            // maybe current skills and attributes for werewolf form
            esm.getSubHeader();
            esm.skip(152);
        }
    }
Пример #6
0
void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, bool project)
{
    ESM::ESMReader reader;

    /// \todo set encoding properly, once config implementation has been fixed.
    ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252"));
    reader.setEncoder (&encoder);

    reader.open (path.string());

    const ESM::Dialogue *dialogue = 0;

    mAuthor = reader.getAuthor();
    mDescription = reader.getDesc();

    // Note: We do not need to send update signals here, because at this point the model is not connected
    // to any view.
    while (reader.hasMoreRecs())
    {
        ESM::NAME n = reader.getRecName();
        reader.getRecHeader();

        switch (n.val)
        {
            case ESM::REC_GLOB: mGlobals.load (reader, base); break;
            case ESM::REC_GMST: mGmsts.load (reader, base); break;
            case ESM::REC_SKIL: mSkills.load (reader, base); break;
            case ESM::REC_CLAS: mClasses.load (reader, base); break;
            case ESM::REC_FACT: mFactions.load (reader, base); break;
            case ESM::REC_RACE: mRaces.load (reader, base); break;
            case ESM::REC_SOUN: mSounds.load (reader, base); break;
            case ESM::REC_SCPT: mScripts.load (reader, base); break;
            case ESM::REC_REGN: mRegions.load (reader, base); break;
            case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
            case ESM::REC_SPEL: mSpells.load (reader, base); break;

            case ESM::REC_CELL:
                mCells.load (reader, base);
                mRefs.load (reader, mCells.getSize()-1, base);
                break;

            case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break;
            case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break;
            case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break;
            case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break;
            case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break;
            case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break;
            case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break;
            case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break;
            case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break;
            case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break;
            case ESM::REC_LEVC:
                mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break;
            case ESM::REC_LEVI:
                mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break;
            case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break;
            case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break;
            case ESM::REC_MISC:
                mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break;
            case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break;
            case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break;
            case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break;
            case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break;
            case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break;

            case ESM::REC_DIAL:
            {
                std::string id = reader.getHNOString ("NAME");

                ESM::Dialogue record;
                record.mId = id;
                record.load (reader);

                if (record.mType==ESM::Dialogue::Journal)
                {
                    mJournals.load (record, base);
                    dialogue = &mJournals.getRecord (id).get();
                }
                else if (record.mType==ESM::Dialogue::Deleted)
                {
                    dialogue = 0; // record vector can be shuffled around which would make pointer
                                  // to record invalid

                    if (mJournals.tryDelete (id))
                    {
                        /// \todo handle info records
                    }
                    else if (mTopics.tryDelete (id))
                    {
                        /// \todo handle info records
                    }
                    else
                    {
                        /// \todo report deletion of non-existing record
                    }
                }
                else
                {
                    mTopics.load (record, base);
                    dialogue = &mTopics.getRecord (id).get();
                }

                break;
            }

            case ESM::REC_INFO:
            {
                if (!dialogue)
                {
                    /// \todo INFO record without matching DIAL record -> report to user
                    reader.skipRecord();
                    break;
                }

                if (dialogue->mType==ESM::Dialogue::Journal)
                    mJournalInfos.load (reader, base, *dialogue);
                else
                    mTopicInfos.load (reader, base, *dialogue);

                break;
            }

            case ESM::REC_FILT:

                if (project)
                {
                    mFilters.load (reader, base);
                    mFilters.setData (mFilters.getSize()-1,
                        mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
                        static_cast<int> (CSMFilter::Filter::Scope_Project));
                    break;
                }

                // fall through (filter record in a content file is an error with format 0)

            default:

                /// \todo throw an exception instead, once all records are implemented
                /// or maybe report error and continue?
                reader.skipRecord();
        }
    }
}
Пример #7
0
void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
{
    listener->setProgressRange(1000);

    std::set<std::string> missing;

    ESM::Dialogue *dialogue = 0;

    /// \todo Move this to somewhere else. ESMReader?
    // Cache parent esX files by tracking their indices in the global list of
    //  all files/readers used by the engine. This will greaty accelerate
    //  refnumber mangling, as required for handling moved references.
    int index = ~0;
    const std::vector<ESM::Header::MasterData> &masters = esm.getGameFiles();
    std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
    for (size_t j = 0; j < masters.size(); j++) {
        ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
        std::string fname = mast.name;
        for (int i = 0; i < esm.getIndex(); i++) {
            const std::string &candidate = allPlugins->at(i).getContext().filename;
            std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
            if (fname == fnamecandidate) {
                index = i;
                break;
            }
        }
        if (index == (int)~0) {
            // Tried to load a parent file that has not been loaded yet. This is bad,
            //  the launcher should have taken care of this.
            std::string fstring = "File " + esm.getName() + " asks for parent file " + masters[j].name
                + ", but it has not been loaded yet. Please check your load order.";
            esm.fail(fstring);
        }
        mast.index = index;
    }

    // Loop through all records
    while(esm.hasMoreRecs())
    {
        ESM::NAME n = esm.getRecName();
        esm.getRecHeader();

        // Look up the record type.
        std::map<int, StoreBase *>::iterator it = mStores.find(n.val);

        if (it == mStores.end()) {
            if (n.val == ESM::REC_INFO) {
                std::string id = esm.getHNOString("INAM");
                if (dialogue) {
                    dialogue->mInfo.push_back(ESM::DialInfo());
                    dialogue->mInfo.back().mId = id;
                    dialogue->mInfo.back().load(esm);
                } else {
                    std::cerr << "error: info record without dialog" << std::endl;
                    esm.skipRecord();
                }
            } else if (n.val == ESM::REC_MGEF) {
                mMagicEffects.load (esm);
            } else if (n.val == ESM::REC_SKIL) {
                mSkills.load (esm);
            } else {
                // Not found (this would be an error later)
                esm.skipRecord();
                missing.insert(n.toString());
            }
        } else {
            // Load it
            std::string id = esm.getHNOString("NAME");
            // ... unless it got deleted! This means that the following record
            //  has been deleted, and trying to load it using standard assumptions
            //  on the structure will (probably) fail.
            if (esm.isNextSub("DELE")) {
              esm.skipRecord();
              it->second->eraseStatic(id);
              continue;
            }
            it->second->load(esm, id);

            if (n.val==ESM::REC_DIAL) {
                dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
            } else {
                dialogue = 0;
            }
            // Insert the reference into the global lookup
            if (!id.empty() && isCacheableRecord(n.val)) {
                mIds[Misc::StringUtils::lowerCase (id)] = n.val;
            }
        }
        listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);
    }

  /* This information isn't needed on screen. But keep the code around
     for debugging purposes later.

  cout << "\n" << mStores.size() << " record types:\n";
  for(RecListList::iterator it = mStores.begin(); it != mStores.end(); it++)
    cout << "  " << toStr(it->first) << ": " << it->second->getSize() << endl;
  cout << "\nNot implemented yet: ";
  for(set<string>::iterator it = missing.begin();
      it != missing.end(); it++ )
    cout << *it << " ";
  cout << endl;
  */
}
Пример #8
0
void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
{
    listener->setProgressRange(1000);

    ESM::Dialogue *dialogue = 0;

    /// \todo Move this to somewhere else. ESMReader?
    // Cache parent esX files by tracking their indices in the global list of
    //  all files/readers used by the engine. This will greaty accelerate
    //  refnumber mangling, as required for handling moved references.
    const std::vector<ESM::Header::MasterData> &masters = esm.getGameFiles();
    std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
    for (size_t j = 0; j < masters.size(); j++) {
        ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
        std::string fname = mast.name;
        int index = ~0;
        for (int i = 0; i < esm.getIndex(); i++) {
            const std::string &candidate = allPlugins->at(i).getContext().filename;
            std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
            if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) {
                index = i;
                break;
            }
        }
        if (index == (int)~0) {
            // Tried to load a parent file that has not been loaded yet. This is bad,
            //  the launcher should have taken care of this.
            std::string fstring = "File " + esm.getName() + " asks for parent file " + masters[j].name
                + ", but it has not been loaded yet. Please check your load order.";
            esm.fail(fstring);
        }
        mast.index = index;
    }

    // Loop through all records
    while(esm.hasMoreRecs())
    {
        ESM::NAME n = esm.getRecName();
        esm.getRecHeader();

        // Look up the record type.
        std::map<int, StoreBase *>::iterator it = mStores.find(n.val);

        if (it == mStores.end()) {
            if (n.val == ESM::REC_INFO) {
                if (dialogue)
                {
                    dialogue->readInfo(esm, esm.getIndex() != 0);
                }
                else
                {
                    std::cerr << "error: info record without dialog" << std::endl;
                    esm.skipRecord();
                }
            } else if (n.val == ESM::REC_MGEF) {
                mMagicEffects.load (esm);
            } else if (n.val == ESM::REC_SKIL) {
                mSkills.load (esm);
            }
            else if (n.val==ESM::REC_FILT || ESM::REC_DBGP)
            {
                // ignore project file only records
                esm.skipRecord();
            }
            else {
                std::stringstream error;
                error << "Unknown record: " << n.toString();
                throw std::runtime_error(error.str());
            }
        } else {
            // Load it
            std::string id = esm.getHNOString("NAME");
            // ... unless it got deleted! This means that the following record
            //  has been deleted, and trying to load it using standard assumptions
            //  on the structure will (probably) fail.
            if (esm.isNextSub("DELE")) {
              esm.skipRecord();
              it->second->eraseStatic(id);
              continue;
            }
            it->second->load(esm, id);

            // DELE can also occur after the usual subrecords
            if (esm.isNextSub("DELE")) {
              esm.skipRecord();
              it->second->eraseStatic(id);
              continue;
            }

            if (n.val==ESM::REC_DIAL) {
                dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
            } else {
                dialogue = 0;
            }
            // Insert the reference into the global lookup
            if (!id.empty() && isCacheableRecord(n.val)) {
                mIds[Misc::StringUtils::lowerCase (id)] = n.val;
            }
        }
        listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);
    }
}