void World::loadPakList(std::string&& fname, std::vector<PakArray> &paklist) { VFS::IStreamPtr stream = VFS::Manager::get().open(fname.c_str()); if(!stream) throw std::runtime_error("Failed to open "+fname); size_t rownum = 0; std::map<size_t,size_t> offsets_rows; offsets_rows[VFS::read_le32(*stream)] = rownum++; while((size_t)stream->tellg() < offsets_rows.begin()->first) offsets_rows[VFS::read_le32(*stream)] = rownum++; auto iter = offsets_rows.begin(); while(iter != offsets_rows.end()) { auto next = std::next(iter); PakArray pak; while((next != offsets_rows.end() && (size_t)stream->tellg() < next->first) || (next == offsets_rows.end() && stream->peek() != std::istream::traits_type::eof())) { uint16_t count = VFS::read_le16(*stream); uint8_t val = stream->get(); pak.push_back(std::make_pair(count, val)); } if(iter->second >= paklist.size()) paklist.resize(iter->second+1); paklist[iter->second] = std::move(pak); iter = next; } }
void World::initialize(osgViewer::Viewer *viewer, osg::Group *sceneroot) { std::set<std::string> names = VFS::Manager::get().list("MAPNAMES.[0-9]*"); if(names.empty()) throw std::runtime_error("Failed to find any regions"); VFS::IStreamPtr stream; for(const std::string &name : names) { size_t pos = name.rfind('.'); if(pos == std::string::npos) continue; std::string regstr = name.substr(pos+1); unsigned long regnum = std::stoul(regstr, nullptr, 10); /* Get names */ stream = VFS::Manager::get().open(name.c_str()); if(!stream) throw std::runtime_error("Failed to open "+name); uint32_t mapcount = VFS::read_le32(*stream); if(mapcount == 0) continue; MapRegion region; region.mNames.resize(mapcount); for(std::string &mapname : region.mNames) { char mname[32]; if(!stream->read(mname, sizeof(mname)) || stream->gcount() != sizeof(mname)) throw std::runtime_error("Failed to read map names from "+name); mapname.assign(mname, sizeof(mname)); size_t end = mapname.find('\0'); if(end != std::string::npos) mapname.resize(end); } stream = nullptr; /* Get table data */ std::string fname = "MAPTABLE."+regstr; stream = VFS::Manager::get().open(fname.c_str()); if(!stream) throw std::runtime_error("Failed to open "+fname); region.mTable.resize(region.mNames.size()); for(MapTable &maptable : region.mTable) { maptable.mMapId = VFS::read_le32(*stream); maptable.mUnknown1 = stream->get(); maptable.mLongitudeType = VFS::read_le32(*stream); maptable.mLatitude = VFS::read_le16(*stream); maptable.mUnknown2 = VFS::read_le16(*stream); maptable.mUnknown3 = VFS::read_le32(*stream); } stream = nullptr; /* Get exterior data */ fname = "MAPPITEM."+regstr; stream = VFS::Manager::get().open(fname.c_str()); if(!stream) throw std::runtime_error("Failed to open "+fname); std::vector<uint32_t> extoffsets(region.mNames.size()); for(uint32_t &offset : extoffsets) offset = VFS::read_le32(*stream); std::streamoff extbase_offset = stream->tellg(); uint32_t *extoffset = extoffsets.data(); region.mExteriors.resize(extoffsets.size()); for(ExteriorLocation &extinfo : region.mExteriors) { stream->seekg(extbase_offset + *extoffset); extinfo.load(*stream); ++extoffset; } stream = nullptr; /* Get dungeon data */ fname = "MAPDITEM."+regstr; stream = VFS::Manager::get().open(fname.c_str()); if(!stream) throw std::runtime_error("Failed to open "+fname); DungeonHeader dheader; dheader.load(*stream); std::streamoff dbase_offset = stream->tellg(); DungeonHeader::Offset *doffset = dheader.mOffsets.data(); region.mDungeons.resize(dheader.mDungeonCount); for(DungeonInterior &dinfo : region.mDungeons) { stream->seekg(dbase_offset + doffset->mOffset); dinfo.load(*stream); if(dinfo.mExteriorLocationId != doffset->mExteriorLocationId) throw std::runtime_error("Dungeon exterior location id mismatch for "+std::string(dinfo.mLocationName)+": "+ std::to_string(dinfo.mExteriorLocationId)+" / "+std::to_string(doffset->mExteriorLocationId)); ++doffset; } stream = nullptr; if(regnum >= mRegions.size()) mRegions.resize(regnum+1); mRegions[regnum] = std::move(region); } loadPakList("CLIMATE.PAK", mClimates); loadPakList("POLITIC.PAK", mPolitics); mViewer = viewer; mSceneRoot = sceneroot; }