mirror of
https://github.com/izzy2lost/libultraship.git
synced 2026-06-19 01:16:13 -07:00
.meta files (#449)
* start refactoring, legacy load still working * account for path in meta file * meta * clang format * move addfile * more cleanup
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "resource/ResourceLoader.h"
|
||||
#include "utils/binarytools/MemoryStream.h"
|
||||
#include <StrHash64.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
// TODO: Delete me and find an implementation
|
||||
// Comes from stormlib. May not be the most efficient, but it's also important to be consistent.
|
||||
@@ -103,62 +104,130 @@ void Archive::SetGameVersion(uint32_t gameVersion) {
|
||||
}
|
||||
|
||||
void Archive::AddFile(const std::string& filePath) {
|
||||
if (filePath.length() > 5 && filePath.substr(filePath.length() - 5) == ".meta") {
|
||||
AddFile(filePath.substr(0, filePath.length() - 5));
|
||||
return;
|
||||
}
|
||||
|
||||
(*mHashes)[CRC64(filePath.c_str())] = filePath;
|
||||
}
|
||||
|
||||
std::shared_ptr<File> Archive::LoadFile(const std::string& filePath) {
|
||||
auto fileToLoad = LoadFileRaw(filePath);
|
||||
std::shared_ptr<ResourceInitData> Archive::ReadResourceInitData(const std::string& filePath,
|
||||
std::shared_ptr<File> metaFileToLoad) {
|
||||
auto initData = CreateDefaultResourceInitData();
|
||||
|
||||
// just using metaFileToLoad->Buffer->data() leads to garbage at the end
|
||||
// that causes nlohmann to fail parsing, following the pattern used for
|
||||
// xml resolves that issue
|
||||
auto stream = std::make_shared<MemoryStream>(metaFileToLoad->Buffer);
|
||||
auto binaryReader = std::make_shared<BinaryReader>(stream);
|
||||
auto parsed = nlohmann::json::parse(binaryReader->ReadCString());
|
||||
|
||||
if (parsed.contains("path")) {
|
||||
initData->Path = parsed["path"];
|
||||
} else {
|
||||
initData->Path = filePath;
|
||||
}
|
||||
|
||||
auto formatString = parsed["format"];
|
||||
if (formatString == "XML") {
|
||||
initData->Format = RESOURCE_FORMAT_XML;
|
||||
}
|
||||
|
||||
initData->Type = Context::GetInstance()->GetResourceManager()->GetResourceLoader()->GetResourceType(parsed["type"]);
|
||||
initData->ResourceVersion = parsed["version"];
|
||||
|
||||
return initData;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceInitData> Archive::ReadResourceInitDataLegacy(const std::string& filePath,
|
||||
std::shared_ptr<File> fileToLoad) {
|
||||
// Determine if file is binary or XML...
|
||||
if (fileToLoad->Buffer->at(0) == '<') {
|
||||
// File is XML
|
||||
// Read the xml document
|
||||
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
|
||||
auto binaryReader = std::make_shared<BinaryReader>(stream);
|
||||
fileToLoad->Reader = std::make_shared<tinyxml2::XMLDocument>();
|
||||
auto xmlReader = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(fileToLoad->Reader);
|
||||
|
||||
auto xmlReader = std::make_shared<tinyxml2::XMLDocument>();
|
||||
|
||||
xmlReader->Parse(binaryReader->ReadCString().data());
|
||||
if (xmlReader->Error()) {
|
||||
SPDLOG_ERROR("Failed to parse XML file {}. Error: {}", filePath, xmlReader->ErrorStr());
|
||||
return nullptr;
|
||||
}
|
||||
fileToLoad->InitData = ReadResourceInitDataXml(filePath, xmlReader);
|
||||
return ReadResourceInitDataXml(filePath, xmlReader);
|
||||
} else {
|
||||
// File is Binary
|
||||
auto fileToLoadMeta = LoadFileMeta(filePath);
|
||||
auto headerBuffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(),
|
||||
fileToLoad->Buffer->begin() + OTR_HEADER_SIZE);
|
||||
|
||||
// Split out the header for reading.
|
||||
if (fileToLoadMeta != nullptr) {
|
||||
fileToLoad->Buffer =
|
||||
std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(), fileToLoad->Buffer->end());
|
||||
} else {
|
||||
auto headerBuffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(),
|
||||
fileToLoad->Buffer->begin() + OTR_HEADER_SIZE);
|
||||
|
||||
if (headerBuffer->size() < OTR_HEADER_SIZE) {
|
||||
SPDLOG_ERROR("Failed to parse ResourceInitData, buffer size too small. File: {}. Got {} bytes and "
|
||||
"needed {} bytes.",
|
||||
filePath, headerBuffer->size(), OTR_HEADER_SIZE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fileToLoad->Buffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE,
|
||||
fileToLoad->Buffer->end());
|
||||
|
||||
// Create a reader for the header buffer
|
||||
auto headerStream = std::make_shared<MemoryStream>(headerBuffer);
|
||||
auto headerReader = std::make_shared<BinaryReader>(headerStream);
|
||||
fileToLoadMeta = ReadResourceInitDataBinary(filePath, headerReader);
|
||||
if (headerBuffer->size() < OTR_HEADER_SIZE) {
|
||||
SPDLOG_ERROR("Failed to parse ResourceInitData, buffer size too small. File: {}. Got {} bytes and "
|
||||
"needed {} bytes.",
|
||||
filePath, headerBuffer->size(), OTR_HEADER_SIZE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a reader for the data buffer
|
||||
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
|
||||
fileToLoad->Reader = std::make_shared<BinaryReader>(stream);
|
||||
// Factories expect the buffer to not include the header,
|
||||
// so we need to remove it from the buffer on the file
|
||||
fileToLoad->Buffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE,
|
||||
fileToLoad->Buffer->end());
|
||||
|
||||
fileToLoad->InitData = fileToLoadMeta;
|
||||
auto binaryReader = std::get<std::shared_ptr<BinaryReader>>(fileToLoad->Reader);
|
||||
binaryReader->SetEndianness(fileToLoad->InitData->ByteOrder);
|
||||
// Create a reader for the header buffer
|
||||
auto headerStream = std::make_shared<MemoryStream>(headerBuffer);
|
||||
auto headerReader = std::make_shared<BinaryReader>(headerStream);
|
||||
return ReadResourceInitDataBinary(filePath, headerReader);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BinaryReader> Archive::CreateBinaryReader(std::shared_ptr<File> fileToLoad) {
|
||||
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
|
||||
auto reader = std::make_shared<BinaryReader>(stream);
|
||||
reader->SetEndianness(fileToLoad->InitData->ByteOrder);
|
||||
return reader;
|
||||
}
|
||||
|
||||
std::shared_ptr<tinyxml2::XMLDocument> Archive::CreateXMLReader(std::shared_ptr<File> fileToLoad) {
|
||||
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
|
||||
auto binaryReader = std::make_shared<BinaryReader>(stream);
|
||||
|
||||
auto xmlReader = std::make_shared<tinyxml2::XMLDocument>();
|
||||
|
||||
xmlReader->Parse(binaryReader->ReadCString().data());
|
||||
if (xmlReader->Error()) {
|
||||
SPDLOG_ERROR("Failed to parse XML file {}. Error: {}", fileToLoad->InitData->Path, xmlReader->ErrorStr());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return xmlReader;
|
||||
}
|
||||
|
||||
std::shared_ptr<File> Archive::LoadFile(const std::string& filePath) {
|
||||
auto metaFilePath = filePath + ".meta";
|
||||
auto metaFileToLoad = LoadFileRaw(metaFilePath);
|
||||
|
||||
std::shared_ptr<File> fileToLoad = nullptr;
|
||||
if (metaFileToLoad != nullptr) {
|
||||
auto initData = ReadResourceInitData(filePath, metaFileToLoad);
|
||||
fileToLoad = LoadFileRaw(initData->Path);
|
||||
fileToLoad->InitData = initData;
|
||||
} else {
|
||||
fileToLoad = LoadFileRaw(filePath);
|
||||
fileToLoad->InitData = ReadResourceInitDataLegacy(filePath, fileToLoad);
|
||||
}
|
||||
|
||||
if (fileToLoad == nullptr) {
|
||||
SPDLOG_ERROR("Failed to load file at path {}.", filePath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (fileToLoad->InitData->Format) {
|
||||
case RESOURCE_FORMAT_BINARY:
|
||||
fileToLoad->Reader = CreateBinaryReader(fileToLoad);
|
||||
break;
|
||||
case RESOURCE_FORMAT_XML:
|
||||
fileToLoad->Reader = CreateXMLReader(fileToLoad);
|
||||
break;
|
||||
}
|
||||
|
||||
return fileToLoad;
|
||||
|
||||
@@ -40,19 +40,22 @@ class Archive {
|
||||
virtual std::shared_ptr<File> LoadFileRaw(uint64_t hash) = 0;
|
||||
|
||||
protected:
|
||||
static std::shared_ptr<ResourceInitData> ReadResourceInitDataBinary(const std::string& filePath,
|
||||
std::shared_ptr<BinaryReader> headerReader);
|
||||
static std::shared_ptr<ResourceInitData> ReadResourceInitDataXml(const std::string& filePath,
|
||||
std::shared_ptr<tinyxml2::XMLDocument> document);
|
||||
virtual std::shared_ptr<ResourceInitData> LoadFileMeta(const std::string& filePath) = 0;
|
||||
virtual std::shared_ptr<ResourceInitData> LoadFileMeta(uint64_t hash) = 0;
|
||||
|
||||
void SetLoaded(bool isLoaded);
|
||||
void SetGameVersion(uint32_t gameVersion);
|
||||
void AddFile(const std::string& filePath);
|
||||
|
||||
private:
|
||||
static std::shared_ptr<ResourceInitData> CreateDefaultResourceInitData();
|
||||
std::shared_ptr<ResourceInitData> ReadResourceInitData(const std::string& filePath,
|
||||
std::shared_ptr<File> metaFileToLoad);
|
||||
std::shared_ptr<ResourceInitData> ReadResourceInitDataLegacy(const std::string& filePath,
|
||||
std::shared_ptr<File> fileToLoad);
|
||||
static std::shared_ptr<ResourceInitData> ReadResourceInitDataBinary(const std::string& filePath,
|
||||
std::shared_ptr<BinaryReader> headerReader);
|
||||
static std::shared_ptr<ResourceInitData> ReadResourceInitDataXml(const std::string& filePath,
|
||||
std::shared_ptr<tinyxml2::XMLDocument> document);
|
||||
std::shared_ptr<BinaryReader> CreateBinaryReader(std::shared_ptr<File> fileToLoad);
|
||||
std::shared_ptr<tinyxml2::XMLDocument> CreateXMLReader(std::shared_ptr<File> fileToLoad);
|
||||
|
||||
bool mIsLoaded;
|
||||
bool mHasGameVersion;
|
||||
|
||||
@@ -18,16 +18,6 @@ std::shared_ptr<File> O2rArchive::LoadFileRaw(const std::string& filePath) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceInitData> O2rArchive::LoadFileMeta(const std::string& filePath) {
|
||||
// Search for file with .meta postfix.
|
||||
// If exists, return a ResourceInitData with that data parsed out. Else return a default ResourceInitData
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceInitData> O2rArchive::LoadFileMeta(uint64_t hash) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool O2rArchive::LoadRaw() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -24,9 +24,6 @@ class O2rArchive : virtual public Archive {
|
||||
std::shared_ptr<File> LoadFileRaw(uint64_t hash);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ResourceInitData> LoadFileMeta(const std::string& filePath);
|
||||
std::shared_ptr<ResourceInitData> LoadFileMeta(uint64_t hash);
|
||||
|
||||
private:
|
||||
};
|
||||
} // namespace LUS
|
||||
|
||||
@@ -56,14 +56,6 @@ std::shared_ptr<File> OtrArchive::LoadFileRaw(uint64_t hash) {
|
||||
return LoadFileRaw(filePath);
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceInitData> OtrArchive::LoadFileMeta(const std::string& filePath) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceInitData> OtrArchive::LoadFileMeta(uint64_t hash) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool OtrArchive::LoadRaw() {
|
||||
const bool opened = SFileOpenArchive(GetPath().c_str(), 0, MPQ_OPEN_READ_ONLY, &mHandle);
|
||||
if (opened) {
|
||||
|
||||
@@ -30,9 +30,6 @@ class OtrArchive : virtual public Archive {
|
||||
std::shared_ptr<File> LoadFileRaw(uint64_t hash);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ResourceInitData> LoadFileMeta(const std::string& filePath);
|
||||
std::shared_ptr<ResourceInitData> LoadFileMeta(uint64_t hash);
|
||||
|
||||
private:
|
||||
HANDLE mHandle;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user