Ejemplo n.º 1
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();
        }
    }
}
Ejemplo n.º 2
0
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.
            boost::shared_ptr<ESM::ESMReader> ptr(mReader);
            mReaders.push_back(ptr);
        }
        else
            delete mReader;

        mReader = 0;

        mDialogue = 0;
        return true;
    }

    ESM::NAME n = mReader->getRecName();
    mReader->getRecHeader();

    bool unhandledRecord = false;

    switch (n.val)
    {
        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:
        {
            int index = mLand.load(*mReader, mBase);

            if (index!=-1 && !mBase)
                mLand.getRecord (index).mModified.mLand->loadData (
                    ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
                    ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);

            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 = Misc::StringUtils::lowerCase (mCells.getId (index));
            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:
        {
            std::string id = mReader->getHNOString ("NAME");

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

            if (record.mType==ESM::Dialogue::Journal)
            {
                mJournals.load (record, mBase);
                mDialogue = &mJournals.getRecord (id).get();
            }
            else if (record.mType==ESM::Dialogue::Deleted)
            {
                mDialogue = 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
                {
                    messages.add (UniversalId::Type_None,
                        "Trying to delete dialogue record " + id + " which does not exist",
                        "", CSMDoc::Message::Severity_Warning);
                }
            }
            else
            {
                mTopics.load (record, mBase);
                mDialogue = &mTopics.getRecord (id).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;
}