diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 5014b16a..7df53f59 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -2,6 +2,7 @@ #include "Game/T6/GameT6.h" #include "Game/T6/GameAssetPoolT6.h" #include "ObjContainer/IPak/IPak.h" +#include "ObjLoading.h" const int ObjLoaderT6::IPAK_READ_HASH = Com_HashKey("ipak_read", 64); const int ObjLoaderT6::GLOBAL_HASH = Com_HashKey("GLOBAL", 64); @@ -30,15 +31,36 @@ bool ObjLoaderT6::SupportsZone(Zone* zone) void ObjLoaderT6::LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone) { - printf("Loading ipak '%s' for zone '%s'\n", ipakName.c_str(), zone->m_name.c_str()); + if(ObjLoading::Configuration.Verbose) + { + printf("Loading ipak '%s' for zone '%s'\n", ipakName.c_str(), zone->m_name.c_str()); + } const std::string ipakFilename = ipakName + ".ipak"; auto* file = searchPath->Open(ipakFilename); - if(file && file->IsOpen()) { - + IPak* ipak = new IPak(ipakFilename, file); + + if(ipak->Initialize()) + { + IPak::Repository.AddContainer(ipak, zone); + } + else + { + delete ipak; + file->Close(); + delete file; + + printf("Failed to load ipak '%s'!\n", ipakFilename.c_str()); + } + } + + if(ipakName == "base") + { + LoadIPakForZone(searchPath, "mp", zone); + LoadIPakForZone(searchPath, "so", zone); } } @@ -49,11 +71,12 @@ void ObjLoaderT6::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* if(assetPoolT6->m_key_value_pairs != nullptr) { - for(auto* keyValuePairs : *assetPoolT6->m_key_value_pairs) + for(auto* keyValuePairsEntry : *assetPoolT6->m_key_value_pairs) { - for(int variableIndex = 0; variableIndex < keyValuePairs->m_asset->numVariables; variableIndex++) + auto* keyValuePairs = keyValuePairsEntry->m_asset; + for(int variableIndex = 0; variableIndex < keyValuePairs->numVariables; variableIndex++) { - T6::KeyValuePair* variable = &keyValuePairs->m_asset->keyValuePairs[variableIndex]; + T6::KeyValuePair* variable = &keyValuePairs->keyValuePairs[variableIndex]; if(variable->namespaceHash == zoneNameHash && variable->keyHash == IPAK_READ_HASH) { @@ -69,7 +92,53 @@ void ObjLoaderT6::UnloadContainersOfZone(Zone* zone) IPak::Repository.RemoveContainerReferences(zone); } +void ObjLoaderT6::LoadImageDataFromFile(T6::GfxImage* image, FileAPI::IFile* file, Zone* zone) +{ +} + +void ObjLoaderT6::LoadImageData(ISearchPath* searchPath, Zone* zone) +{ + auto* assetPoolT6 = dynamic_cast(zone->GetPools()); + + if (assetPoolT6->m_image != nullptr) + { + for (auto* imageEntry : *assetPoolT6->m_image) + { + auto* image = imageEntry->m_asset; + + // TODO: Enable this when loadDef is no longer loaded into the temp block and never updated. + // if(image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + // { + // continue; + // } + + std::string imageFileName = "images/" + std::string(image->name) + ".iwi"; + auto* filePathImage = searchPath->Open(imageFileName); + if(filePathImage != nullptr && filePathImage->IsOpen()) + { + LoadImageDataFromFile(image, filePathImage, zone); + filePathImage->Close(); + delete filePathImage; + } + else if(image->streamedPartCount > 0) + { + for (auto* ipak : IPak::Repository) + { + auto* ipakEntry = ipak->GetEntryData(image->hash, image->streamedParts[0].hash); + + if (ipakEntry != nullptr && ipakEntry->IsOpen()) + { + LoadImageDataFromFile(image, ipakEntry, zone); + ipakEntry->Close(); + delete ipakEntry; + } + } + } + } + } +} + void ObjLoaderT6::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) { - // TODO + LoadImageData(searchPath, zone); } diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.h b/src/ObjLoading/Game/T6/ObjLoaderT6.h index 0ff86dc1..6d8b2d20 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.h +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.h @@ -2,6 +2,7 @@ #include "IObjLoader.h" #include "SearchPath/ISearchPath.h" +#include "Game/T6/T6.h" class ObjLoaderT6 final : public IObjLoader { @@ -11,6 +12,9 @@ class ObjLoaderT6 final : public IObjLoader static void LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone); + static void LoadImageDataFromFile(T6::GfxImage* image, FileAPI::IFile* file, Zone* zone); + static void LoadImageData(ISearchPath* searchPath, Zone* zone); + public: bool SupportsZone(Zone* zone) override; diff --git a/src/ObjLoading/ObjContainer/IPak/IPak.cpp b/src/ObjLoading/ObjContainer/IPak/IPak.cpp index 346c0742..d887d849 100644 --- a/src/ObjLoading/ObjContainer/IPak/IPak.cpp +++ b/src/ObjLoading/ObjContainer/IPak/IPak.cpp @@ -1,131 +1,223 @@ #include "IPak.h" #include "zlib.h" #include "Exception/IPakLoadException.h" - -#include +#include "ObjContainer/IPak/IPakTypes.h" #include "Utils/PathUtils.h" -const uint32_t IPak::MAGIC = 'IPAK'; -const uint32_t IPak::VERSION = 0x50000; +#include +#include ObjContainerRepository IPak::Repository; -uint32_t IPak::R_HashString(const char* str, uint32_t hash) +class IPak::Impl : public ObjContainerReferenceable { - for (const char* pos = str; *pos; pos++) + static const uint32_t MAGIC = 'IPAK'; + static const uint32_t VERSION = 0x50000; + + std::string m_path; + FileAPI::IFile* m_file; + + bool m_initialized; + + IPakSection* m_index_section; + IPakSection* m_data_section; + + std::vector m_index_entries; + + static uint32_t R_HashString(const char* str, uint32_t hash) { - hash = 33 * hash ^ (*pos | 0x20); + for (const char* pos = str; *pos; pos++) + { + hash = 33 * hash ^ (*pos | 0x20); + } + + return hash; } - return hash; -} + bool ReadIndexSection() + { + m_file->Goto(m_index_section->offset); + IPakIndexEntry indexEntry{}; + + for (unsigned itemIndex = 0; itemIndex < m_index_section->itemCount; itemIndex++) + { + if (m_file->Read(&indexEntry, sizeof indexEntry, 1) != 1) + { + printf("Unexpected eof when trying to load index entry %u.\n", itemIndex); + return false; + } + + m_index_entries.push_back(indexEntry); + } + + return true; + } + + bool ReadSection() + { + IPakSection section{}; + + if (m_file->Read(§ion, sizeof section, 1) != 1) + { + printf("Unexpected eof when trying to load section.\n"); + return false; + } + + switch (section.type) + { + case 1: + m_index_section = new IPakSection(section); + break; + + case 2: + m_data_section = new IPakSection(section); + break; + + default: + break; + } + + return true; + } + + bool ReadHeader() + { + IPakHeader header{}; + + if (m_file->Read(&header, sizeof header, 1) != 1) + { + printf("Unexpected eof when trying to load header.\n"); + return false; + } + + if (header.magic != MAGIC) + { + printf("Invalid ipak magic '0x%x'.\n", header.magic); + return false; + } + + if (header.version != VERSION) + { + printf("Unsupported ipak version '%u'.\n", header.version); + return false; + } + + for (unsigned section = 0; section < header.sectionCount; section++) + { + if (!ReadSection()) + return false; + } + + if (m_index_section == nullptr) + { + printf("IPak does not contain an index section.\n"); + return false; + } + + if (m_data_section == nullptr) + { + printf("IPak does not contain a data section.\n"); + return false; + } + + if (!ReadIndexSection()) + return false; + + return true; + } + +public: + Impl(std::string path, FileAPI::IFile* file) + { + m_path = std::move(path); + m_file = file; + m_initialized = false; + m_index_section = nullptr; + m_data_section = nullptr; + } + + ~Impl() + { + delete m_index_section; + m_index_section = nullptr; + + delete m_data_section; + m_data_section = nullptr; + } + + std::string GetName() override + { + return utils::Path::GetFilename(m_path); + } + + bool Initialize() + { + if (m_initialized) + return true; + + if (!ReadHeader()) + return false; + + m_initialized = true; + return true; + } + + FileAPI::IFile* GetEntryData(const Hash nameHash, const Hash dataHash) + { + for(auto& entry : m_index_entries) + { + if(entry.key.nameHash == nameHash && entry.key.dataHash == dataHash) + { + __asm nop; + } + } + + return nullptr; + } + + static Hash HashString(const std::string& str) + { + return R_HashString(str.c_str(), 0); + } + + static Hash HashData(const void* data, const size_t dataSize) + { + return crc32(0, static_cast(data), dataSize); + } +}; IPak::IPak(std::string path, FileAPI::IFile* file) { - m_path = std::move(path); - m_file = file; - m_initialized = false; - m_index_section = nullptr; - m_data_section = nullptr; + m_impl = new Impl(std::move(path), file); } IPak::~IPak() { - delete m_index_section; - m_index_section = nullptr; - - delete m_data_section; - m_data_section = nullptr; + delete m_impl; + m_impl = nullptr; } std::string IPak::GetName() { - return utils::Path::GetFilename(m_path); + return m_impl->GetName(); } -void IPak::ReadSection() +bool IPak::Initialize() const { - IPakSection section{}; - - if (m_file->Read(§ion, sizeof section, 1) != sizeof section) - throw IPakLoadException("Unexpected eof when trying to load section."); - - switch (section.type) - { - case 1: - m_index_section = new IPakSection(section); - break; - - case 2: - m_data_section = new IPakSection(section); - break; - - default: - break; - } + return m_impl->Initialize(); } -void IPak::ReadHeader() +FileAPI::IFile* IPak::GetEntryData(const Hash nameHash, const Hash dataHash) const { - IPakHeader header{}; - - if (m_file->Read(&header, sizeof header, 1) != sizeof header) - throw IPakLoadException("Unexpected eof when trying to load header."); - - if (header.magic != MAGIC) - { - std::ostringstream oss; - oss << "Invalid magic '0x" << std::hex << header.magic << "'."; - - throw IPakLoadException(oss.str()); - } - - if(header.version != VERSION) - { - std::ostringstream oss; - oss << "Unsupported version '" << header.version << "'."; - - throw IPakLoadException(oss.str()); - } - - for(unsigned section = 0; section < header.sectionCount; section++) - { - ReadSection(); - } - - if(m_index_section == nullptr) - { - throw IPakLoadException("IPak does not contain an index section."); - } - - if(m_data_section == nullptr) - { - throw IPakLoadException("IPak does not contain a data section."); - } + return m_impl->GetEntryData(nameHash, dataHash); } -void IPak::Initialize() +IPak::Hash IPak::HashString(const std::string& str) { - if (m_initialized) - return; - - ReadHeader(); - - m_initialized = true; + return Impl::HashString(str); } -FileAPI::IFile* IPak::GetEntryData(IPakHash nameHash, IPakHash dataHash) +IPak::Hash IPak::HashData(const void* data, const size_t dataSize) { - // TODO - return nullptr; -} - -IPakHash IPak::HashString(const std::string& str) -{ - return R_HashString(str.c_str(), 0); -} - -IPakHash IPak::HashData(const void* data, const size_t dataSize) -{ - return crc32(0, static_cast(data), dataSize); + return Impl::HashData(data, dataSize); } \ No newline at end of file diff --git a/src/ObjLoading/ObjContainer/IPak/IPak.h b/src/ObjLoading/ObjContainer/IPak/IPak.h index ec91d137..c76c9d80 100644 --- a/src/ObjLoading/ObjContainer/IPak/IPak.h +++ b/src/ObjLoading/ObjContainer/IPak/IPak.h @@ -1,34 +1,18 @@ #pragma once #include "Utils/FileAPI.h" -#include "ObjContainer/IPak/IPakTypes.h" #include "ObjContainer/ObjContainerReferenceable.h" #include "ObjContainer/ObjContainerRepository.h" #include "Zone/Zone.h" -#include - class IPak final : public ObjContainerReferenceable { - static const uint32_t MAGIC; - static const uint32_t VERSION; - - std::string m_path; - FileAPI::IFile* m_file; - - bool m_initialized; - - IPakSection* m_index_section; - IPakSection* m_data_section; - - std::vector m_index_entries; - - static uint32_t R_HashString(const char* str, uint32_t hash); - - void ReadSection(); - void ReadHeader(); + class Impl; + Impl* m_impl; public: + typedef uint32_t Hash; + static ObjContainerRepository Repository; IPak(std::string path, FileAPI::IFile* file); @@ -36,9 +20,9 @@ public: std::string GetName() override; - void Initialize(); - FileAPI::IFile* GetEntryData(IPakHash nameHash, IPakHash dataHash); + bool Initialize() const; + FileAPI::IFile* GetEntryData(Hash nameHash, Hash dataHash) const; - static IPakHash HashString(const std::string& str); - static IPakHash HashData(const void* data, size_t dataSize); + static Hash HashString(const std::string& str); + static Hash HashData(const void* data, size_t dataSize); };