diff --git a/NFS3/FEDATA/FedataFile.h b/NFS3/FEDATA/FedataFile.h index 552775b..ceab946 100644 --- a/NFS3/FEDATA/FedataFile.h +++ b/NFS3/FEDATA/FedataFile.h @@ -1,6 +1,7 @@ #pragma once #include "../../Common/IRawData.h" +#include "../../Shared/VIV/VivArchive.h" namespace LibOpenNFS::NFS3 { diff --git a/NFS3/NFS3Loader.cpp b/NFS3/NFS3Loader.cpp index cef1bee..36af340 100644 --- a/NFS3/NFS3Loader.cpp +++ b/NFS3/NFS3Loader.cpp @@ -29,7 +29,7 @@ namespace LibOpenNFS::NFS3 { Car::PhysicsData carPhysicsData; - if (std::filesystem::exists(carOutPath)) { + if (std::filesystem::exists(fcePath.str()) && std::filesystem::exists(fedataPath.str()) && std::filesystem::exists(carpPath.str())) { LogInfo("VIV has already been extracted to %s, skipping", carOutPath.c_str()); } else { ASSERT(Shared::VivArchive::Load(vivPath.str(), vivFile), "Could not open VIV file: " << vivPath.str()); @@ -98,6 +98,33 @@ namespace LibOpenNFS::NFS3 { return track; } + FedataFile Loader::LoadCarMenuData(std::string const &carBasePath, std::string const &carOutPath) { + LogInfo("Loading NFS3 car menu data from %s into %s", carBasePath.c_str(), carOutPath.c_str()); + + std::filesystem::path p(carBasePath); + std::string carName = p.filename().string(); + std::string const fedataFileName = "fedata.eng"; + std::stringstream vivPath, fcePath, fedataPath, carpPath; + vivPath << carBasePath << "/car.viv"; + fedataPath << carOutPath << "/" << fedataFileName; + + Shared::VivArchive vivFile; + FedataFile fedataFile; + + if (std::filesystem::exists(fedataPath.str())) { + LogInfo("Fedata file has already been extracted to %s, skipping", carOutPath.c_str()); + } else { + ASSERT(Shared::VivArchive::Load(vivPath.str(), vivFile), "Could not open VIV file: " << vivPath.str()); + ASSERT(Shared::VivArchive::ExtractFile(carOutPath, vivFile, fedataFileName), + "Could not extract fedata file from VIV file: " << vivPath.str() << "to: " << carOutPath); + } + if (!FedataFile::Load(fedataPath.str(), fedataFile)) { + LogWarning("Could not load FeData file: %s", fedataPath.str().c_str()); + } + + return fedataFile; + } + Car::MetaData Loader::_ParseAssetData(FceFile const &fceFile, FedataFile const &fedataFile) { LogInfo("Parsing FCE File into ONFS Structures"); diff --git a/NFS3/NFS3Loader.h b/NFS3/NFS3Loader.h index 43ac6f0..33aa468 100644 --- a/NFS3/NFS3Loader.h +++ b/NFS3/NFS3Loader.h @@ -30,6 +30,8 @@ namespace LibOpenNFS::NFS3 { static Car LoadCar(std::string const &carBasePath, std::string const &carOutPath); static Track LoadTrack(std::string const &trackBasePath); + static FedataFile LoadCarMenuData(std::string const &carBasePath, std::string const &carOutPath); + private: static Car::MetaData _ParseAssetData(FceFile const &fceFile, FedataFile const &fedataFile); static Car::PhysicsData _ParsePhysicsData(Shared::CarpFile const &carpFile); diff --git a/NFS4/PC/FEDATA/FedataFile.cpp b/NFS4/PC/FEDATA/FedataFile.cpp index 077651f..3a64b40 100644 --- a/NFS4/PC/FEDATA/FedataFile.cpp +++ b/NFS4/PC/FEDATA/FedataFile.cpp @@ -1,10 +1,12 @@ #include "FedataFile.h" + +#include + namespace LibOpenNFS::NFS4 { - bool FedataFile::Load(std::string const &fedataPath, FedataFile &fedataFile, uint8_t const nPriColours) { + bool FedataFile::Load(std::string const &fedataPath, FedataFile &fedataFile) { std::ifstream fedata(fedataPath, std::ios::in | std::ios::binary); - fedataFile.m_nPriColours = nPriColours; bool const loadStatus{fedataFile._SerializeIn(fedata)}; fedata.close(); @@ -31,18 +33,15 @@ namespace LibOpenNFS::NFS4 { // Jump to location of FILEPOS table for car colour names ifstream.seekg(COLOUR_TABLE_OFFSET, std::ios::beg); // Read that table in - std::vector colourNameOffsets(m_nPriColours); - onfs_check(safe_read(ifstream, colourNameOffsets)); + uint32_t colourNameOffset; + onfs_check(safe_read(ifstream, colourNameOffset)); - for (uint8_t colourIdx = 0; colourIdx < m_nPriColours; ++colourIdx) { - ifstream.seekg(colourNameOffsets[colourIdx], std::ios::beg); - std::string colourName; - std::getline(ifstream, colourName, '\0'); + std::string colourName; + ifstream.seekg(colourNameOffset, std::ios::beg); + while (std::getline(ifstream, colourName, '\0')) { primaryColourNames.emplace_back(colourName.begin(), colourName.end()); } - //uint32_t colourNameLength = colourIdx < (fceHeader->nColours - 1) ? (colourNameOffsets[colourIdx + 1] - colourNameOffsets[colourIdx]) : 32; - return true; } diff --git a/NFS4/PC/FEDATA/FedataFile.h b/NFS4/PC/FEDATA/FedataFile.h index 84d34f6..37a620e 100644 --- a/NFS4/PC/FEDATA/FedataFile.h +++ b/NFS4/PC/FEDATA/FedataFile.h @@ -10,7 +10,7 @@ namespace LibOpenNFS::NFS4 { public: FedataFile() = default; - static bool Load(std::string const &fedataPath, FedataFile &fedataFile, uint8_t nPriColours); + static bool Load(std::string const &fedataPath, FedataFile &fedataFile); static void Save(std::string const &fedataPath, FedataFile &fedataFile); std::string menuName; diff --git a/NFS4/PC/NFS4Loader.cpp b/NFS4/PC/NFS4Loader.cpp index e6da28f..c11c1b6 100644 --- a/NFS4/PC/NFS4Loader.cpp +++ b/NFS4/PC/NFS4Loader.cpp @@ -40,7 +40,7 @@ namespace LibOpenNFS::NFS4 { Car::PhysicsData carPhysicsData; - if (std::filesystem::exists(carOutPath)) { + if (std::filesystem::exists(fcePath.str()) && std::filesystem::exists(fedataPath.str()) && std::filesystem::exists(carpPath.str())) { LogInfo("VIV has already been extracted to %s, skipping", carOutPath.c_str()); } else { ASSERT(Shared::VivArchive::Load(vivPath.str(), vivFile), "Could not open VIV file: " << vivPath.str()); @@ -48,7 +48,7 @@ namespace LibOpenNFS::NFS4 { "Could not extract VIV file: " << vivPath.str() << "to: " << carOutPath); } ASSERT(NFS4::FceFile::Load(fcePath.str(), fceFile), "Could not load FCE file: " << fcePath.str()); - if (!FedataFile::Load(fedataPath.str(), fedataFile, fceFile.nColours)) { + if (!FedataFile::Load(fedataPath.str(), fedataFile)) { LogWarning("Could not load FeData file: %s", fedataPath.str().c_str()); } if (Shared::CarpFile::Load(carpPath.str(), carpFile)) { @@ -105,6 +105,42 @@ namespace LibOpenNFS::NFS4 { return track; } + FedataFile Loader::LoadCarMenuData(std::string const &carBasePath, std::string const &carOutPath, NFSVersion version) { + LogInfo("Loading NFS4 car menu data from %s into %s", carBasePath.c_str(), carOutPath.c_str()); + + std::filesystem::path p(carBasePath); + std::string carName = p.filename().replace_extension("").string(); + std::string const fedataFileName = "fedata.eng"; + + std::stringstream vivPath, fedataPath; + vivPath << carBasePath; + fedataPath << carOutPath << "/" << fedataFileName; + + if (version == NFSVersion::NFS_4) { + vivPath << "/car.viv"; + } else { + // MCO + vivPath << ".viv"; + } + + Shared::VivArchive vivFile; + FceFile fceFile; + FedataFile fedataFile; + + if (std::filesystem::exists(fedataPath.str())) { + LogInfo("Fedata file has already been extracted to %s, skipping", carOutPath.c_str()); + } else { + ASSERT(Shared::VivArchive::Load(vivPath.str(), vivFile), "Could not open VIV file: " << vivPath.str()); + ASSERT(Shared::VivArchive::ExtractFile(carOutPath, vivFile, fedataFileName), + "Could not extract fedata file from VIV file: " << vivPath.str() << "to: " << carOutPath); + } + if (!FedataFile::Load(fedataPath.str(), fedataFile)) { + LogWarning("Could not load FeData file: %s", fedataPath.str().c_str()); + } + + return fedataFile; + } + Car::MetaData Loader::_ParseAssetData(FceFile const &fceFile, FedataFile const &fedataFile, NFSVersion version) { LogInfo("Parsing FCE File into ONFS Structures"); Car::MetaData carMetadata; diff --git a/NFS4/PC/NFS4Loader.h b/NFS4/PC/NFS4Loader.h index dc8e2f7..f5b13f4 100644 --- a/NFS4/PC/NFS4Loader.h +++ b/NFS4/PC/NFS4Loader.h @@ -17,6 +17,8 @@ namespace LibOpenNFS::NFS4 { static Car LoadCar(std::string const &carBasePath, std::string const &carOutPath, NFSVersion version); static Track LoadTrack(std::string const &trackBasePath); + static FedataFile LoadCarMenuData(std::string const &carBasePath, std::string const &carOutPath, NFSVersion version); + private: static Car::MetaData _ParseAssetData(FceFile const &fceFile, FedataFile const &fedataFile, NFSVersion version); static Car::PhysicsData _ParsePhysicsData(Shared::CarpFile const &carpFile); diff --git a/Shared/VIV/VivArchive.cpp b/Shared/VIV/VivArchive.cpp index 8a0fc8f..4a429df 100644 --- a/Shared/VIV/VivArchive.cpp +++ b/Shared/VIV/VivArchive.cpp @@ -24,7 +24,8 @@ namespace LibOpenNFS::Shared { } bool VivArchive::Extract(std::string const &outPath, VivArchive &vivFile) { - std::filesystem::create_directories(outPath); + if (!std::filesystem::exists(outPath)) + std::filesystem::create_directories(outPath); for (uint32_t fileIdx = 0; fileIdx < vivFile.nFiles; ++fileIdx) { VivEntry &curFile{vivFile.files.at(fileIdx)}; @@ -32,6 +33,11 @@ namespace LibOpenNFS::Shared { std::stringstream out_file_path; out_file_path << outPath << "/" << curFile.filename; + if (std::filesystem::exists(out_file_path.str())) { + LogInfo("Not extracting file %s, because it already exists", out_file_path.str().c_str()); + continue; + } + std::ofstream out(out_file_path.str(), std::ios::out | std::ios::binary); if (!out.is_open()) { LogWarning("Error while creating output file %s", out_file_path.str().c_str()); @@ -43,6 +49,36 @@ namespace LibOpenNFS::Shared { return true; } + bool VivArchive::ExtractFile(std::string const &outPath, VivArchive &vivFile, std::string const &fileName) { + if (!std::filesystem::exists(outPath)) + std::filesystem::create_directories(outPath); + + std::stringstream out_file_path; + out_file_path << outPath << "/" << fileName; + if (std::filesystem::exists(out_file_path.str())) { + return true; + } + + for (uint32_t fileIdx = 0; fileIdx < vivFile.nFiles; ++fileIdx) { + VivEntry &curFile{vivFile.files.at(fileIdx)}; + + if (curFile.filename != fileName) { + continue; + } + + std::ofstream out(out_file_path.str(), std::ios::out | std::ios::binary); + if (!out.is_open()) { + LogWarning("Error while creating output file %s", out_file_path.str().c_str()); + return false; + } + out.write((char *)curFile.data.data(), curFile.data.size()); + out.close(); + return true; + } + + return false; + } + bool VivArchive::_SerializeIn(std::ifstream &ifstream) { onfs_check(safe_read(ifstream, vivHeader)); diff --git a/Shared/VIV/VivArchive.h b/Shared/VIV/VivArchive.h index d66e45a..e4341da 100644 --- a/Shared/VIV/VivArchive.h +++ b/Shared/VIV/VivArchive.h @@ -14,6 +14,7 @@ namespace LibOpenNFS::Shared { static bool Load(std::string const &vivPath, VivArchive &vivFile); static void Save(std::string const &vivPath, VivArchive &vivFile); static bool Extract(std::string const &outPath, VivArchive &vivFile); + static bool ExtractFile(std::string const &outPath, VivArchive &vivFile, std::string const &fileName); char vivHeader[4]; uint32_t vivSize;