Exemple #1
0
bool FalloutESM::ParseTextureSets(ESMStream& substream) {
    
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::TXST) {
            mLoadMessages.push_back("Error: encountered a non-texture set record in the texture set group");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        TextureSet set(record.Meta.AsRecord.FormID);
        
        if (set.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: encountered a malformed texture set record");
            return false;
        }
        
        mTextures.insert(std::pair<FormIdentifier, TextureSet>(record.Meta.AsRecord.FormID, std::move(set)));
    }
    
    return true;
}
Exemple #2
0
bool FalloutESM::ParseStatics(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        if (header.Tag != ESMTag::STAT) {
            mLoadMessages.push_back("Error: encountered an invalid record in the static object group");
            return false;
        }
        
        ESMStream recordStream(substream, header.Size);
        StaticObject object(StaticObjectType::Static, header.Meta.AsRecord.FormID);
        
        if (object.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: error parsing a static object record");
            return false;
        }
        
        mStaticObjects.insert(std::pair<FormIdentifier, StaticObject>(header.Meta.AsRecord.FormID, std::move(object)));
        mEntityTypeMap.insert(std::pair<FormIdentifier, ESMTag>(header.Meta.AsRecord.FormID, ESMTag::STAT));
    }
    
    return true;
}
Exemple #3
0
bool FalloutESM::ParseWorldCellGroup(ESMStream& stream, FormIdentifier parentWorld) {
    auto worldItr = mWorldspaces.find(parentWorld);
    
    if (worldItr == mWorldspaces.end()) {
        mLoadMessages.push_back("Error: trying to add entites to a non-existent world");
        return false;
    }
    
    Worldspace& world = (*worldItr).second;
    
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                if (ParseWorldInnerGroup(stream, world, header, 0, 0) == false) {
                    mLoadMessages.push_back("Error: unable to parse world cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::CELL:
            {
                ESMStream cellStream(stream, header.Size);
                
                Cell cell(header.Meta.AsRecord.FormID, -1, -1);
                
                if (cell.Parse(cellStream) == false) {
                    mLoadMessages.push_back("Error: invalid cell record in the world group");
                    return false;
                }
                
                mCells.insert(std::pair<FormIdentifier, Cell>(header.Meta.AsRecord.FormID, std::move(cell)));
                world.GetCellsWritable().push_back(header.Meta.AsRecord.FormID);
                break;
            }
            
            default:
                mLoadMessages.push_back("Error: invalid tag inside the world cell group");
                return false;
        }
    }
    
    return true;
}
Exemple #4
0
bool TextureSet::Parse(ESMStream& stream) {
    
    while(stream.IsValid() == true) {
        FieldHeader fieldHeader;
        
        stream.ReadFieldHeader(fieldHeader);
        
        switch(fieldHeader.Tag) {
            case ESMTag::EDID:
                FieldParser::ParseEDIDField(stream, fieldHeader.Size, mEditorId);
                break;
                
            case ESMTag::OBND:
                FieldParser::ParseOBDNField(stream, fieldHeader.Size, mBounds);
                break;
                
            case ESMTag::TX00:
            case ESMTag::TX01:
            case ESMTag::TX02:
            case ESMTag::TX03:
            case ESMTag::TX04:
            case ESMTag::TX05:
            case ESMTag::TX06:
            case ESMTag::TX07:
            {
                std::string textureName;
                FieldParser::ParseTXNNField(stream, fieldHeader.Size, textureName);
                
                mTextureNames.push_back(std::move(textureName));
                break;
            }
                
            case ESMTag::DODT:
                FieldParser::ParseDODTField(stream, fieldHeader.Size, mDecalData);
                break;
                
            case ESMTag::DNAM:
                stream.Read16((uint16_t&)mFlags);
                break;
                
            default:
                return false;
        }
    }
    
    return true;
}
Exemple #5
0
bool FalloutScript::Parse(ESMStream& stream) {
    while(stream.IsValid() == true) {
        FieldHeader header;
        
        stream.ReadFieldHeader(header);
        
        switch(header.Tag) {
            case ESMTag::EDID:
                FieldParser::ParseEDIDField(stream, header.Size, mEditorID);
                break;
                
            case ESMTag::SCHR:
                FieldParser::ParseSCHRField(stream, header.Size, mScriptHeader);
                break;
                
            case ESMTag::SCDA:
                FieldParser::ParseBinaryField(stream, header.Size, mScriptBytecode);
                break;
                
            case ESMTag::SCTX:
                FieldParser::ParseEDIDField(stream, header.Size, mScriptSource);
                break;
                
            case ESMTag::SCRO:
            {
                FormIdentifier id = 0;
                
                FieldParser::ParseFormID(stream, header.Size, id);
                mReferences.push_back(id);
                break;
            }   
            
            case ESMTag::SCVR:
            case ESMTag::SCRV: //TODO: This is undocumented, fixed uint32_t field
            case ESMTag::SLSD:
                //TODO: Handle these
                stream.Skip(header.Size);
                break;
                
            default:
                return false;
        }
    }
    
    return true;
}
Exemple #6
0
bool FalloutESM::ParseCellExteriorGroup(ESMStream& stream, Worldspace& world, int x, int y, bool isblock) {
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                if (ParseWorldInnerGroup(stream, world, header, x, y) == false) {
                    mLoadMessages.push_back("Error: unable to parse world exterior cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::CELL:
            {
                ESMStream recordStream(stream, header.Size);
                
                Cell cell(header.Meta.AsRecord.FormID, x, y, isblock);
                
                if (cell.Parse(recordStream) == false) {
                    mLoadMessages.push_back("Error: invalid cell record in the world group");
                    return false;
                }
                
                mCells.insert(std::pair<FormIdentifier, Cell>(header.Meta.AsRecord.FormID, std::move(cell)));
                world.GetCellsWritable().push_back(header.Meta.AsRecord.FormID);
                break;
            }
                
            default:
            {
                mLoadMessages.push_back("Error: invalid tag inside a world exterior cell group");
                break;
            }
        }
    }
    
    return true;
}
Exemple #7
0
bool FalloutESM::ParseWorlds(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                ESMStream groupStream(substream, header.Size - sizeof(RecordHeader));
                
                if (ParseWorldCellGroup(groupStream, header.Meta.AsGroup.Label.AsFormIdentifier) == false) {
                    mLoadMessages.push_back("Error: unable to parse world cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::WRLD:
            {
                ESMStream worldStream(substream, header.Size);
                
                Worldspace world(header.Meta.AsRecord.FormID);
                
                if (world.Parse(worldStream) == false) {
                    mLoadMessages.push_back("Error: invalid world record");
                    return false;
                }
                
                mWorldspaces.insert(std::pair<FormIdentifier, Worldspace>(header.Meta.AsRecord.FormID, std::move(world)));
                break;
            }
            
            default:
                return false;
        }
        
    }
    
    return true;
}
Exemple #8
0
bool LandscapeTextureSet::Parse(ESMStream& stream) {
    while(stream.IsValid() == true) {
        FieldHeader header;
        
        stream.ReadFieldHeader(header);
        
        switch(header.Tag) {
            case ESMTag::EDID:
                FieldParser::ParseEDIDField(stream, header.Size, mEditorId);
                break;
                
            case ESMTag::ICON:
                FieldParser::ParseEDIDField(stream, header.Size, mLargeIconFilename);
                break;
                
            case ESMTag::MICO:
                FieldParser::ParseEDIDField(stream, header.Size, mSmallIconFilename);
                break;
                
            case ESMTag::TNAM:
                FieldParser::ParseFormID(stream, header.Size, mTextureIdentifier);
                break;
                
            case ESMTag::HNAM:
                FieldParser::ParseHavokData(stream, header.Size, mHavokData);
                break;
                
            case ESMTag::SNAM:
                FieldParser::ParseByteValue(stream, header.Size, mSpecularExponent);
                break;
                
            case ESMTag::GNAM:
                FieldParser::ParseFormID(stream, header.Size, mGrassIdentifier);
                break;
                
            default:
                return false;
        }
    }
    
    return true;
}
Exemple #9
0
bool FalloutESM::ParseCells(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        if (header.Tag != ESMTag::GRUP) {
            mLoadMessages.push_back("Error: found a non-group record in the top level cell structure");
            return false;
        }
        
        //These are all groups of type 2 (interior cell block)
        ESMStream groupStream(substream, header.Size - sizeof(RecordHeader));
        
        if (ParseCellGroup(substream, -1, -1) == false) {            
            return false;
        }
    }
    
    return true;
}
Exemple #10
0
bool FalloutESM::ParseCellGroup(ESMStream& stream, int block, int subblock) {
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                if (ParseCellInnerGroup(stream, header, block, subblock) == false) {
                    mLoadMessages.push_back("Error: unable to parse cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::CELL:
            {
                ESMStream cellStream(stream, header.Size);
                
                Cell cell(header.Meta.AsRecord.FormID, block, subblock);
                
                if (cell.Parse(cellStream) == false) {
                    mLoadMessages.push_back("Error: invalid cell record");
                    return false;
                }
                
                mCells.insert(std::pair<FormIdentifier, Cell>(header.Meta.AsRecord.FormID, std::move(cell)));
                break;
            }
            
            default:
                return false;
        }
    }
    
    return true;
}
Exemple #11
0
bool FalloutESM::ParseScripts(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::SCPT) {
            mLoadMessages.push_back("Error: encountered a non-script record in the script group");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        FalloutScript script(record.Meta.AsRecord.FormID);
        
        if (script.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: malformed script record");
            return false;
        }
        
        mScripts.insert(std::pair<FormIdentifier, FalloutScript>(record.Meta.AsRecord.FormID, std::move(script)));
    }
    
    return true;
}
Exemple #12
0
bool FalloutESM::ParseLandTextureSets(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::LTEX) {
            mLoadMessages.push_back("Error: encountered a non-land-texture set record");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        LandscapeTextureSet textureSet(record.Meta.AsRecord.FormID);
        
        if (textureSet.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: malformed land-texture set record");
            return false;
        }
        
        mLandTextures.insert(std::pair<FormIdentifier, LandscapeTextureSet>(record.Meta.AsRecord.FormID, std::move(textureSet)));
    }
    
    return true;
}
Exemple #13
0
bool FalloutESM::ParseGameSettings(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::GMST) {
            mLoadMessages.push_back("Error: encountered a non-GMST tag in the game settings group");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        GameSetting setting(record.Meta.AsRecord.FormID);
        
        if (setting.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: malformed GMST record");
            return false;
        }
        
        mSettings.insert(std::pair<FormIdentifier, GameSetting>(record.Meta.AsRecord.FormID, std::move(setting)));
    }
    
    return true;
}
Exemple #14
0
bool FalloutESM::ParseMessages(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        if (header.Tag != ESMTag::MESG) {
            mLoadMessages.push_back("Error: encountered an invalid record in the messages group");
            return false;
        }
        
        ESMStream recordStream(substream, header.Size);
        Message message(header.Meta.AsRecord.FormID);
        
        if (message.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: error parsing a message record");
            return false;
        }

        mMessages.insert(std::pair<FormIdentifier, Message>(header.Meta.AsRecord.FormID, std::move(message)));
    }
    
    return true;
}
Exemple #15
0
bool FalloutESM::ParseCellChildren(FormIdentifier cellID, CellChildType childType, ESMStream& stream, int block, int subblock) {
    auto cellItr = mCells.find(cellID);
    // = mCells[cellID];
    
    if (cellItr == mCells.end()) {
        mLoadMessages.push_back("Error: tried to add children for a non-existent cell");
        return false;
    }
    
    Cell& cell = (*cellItr).second;
    
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            // Static objects
            case ESMTag::REFR: 
            {
                ESMStream substream(stream, header.Size);
                WorldObject obj(WorldObjectType::Static, header.Meta.AsRecord.FormID);
                
                if (obj.Parse(substream) == false) {
                    mLoadMessages.push_back("Error: invalid REFR record");
                    return false;
                }
                
                cell.AddObject(childType, obj);
                break;
            }
            
            // Creatures
            case ESMTag::ACRE:
            {
                ESMStream substream(stream, header.Size);
                WorldObject obj(WorldObjectType::Creature, header.Meta.AsRecord.FormID);
                
                if (obj.Parse(substream) == false) {
                    mLoadMessages.push_back("Error: invalid ACRE record");
                    return false;
                }
                
                cell.AddObject(childType,obj);
                break;
            }
            
            // Grenades
            case ESMTag::PGRE:
            {
                ESMStream substream(stream, header.Size);
                substream.Skip(substream.GetSize());
                break;
            }
            
            // Missiles
            case ESMTag::PMIS:
            {
                ESMStream substream(stream, header.Size);
                substream.Skip(substream.GetSize());
                break;
            }
                
            // Characters
            case ESMTag::ACHR:
            {
                ESMStream substream(stream, header.Size);
                WorldObject obj(WorldObjectType::Character, header.Meta.AsRecord.FormID);
                
                if (obj.Parse(substream) == false) {
                    mLoadMessages.push_back("Error: invalid ACHR record");
                    return false;
                }
                
                cell.AddObject(childType, obj);
                break;
            }
                
            case ESMTag::GRUP:
            {
                if (ParseCellChildrenGroup(stream, header, block, subblock) == false) {
                    mLoadMessages.push_back("Error: unable to parse cell children");
                    return false;
                }
                
                break;
            }
                
            case ESMTag::NAVM:
            {
                ESMStream substream(stream, header.Size);
                
                substream.Skip(substream.GetSize());
                break;
            }
            
            case ESMTag::LAND:
            {
                ESMStream substream(stream, header.Size);
                uint32_t decompSize;
                
                substream.Read32(decompSize);
                
                const size_t sourceSize = header.Size - 4;
                
                mBuffer.reserve(sourceSize);
                mDecompressedBuffer.reserve(decompSize);
                
                substream.ReadRaw((char *)&mBuffer[0], sourceSize);
                
                if (ESMUtility::ZlibDecompress(mBuffer, mDecompressedBuffer, sourceSize, decompSize) == false) {
                    mLoadMessages.push_back("Error: unable to decompress zlib LAND data");
                    //TODO: There is a single land entry in FalloutNV.esm that appears corrupted, skip it
                    break;
                }

                //This is fairly unpleasant but functions
                std::stringstream dataStream;
                dataStream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(&mDecompressedBuffer[0]), decompSize);
                
                ESMStream decompressedStream(stream, dataStream, decompSize);
                
                LandDefinition landDefinition(header.Meta.AsRecord.FormID);
                
                if (landDefinition.Parse(decompressedStream) == false) {
                    mLoadMessages.push_back("Error: invalid LAND record");
                    return false;
                }
                
                cell.SetLandscapeID(header.Meta.AsRecord.FormID);
                mLandscapes.insert(std::pair<FormIdentifier, LandDefinition>(header.Meta.AsRecord.FormID, std::move(landDefinition)));
                break;
            }
            
            default:
                std::cout << "Found unhandled tag: " << ESMUtility::TagToString(header.Tag) << " " << header.Size << std::endl;
                break;
        }
        
        
    }
    
    return true;
}