mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
ObjLoading: Be able to load and index IWD files
This commit is contained in:
parent
a4d55ffae7
commit
0abdb64832
@ -2,6 +2,7 @@ ObjCommon = {}
|
||||
|
||||
function ObjCommon:include()
|
||||
ZoneCommon:include()
|
||||
minizip:include()
|
||||
includedirs {
|
||||
path.join(ProjectFolder(), "ObjCommon")
|
||||
}
|
||||
@ -10,6 +11,7 @@ end
|
||||
function ObjCommon:link()
|
||||
Utils:link()
|
||||
ZoneCommon:link()
|
||||
minizip:link()
|
||||
links {
|
||||
"ObjCommon"
|
||||
}
|
||||
|
@ -7,5 +7,5 @@ class IObjContainer
|
||||
public:
|
||||
virtual ~IObjContainer() = default;
|
||||
|
||||
virtual const std::string& GetName() = 0;
|
||||
virtual std::string GetName() = 0;
|
||||
};
|
87
src/ObjCommon/Utils/ZlibFileWrapper.cpp
Normal file
87
src/ObjCommon/Utils/ZlibFileWrapper.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "ZlibFileWrapper.h"
|
||||
#include <cassert>
|
||||
|
||||
voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int)
|
||||
{
|
||||
return opaque;
|
||||
}
|
||||
|
||||
uLong Wrapper_Zlib_FileRead(voidpf, voidpf stream, void* buf, const uLong size)
|
||||
{
|
||||
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
|
||||
|
||||
return file->Read(buf, 1, size);
|
||||
}
|
||||
|
||||
uLong Wrapper_Zlib_FileWrite(voidpf opaque, voidpf stream, const void* buf, const uLong size)
|
||||
{
|
||||
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
|
||||
|
||||
return file->Write(buf, 1, size);
|
||||
}
|
||||
|
||||
long Wrapper_Zlib_FileTell(voidpf opaque, voidpf stream)
|
||||
{
|
||||
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
|
||||
|
||||
return static_cast<long>(file->Pos());
|
||||
}
|
||||
|
||||
long Wrapper_Zlib_FileSeek(voidpf opaque, voidpf stream, const uLong offset, const int origin)
|
||||
{
|
||||
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
case ZLIB_FILEFUNC_SEEK_CUR:
|
||||
file->Skip(offset);
|
||||
break;
|
||||
|
||||
case ZLIB_FILEFUNC_SEEK_END:
|
||||
assert(offset == 0);
|
||||
file->GotoEnd();
|
||||
break;
|
||||
|
||||
case ZLIB_FILEFUNC_SEEK_SET:
|
||||
file->Goto(offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wrapper_Zlib_FileClose(voidpf opaque, voidpf stream)
|
||||
{
|
||||
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
|
||||
|
||||
if (file->IsOpen())
|
||||
{
|
||||
file->Close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
zlib_filefunc_def ZlibFileWrapper::CreateFunctions32ForFile(FileAPI::IFile* file)
|
||||
{
|
||||
return zlib_filefunc_def_s
|
||||
{
|
||||
Wrapper_Zlib_FileOpen,
|
||||
Wrapper_Zlib_FileRead,
|
||||
Wrapper_Zlib_FileWrite,
|
||||
Wrapper_Zlib_FileTell,
|
||||
Wrapper_Zlib_FileSeek,
|
||||
Wrapper_Zlib_FileClose,
|
||||
Wrapper_Zlib_FileError,
|
||||
file
|
||||
};
|
||||
}
|
10
src/ObjCommon/Utils/ZlibFileWrapper.h
Normal file
10
src/ObjCommon/Utils/ZlibFileWrapper.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <ioapi.h>
|
||||
#include "Utils/FileAPI.h"
|
||||
|
||||
class ZlibFileWrapper
|
||||
{
|
||||
public:
|
||||
static zlib_filefunc_def CreateFunctions32ForFile(FileAPI::IFile* file);
|
||||
};
|
@ -1,9 +1,10 @@
|
||||
#include "ObjLoaderT6.h"
|
||||
#include "Game/T6/GameT6.h"
|
||||
#include "Game/T6/GameAssetPoolT6.h"
|
||||
#include "ObjContainer/IPak/IPak.h"
|
||||
|
||||
const int ObjLoaderT6::IPAK_READ_HASH = ObjLoaderT6::Com_HashKey("ipak_read", 64);
|
||||
const int ObjLoaderT6::GLOBAL_HASH = ObjLoaderT6::Com_HashKey("GLOBAL", 64);
|
||||
const int ObjLoaderT6::IPAK_READ_HASH = Com_HashKey("ipak_read", 64);
|
||||
const int ObjLoaderT6::GLOBAL_HASH = Com_HashKey("GLOBAL", 64);
|
||||
|
||||
int ObjLoaderT6::Com_HashKey(const char* str, const int maxLen)
|
||||
{
|
||||
@ -27,10 +28,18 @@ bool ObjLoaderT6::SupportsZone(Zone* zone)
|
||||
return zone->m_game == &g_GameT6;
|
||||
}
|
||||
|
||||
void ObjLoaderT6::LoadIPakForZone(const std::string& ipakName, 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());
|
||||
// TODO
|
||||
|
||||
const std::string ipakFilename = ipakName + ".ipak";
|
||||
|
||||
auto* file = searchPath->Open(ipakFilename);
|
||||
|
||||
if(file && file->IsOpen())
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ObjLoaderT6::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone)
|
||||
@ -48,13 +57,18 @@ void ObjLoaderT6::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone*
|
||||
|
||||
if(variable->namespaceHash == zoneNameHash && variable->keyHash == IPAK_READ_HASH)
|
||||
{
|
||||
LoadIPakForZone(variable->value, zone);
|
||||
LoadIPakForZone(searchPath, variable->value, zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjLoaderT6::UnloadContainersOfZone(Zone* zone)
|
||||
{
|
||||
IPak::Repository.RemoveContainerReferences(zone);
|
||||
}
|
||||
|
||||
void ObjLoaderT6::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone)
|
||||
{
|
||||
// TODO
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "IObjLoader.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
|
||||
class ObjLoaderT6 final : public IObjLoader
|
||||
{
|
||||
@ -8,10 +9,13 @@ class ObjLoaderT6 final : public IObjLoader
|
||||
static const int GLOBAL_HASH;
|
||||
static int Com_HashKey(const char* str, int maxLen);
|
||||
|
||||
static void LoadIPakForZone(const std::string& ipakName, Zone* zone);
|
||||
static void LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone);
|
||||
|
||||
public:
|
||||
bool SupportsZone(Zone* zone) override;
|
||||
|
||||
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) override;
|
||||
void UnloadContainersOfZone(Zone* zone) override;
|
||||
|
||||
void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) override;
|
||||
};
|
||||
|
@ -9,6 +9,9 @@ public:
|
||||
virtual ~IObjLoader() = default;
|
||||
|
||||
virtual bool SupportsZone(Zone* zone) = 0;
|
||||
|
||||
virtual void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) = 0;
|
||||
virtual void UnloadContainersOfZone(Zone* zone) = 0;
|
||||
|
||||
virtual void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) = 0;
|
||||
};
|
@ -3,10 +3,13 @@
|
||||
#include "Exception/IPakLoadException.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "Utils/PathUtils.h"
|
||||
|
||||
const uint32_t IPak::MAGIC = 'IPAK';
|
||||
const uint32_t IPak::VERSION = 0x50000;
|
||||
|
||||
ObjContainerRepository<IPak, Zone> IPak::Repository;
|
||||
|
||||
uint32_t IPak::R_HashString(const char* str, uint32_t hash)
|
||||
{
|
||||
for (const char* pos = str; *pos; pos++)
|
||||
@ -17,8 +20,9 @@ uint32_t IPak::R_HashString(const char* str, uint32_t hash)
|
||||
return hash;
|
||||
}
|
||||
|
||||
IPak::IPak(FileAPI::IFile* file)
|
||||
IPak::IPak(std::string path, FileAPI::IFile* file)
|
||||
{
|
||||
m_path = std::move(path);
|
||||
m_file = file;
|
||||
m_initialized = false;
|
||||
m_index_section = nullptr;
|
||||
@ -34,6 +38,11 @@ IPak::~IPak()
|
||||
m_data_section = nullptr;
|
||||
}
|
||||
|
||||
std::string IPak::GetName()
|
||||
{
|
||||
return utils::Path::GetFilename(m_path);
|
||||
}
|
||||
|
||||
void IPak::ReadSection()
|
||||
{
|
||||
IPakSection section{};
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "Utils/FileAPI.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
#include "ObjContainer/ObjContainerReferenceable.h"
|
||||
#include "ObjContainer/ObjContainerRepository.h"
|
||||
#include "Zone/Zone.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -11,6 +13,7 @@ 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;
|
||||
@ -26,9 +29,13 @@ class IPak final : public ObjContainerReferenceable
|
||||
void ReadHeader();
|
||||
|
||||
public:
|
||||
explicit IPak(FileAPI::IFile* file);
|
||||
static ObjContainerRepository<IPak, Zone> Repository;
|
||||
|
||||
IPak(std::string path, FileAPI::IFile* file);
|
||||
~IPak();
|
||||
|
||||
std::string GetName() override;
|
||||
|
||||
void Initialize();
|
||||
FileAPI::IFile* GetEntryData(IPakHash nameHash, IPakHash dataHash);
|
||||
|
||||
|
@ -1,32 +1,166 @@
|
||||
#include "IWD.h"
|
||||
|
||||
IWD::IWD(std::string path)
|
||||
#include <unzip.h>
|
||||
#include <cassert>
|
||||
#include "Utils/PathUtils.h"
|
||||
#include "Utils/ZlibFileWrapper.h"
|
||||
#include <filesystem>
|
||||
#include "ObjLoading.h"
|
||||
|
||||
ObjContainerRepository<IWD, ISearchPath> IWD::Repository;
|
||||
|
||||
class IWD::Impl : public ISearchPath, IObjContainer
|
||||
{
|
||||
class IWDEntry
|
||||
{
|
||||
public:
|
||||
std::string m_name;
|
||||
unz_file_pos m_file_pos;
|
||||
};
|
||||
|
||||
std::string m_path;
|
||||
FileAPI::IFile* m_file;
|
||||
unzFile m_unz_file;
|
||||
|
||||
std::vector<IWDEntry> m_entries;
|
||||
|
||||
public:
|
||||
Impl(std::string path, FileAPI::IFile* file)
|
||||
{
|
||||
m_unz_file = nullptr;
|
||||
m_path = std::move(path);
|
||||
m_file = file;
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
if (m_unz_file != nullptr)
|
||||
{
|
||||
unzClose(m_unz_file);
|
||||
}
|
||||
|
||||
if (m_file)
|
||||
{
|
||||
m_file->Close();
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Initialize()
|
||||
{
|
||||
auto ioFunctions = ZlibFileWrapper::CreateFunctions32ForFile(m_file);
|
||||
m_unz_file = unzOpen2("", &ioFunctions);
|
||||
|
||||
if (m_unz_file == nullptr)
|
||||
{
|
||||
printf("Could not open IWD \"%s\"\n", m_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ret = unzGoToFirstFile(m_unz_file);
|
||||
while (ret == Z_OK)
|
||||
{
|
||||
unz_file_info info;
|
||||
char fileNameBuffer[256];
|
||||
unzGetCurrentFileInfo(m_unz_file, &info, fileNameBuffer, sizeof fileNameBuffer, nullptr, 0, nullptr, 0);
|
||||
|
||||
std::string fileName(fileNameBuffer);
|
||||
std::filesystem::path path(fileName);
|
||||
|
||||
if (path.has_filename())
|
||||
{
|
||||
IWDEntry entry;
|
||||
entry.m_name = std::move(fileName);
|
||||
unzGetFilePos(m_unz_file, &entry.m_file_pos);
|
||||
m_entries.push_back(entry);
|
||||
}
|
||||
|
||||
ret = unzGoToNextFile(m_unz_file);
|
||||
}
|
||||
|
||||
if(ObjLoading::Configuration.Verbose)
|
||||
{
|
||||
printf("Loaded IWD \"%s\" with %u entries\n", m_path.c_str(), m_entries.size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override
|
||||
{
|
||||
if (m_unz_file == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string GetPath() override
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
std::string GetName() override
|
||||
{
|
||||
return utils::Path::GetFilename(m_path);
|
||||
}
|
||||
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
};
|
||||
|
||||
IWD::IWD(std::string path, FileAPI::IFile* file)
|
||||
{
|
||||
m_impl = new Impl(std::move(path), file);
|
||||
}
|
||||
|
||||
IWD::~IWD()
|
||||
{
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
IWD::IWD(IWD&& other) noexcept
|
||||
{
|
||||
m_impl = other.m_impl;
|
||||
other.m_impl = nullptr;
|
||||
}
|
||||
|
||||
IWD& IWD::operator=(IWD&& other) noexcept
|
||||
{
|
||||
m_impl = other.m_impl;
|
||||
other.m_impl = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IWD::Initialize() const
|
||||
{
|
||||
return m_impl->Initialize();
|
||||
}
|
||||
|
||||
FileAPI::IFile* IWD::Open(const std::string& fileName)
|
||||
{
|
||||
// TODO
|
||||
return nullptr;
|
||||
return m_impl->Open(fileName);
|
||||
}
|
||||
|
||||
void IWD::FindAll(std::function<void(const std::string&)> callback)
|
||||
std::string IWD::GetPath()
|
||||
{
|
||||
// TODO
|
||||
return m_impl->GetPath();
|
||||
}
|
||||
|
||||
void IWD::FindAllOnDisk(std::function<void(const std::string&)> callback)
|
||||
std::string IWD::GetName()
|
||||
{
|
||||
// Files inside an IWD are not on the disk's file system directly. Therefore do nothing here.
|
||||
return m_impl->GetName();
|
||||
}
|
||||
|
||||
void IWD::FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback)
|
||||
void IWD::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void IWD::FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback)
|
||||
{
|
||||
// Files inside an IWD are not on the disk's file system directly. Therefore do nothing here.
|
||||
return m_impl->Find(options, callback);
|
||||
}
|
||||
|
@ -1,17 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "ObjContainer/ObjContainerRepository.h"
|
||||
|
||||
class IWD final : public ISearchPath
|
||||
class IWD final : public ISearchPath, IObjContainer
|
||||
{
|
||||
std::string m_path;
|
||||
class Impl;
|
||||
Impl* m_impl;
|
||||
|
||||
public:
|
||||
explicit IWD(std::string path);
|
||||
static ObjContainerRepository<IWD, ISearchPath> Repository;
|
||||
|
||||
IWD(std::string path, FileAPI::IFile* file);
|
||||
~IWD();
|
||||
|
||||
IWD(const IWD& other) = delete;
|
||||
IWD(IWD&& other) noexcept;
|
||||
IWD& operator=(const IWD& other) = delete;
|
||||
IWD& operator=(IWD&& other) noexcept;
|
||||
|
||||
bool Initialize() const;
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override;
|
||||
void FindAll(std::function<void(const std::string&)> callback) override;
|
||||
void FindAllOnDisk(std::function<void(const std::string&)> callback) override;
|
||||
void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
|
||||
void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
|
||||
std::string GetPath() override;
|
||||
std::string GetName() override;
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||
};
|
@ -1,52 +0,0 @@
|
||||
#include "ObjContainerRegistry.h"
|
||||
#include <cassert>
|
||||
|
||||
ObjContainerRegistry g_ObjContainerRegistry;
|
||||
|
||||
IObjContainer* ObjContainerRegistry::GetContainerByName(const std::string& name)
|
||||
{
|
||||
for (auto* container : m_containers)
|
||||
{
|
||||
if (container->GetName() == name)
|
||||
{
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ObjContainerRegistry::AddContainer(IObjContainer* container)
|
||||
{
|
||||
assert(dynamic_cast<ObjContainerReferenceable*>(container) == nullptr);
|
||||
|
||||
m_containers.push_back(container);
|
||||
}
|
||||
|
||||
void ObjContainerRegistry::AddContainerWithReference(ObjContainerReferenceable* container, Zone* referencer)
|
||||
{
|
||||
container->AddReference(referencer);
|
||||
m_containers.push_back(container);
|
||||
}
|
||||
|
||||
void ObjContainerRegistry::RemoveContainerReferences(Zone* referencer)
|
||||
{
|
||||
auto iContainer = m_containers.begin();
|
||||
|
||||
while (iContainer != m_containers.end())
|
||||
{
|
||||
auto* container = *iContainer;
|
||||
|
||||
if (auto* referenceableContainer = dynamic_cast<ObjContainerReferenceable*>(container))
|
||||
{
|
||||
if (referenceableContainer->RemoveReference(referencer) && !referenceableContainer->IsReferenced())
|
||||
{
|
||||
delete container;
|
||||
iContainer = m_containers.erase(iContainer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++iContainer;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ObjContainer/IObjContainer.h"
|
||||
#include "ObjContainer/ObjContainerReferenceable.h"
|
||||
#include "Zone/Zone.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ObjContainerRegistry
|
||||
{
|
||||
std::vector<IObjContainer*> m_containers;
|
||||
|
||||
public:
|
||||
void AddContainer(IObjContainer* container);
|
||||
void AddContainerWithReference(ObjContainerReferenceable* container, Zone* referencer);
|
||||
void RemoveContainerReferences(Zone* referencer);
|
||||
|
||||
IObjContainer* GetContainerByName(const std::string& name);
|
||||
};
|
||||
|
||||
extern ObjContainerRegistry g_ObjContainerRegistry;
|
93
src/ObjLoading/ObjContainer/ObjContainerRepository.h
Normal file
93
src/ObjLoading/ObjContainer/ObjContainerRepository.h
Normal file
@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include "ObjContainer/IObjContainer.h"
|
||||
#include "Utils/TransformIterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
template <typename ContainerType, typename ReferencerType>
|
||||
class ObjContainerRepository
|
||||
{
|
||||
class ObjContainerEntry
|
||||
{
|
||||
public:
|
||||
ContainerType* m_container;
|
||||
std::set<ReferencerType*> m_references;
|
||||
|
||||
explicit ObjContainerEntry(ContainerType* container)
|
||||
{
|
||||
m_container = container;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<ObjContainerEntry> m_containers;
|
||||
|
||||
public:
|
||||
void AddContainer(ContainerType* container, ReferencerType* referencer)
|
||||
{
|
||||
auto firstEntry = std::find_if(m_containers.begin(), m_containers.end(),
|
||||
[container](ObjContainerEntry& entry) -> bool
|
||||
{
|
||||
return entry.m_container == container;
|
||||
});
|
||||
|
||||
if(firstEntry != m_containers.end())
|
||||
{
|
||||
firstEntry->m_references.insert(referencer);
|
||||
return;
|
||||
}
|
||||
|
||||
ObjContainerEntry entry(container);
|
||||
entry.m_references.insert(referencer);
|
||||
m_containers.push_back(entry);
|
||||
}
|
||||
|
||||
void RemoveContainerReferences(ReferencerType* referencer)
|
||||
{
|
||||
for(auto iEntry = m_containers.begin(); iEntry != m_containers.end(); ++iEntry)
|
||||
{
|
||||
auto foundReference = iEntry->m_references.find(referencer);
|
||||
|
||||
if(foundReference != iEntry->m_references.end())
|
||||
{
|
||||
iEntry->m_references.erase(foundReference);
|
||||
}
|
||||
|
||||
if(iEntry->m_references.empty())
|
||||
{
|
||||
delete iEntry->m_container;
|
||||
m_containers.erase(iEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IObjContainer* GetContainerByName(const std::string& name)
|
||||
{
|
||||
auto foundEntry = std::find_if(m_containers.begin(), m_containers.end(), [name](ObjContainerEntry& entry) -> bool
|
||||
{
|
||||
return entry.m_container->GetName() == name;
|
||||
});
|
||||
|
||||
if(foundEntry != m_containers.end())
|
||||
{
|
||||
return foundEntry->m_container;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> begin()
|
||||
{
|
||||
return TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*>(
|
||||
m_containers.begin(), [](ObjContainerEntry& entry) -> ContainerType* { return entry.m_container; });
|
||||
}
|
||||
|
||||
TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> end()
|
||||
{
|
||||
return TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*>(
|
||||
m_containers.end(), [](ObjContainerEntry& entry) -> ContainerType* { return entry.m_container; });
|
||||
}
|
||||
};
|
@ -1,13 +1,18 @@
|
||||
#include "ObjLoading.h"
|
||||
#include "IObjLoader.h"
|
||||
#include "Game/T6/ObjLoaderT6.h"
|
||||
#include "ObjContainer/ObjContainerRegistry.h"
|
||||
#include "ObjContainer/IWD/IWD.h"
|
||||
#include "SearchPath/SearchPaths.h"
|
||||
|
||||
ObjLoading::Configuration_t ObjLoading::Configuration;
|
||||
|
||||
IObjLoader* objLoaders[]
|
||||
{
|
||||
new ObjLoaderT6()
|
||||
};
|
||||
|
||||
SearchPaths iwdSearchPaths;
|
||||
|
||||
void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone)
|
||||
{
|
||||
for (auto* loader : objLoaders)
|
||||
@ -34,5 +39,49 @@ void ObjLoading::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone)
|
||||
|
||||
void ObjLoading::UnloadContainersOfZone(Zone* zone)
|
||||
{
|
||||
g_ObjContainerRegistry.RemoveContainerReferences(zone);
|
||||
for (auto* loader : objLoaders)
|
||||
{
|
||||
if (loader->SupportsZone(zone))
|
||||
{
|
||||
loader->UnloadContainersOfZone(zone);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath)
|
||||
{
|
||||
searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"),
|
||||
[searchPath](const std::string& path) -> void
|
||||
{
|
||||
auto file = FileAPI::Open(path, FileAPI::Mode::MODE_READ);
|
||||
|
||||
if (file.IsOpen())
|
||||
{
|
||||
const auto fileP = new FileAPI::File(std::move(file));
|
||||
IWD* iwd = new IWD(path, fileP);
|
||||
|
||||
if (iwd->Initialize())
|
||||
{
|
||||
IWD::Repository.AddContainer(iwd, searchPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete iwd;
|
||||
|
||||
fileP->Close();
|
||||
delete fileP;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath)
|
||||
{
|
||||
IWD::Repository.RemoveContainerReferences(searchPath);
|
||||
}
|
||||
|
||||
ISearchPath* ObjLoading::GetIWDSearchPaths()
|
||||
{
|
||||
return &iwdSearchPaths;
|
||||
}
|
||||
|
@ -6,8 +6,18 @@
|
||||
class ObjLoading
|
||||
{
|
||||
public:
|
||||
static class Configuration_t
|
||||
{
|
||||
public:
|
||||
bool Verbose = false;
|
||||
} Configuration;
|
||||
|
||||
static void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone);
|
||||
static void UnloadContainersOfZone(Zone* zone);
|
||||
|
||||
static void LoadIWDsInSearchPath(ISearchPath* searchPath);
|
||||
static void UnloadIWDsInSearchPath(ISearchPath* searchPath);
|
||||
static ISearchPath* GetIWDSearchPaths();
|
||||
|
||||
static void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone);
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "SearchPathSearchOptions.h"
|
||||
#include "Utils/FileAPI.h"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class ISearchPath
|
||||
@ -16,29 +16,25 @@ public:
|
||||
*/
|
||||
virtual FileAPI::IFile* Open(const std::string& fileName) = 0;
|
||||
|
||||
/**
|
||||
* \brief Returns the path to the search path.
|
||||
* \return The path to the search path.
|
||||
*/
|
||||
virtual std::string GetPath() = 0;
|
||||
|
||||
/**
|
||||
* \brief Iterates through all files of the search path.
|
||||
* \param callback The callback to call for each found file with it's path relative to the search path.
|
||||
* \param options Options that modify the search.
|
||||
*/
|
||||
virtual void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) = 0;
|
||||
|
||||
/**
|
||||
* \brief Iterates through all files of the search path.
|
||||
* \param callback The callback to call for each found file with it's path relative to the search path.
|
||||
*/
|
||||
virtual void FindAll(std::function<void(const std::string&)> callback) = 0;
|
||||
|
||||
/**
|
||||
* \brief Iterates through all files available through the OS file system.
|
||||
* \param callback The callback to call for each found file with it's full path.
|
||||
*/
|
||||
virtual void FindAllOnDisk(std::function<void(const std::string&)> callback) = 0;
|
||||
|
||||
/**
|
||||
* \brief Iterates through all files of the search path with the specified extension.
|
||||
* \param extension The extension of all files to find.
|
||||
* \param callback The callback to call for each found file with it's path relative to the search path.
|
||||
*/
|
||||
virtual void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) = 0;
|
||||
|
||||
/**
|
||||
* \brief Iterates through all files available through the OS file system with the specified extension.
|
||||
* \param extension The extension of all files to find.
|
||||
* \param callback The callback to call for each found file with it's full path.
|
||||
*/
|
||||
virtual void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) = 0;
|
||||
void Find(const std::function<void(const std::string&)>& callback)
|
||||
{
|
||||
Find(SearchPathSearchOptions(), callback);
|
||||
}
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ SearchPathFilesystem::SearchPathFilesystem(std::string path)
|
||||
m_path = std::move(path);
|
||||
}
|
||||
|
||||
const std::string& SearchPathFilesystem::GetPath() const
|
||||
std::string SearchPathFilesystem::GetPath()
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
@ -25,55 +25,28 @@ FileAPI::IFile* SearchPathFilesystem::Open(const std::string& fileName)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SearchPathFilesystem::FindAll(const std::function<void(const std::string&)> callback)
|
||||
void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
||||
{
|
||||
if (options.m_should_include_subdirectories)
|
||||
{
|
||||
std::filesystem::recursive_directory_iterator iterator(m_path);
|
||||
|
||||
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
||||
{
|
||||
callback(entry->path().string());
|
||||
auto path = entry->path();
|
||||
if (options.m_filter_extensions && path.extension().string() != options.m_extension)
|
||||
continue;
|
||||
callback(options.m_absolute_paths ? absolute(path).string() : path.string());
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPathFilesystem::FindAllOnDisk(const std::function<void(const std::string&)> callback)
|
||||
{
|
||||
std::filesystem::recursive_directory_iterator iterator(m_path);
|
||||
|
||||
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
||||
{
|
||||
callback(absolute(entry->path()).string());
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPathFilesystem::FindByExtension(const std::string& extension,
|
||||
const std::function<void(const std::string&)> callback)
|
||||
{
|
||||
std::filesystem::recursive_directory_iterator iterator(m_path);
|
||||
|
||||
else
|
||||
{
|
||||
std::filesystem::directory_iterator iterator(m_path);
|
||||
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
||||
{
|
||||
auto entryPath = entry->path();
|
||||
|
||||
if (entryPath.extension().string() == extension)
|
||||
{
|
||||
callback(entryPath.string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPathFilesystem::FindOnDiskByExtension(const std::string& extension,
|
||||
const std::function<void(const std::string&)> callback)
|
||||
{
|
||||
std::filesystem::recursive_directory_iterator iterator(m_path);
|
||||
|
||||
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
||||
{
|
||||
auto entryPath = entry->path();
|
||||
|
||||
if (entryPath.extension().string() == extension)
|
||||
{
|
||||
callback(absolute(entryPath).string());
|
||||
auto path = entry->path();
|
||||
if (options.m_filter_extensions && path.extension().string() != options.m_extension)
|
||||
continue;
|
||||
callback(options.m_absolute_paths ? absolute(path).string() : path.string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,8 @@ class SearchPathFilesystem final : public ISearchPath
|
||||
|
||||
public:
|
||||
explicit SearchPathFilesystem(std::string path);
|
||||
const std::string& GetPath() const;
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override;
|
||||
void FindAll(std::function<void(const std::string&)> callback) override;
|
||||
void FindAllOnDisk(std::function<void(const std::string&)> callback) override;
|
||||
void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
|
||||
void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
|
||||
std::string GetPath() override;
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||
};
|
41
src/ObjLoading/SearchPath/SearchPathSearchOptions.cpp
Normal file
41
src/ObjLoading/SearchPath/SearchPathSearchOptions.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "SearchPathSearchOptions.h"
|
||||
|
||||
SearchPathSearchOptions::SearchPathSearchOptions()
|
||||
{
|
||||
m_should_include_subdirectories = true;
|
||||
m_disk_files_only = false;
|
||||
m_absolute_paths = false;
|
||||
m_filter_extensions = false;
|
||||
}
|
||||
|
||||
SearchPathSearchOptions& SearchPathSearchOptions::IncludeSubdirectories(const bool value)
|
||||
{
|
||||
m_should_include_subdirectories = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SearchPathSearchOptions& SearchPathSearchOptions::OnlyDiskFiles(const bool value)
|
||||
{
|
||||
m_disk_files_only = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SearchPathSearchOptions& SearchPathSearchOptions::AbsolutePaths(const bool value)
|
||||
{
|
||||
m_absolute_paths = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SearchPathSearchOptions& SearchPathSearchOptions::FilterExtensions(std::string extension)
|
||||
{
|
||||
m_extension = std::move(extension);
|
||||
m_filter_extensions = true;
|
||||
|
||||
if(m_extension[0] != '.')
|
||||
m_extension = "." + m_extension;
|
||||
|
||||
return *this;
|
||||
}
|
21
src/ObjLoading/SearchPath/SearchPathSearchOptions.h
Normal file
21
src/ObjLoading/SearchPath/SearchPathSearchOptions.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class SearchPathSearchOptions
|
||||
{
|
||||
public:
|
||||
bool m_should_include_subdirectories;
|
||||
bool m_disk_files_only;
|
||||
bool m_absolute_paths;
|
||||
|
||||
bool m_filter_extensions;
|
||||
std::string m_extension;
|
||||
|
||||
SearchPathSearchOptions();
|
||||
|
||||
SearchPathSearchOptions& IncludeSubdirectories(bool value);
|
||||
SearchPathSearchOptions& OnlyDiskFiles(bool value);
|
||||
SearchPathSearchOptions& AbsolutePaths(bool value);
|
||||
SearchPathSearchOptions& FilterExtensions(std::string extension);
|
||||
};
|
@ -56,36 +56,16 @@ FileAPI::IFile* SearchPaths::Open(const std::string& fileName)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SearchPaths::FindAll(const std::function<void(const std::string&)> callback)
|
||||
std::string SearchPaths::GetPath()
|
||||
{
|
||||
for (auto searchPathEntry : m_search_paths)
|
||||
{
|
||||
searchPathEntry->FindAll(callback);
|
||||
}
|
||||
return "SearchPaths: " + std::to_string(m_search_paths.size()) + " entries";
|
||||
}
|
||||
|
||||
void SearchPaths::FindAllOnDisk(const std::function<void(const std::string&)> callback)
|
||||
void SearchPaths::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
||||
{
|
||||
for (auto searchPathEntry : m_search_paths)
|
||||
{
|
||||
searchPathEntry->FindAllOnDisk(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPaths::FindByExtension(const std::string& extension, const std::function<void(const std::string&)> callback)
|
||||
{
|
||||
for (auto searchPathEntry : m_search_paths)
|
||||
{
|
||||
searchPathEntry->FindByExtension(extension, callback);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPaths::FindOnDiskByExtension(const std::string& extension, const std::function<void(const std::string&)> callback)
|
||||
{
|
||||
for (auto searchPathEntry : m_search_paths)
|
||||
{
|
||||
searchPathEntry->FindOnDiskByExtension(extension, callback);
|
||||
searchPathEntry->Find(options, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,10 +15,8 @@ public:
|
||||
~SearchPaths() override;
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override;
|
||||
void FindAll(std::function<void(const std::string&)> callback) override;
|
||||
void FindAllOnDisk(std::function<void(const std::string&)> callback) override;
|
||||
void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
|
||||
void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
|
||||
std::string GetPath() override;
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||
|
||||
SearchPaths(const SearchPaths& other);
|
||||
SearchPaths(SearchPaths&& other) noexcept;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <set>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
#include "ObjContainer/IWD/IWD.h"
|
||||
|
||||
const CommandLineOption* optionHelp = CommandLineOption::Builder::Create()
|
||||
.WithShortName("?")
|
||||
@ -80,14 +81,16 @@ class Unlinker::Impl
|
||||
* \brief Loads a search path.
|
||||
* \param searchPath The search path to load.
|
||||
*/
|
||||
void LoadSearchPath(SearchPathFilesystem* searchPath)
|
||||
void LoadSearchPath(ISearchPath* searchPath) const
|
||||
{
|
||||
if(m_should_load_obj)
|
||||
if (m_should_load_obj)
|
||||
{
|
||||
if(m_verbose)
|
||||
if (m_verbose)
|
||||
{
|
||||
printf("Loading search path: \"%s\"\n", searchPath->GetPath().c_str());
|
||||
}
|
||||
|
||||
ObjLoading::LoadIWDsInSearchPath(searchPath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,14 +98,16 @@ class Unlinker::Impl
|
||||
* \brief Unloads a search path.
|
||||
* \param searchPath The search path to unload.
|
||||
*/
|
||||
void UnloadSearchPath(SearchPathFilesystem* searchPath)
|
||||
void UnloadSearchPath(ISearchPath* searchPath) const
|
||||
{
|
||||
if(m_should_load_obj)
|
||||
if (m_should_load_obj)
|
||||
{
|
||||
if(m_verbose)
|
||||
if (m_verbose)
|
||||
{
|
||||
printf("Unloading search path: \"%s\"\n", searchPath->GetPath().c_str());
|
||||
}
|
||||
|
||||
ObjLoading::UnloadIWDsInSearchPath(searchPath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,6 +225,12 @@ class Unlinker::Impl
|
||||
{
|
||||
std::string absolutePath = std::filesystem::absolute(path).string();
|
||||
|
||||
if (!FileAPI::DirectoryExists(absolutePath))
|
||||
{
|
||||
printf("Could not find directory of search path: \"%s\"\n", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SearchPathFilesystem* searchPath = new SearchPathFilesystem(absolutePath);
|
||||
LoadSearchPath(searchPath);
|
||||
m_search_paths.CommitSearchPath(searchPath);
|
||||
@ -327,6 +338,12 @@ class Unlinker::Impl
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetVerbose(const bool verbose)
|
||||
{
|
||||
m_verbose = verbose;
|
||||
ObjLoading::Configuration.Verbose = verbose;
|
||||
}
|
||||
|
||||
public:
|
||||
Impl()
|
||||
: m_argument_parser(commandLineOptions, _countof(commandLineOptions))
|
||||
@ -347,7 +364,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
m_verbose = m_argument_parser.IsOptionSpecified(optionVerbose);
|
||||
SetVerbose(m_argument_parser.IsOptionSpecified(optionVerbose));
|
||||
m_should_load_obj = !m_argument_parser.IsOptionSpecified(optionList);
|
||||
|
||||
// Check if the user requested help
|
||||
@ -385,7 +402,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_verbose)
|
||||
if (m_verbose)
|
||||
{
|
||||
printf("Loaded zone \"%s\"\n", zone->m_name.c_str());
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ bool FileAPI::DirectoryExists(const std::string& directoryName)
|
||||
FileAPI::File FileAPI::Open(const std::string& filename, const Mode mode)
|
||||
{
|
||||
const char* modeStr;
|
||||
switch(mode)
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
case Mode::MODE_READ:
|
||||
@ -98,12 +98,17 @@ size_t FileAPI::File::Write(const void* data, const size_t elementSize, const si
|
||||
return fwrite(data, elementSize, elementCount, static_cast<FILE*>(m_handle));
|
||||
}
|
||||
|
||||
void FileAPI::File::Skip(const size_t amount)
|
||||
void FileAPI::File::Skip(const int64_t amount)
|
||||
{
|
||||
if(!this->IsOpen())
|
||||
if (!this->IsOpen())
|
||||
return;
|
||||
|
||||
fseek(static_cast<FILE*>(m_handle), amount, SEEK_CUR);
|
||||
_fseeki64(static_cast<FILE*>(m_handle), amount, SEEK_CUR);
|
||||
}
|
||||
|
||||
void FileAPI::File::GotoEnd()
|
||||
{
|
||||
_fseeki64(static_cast<FILE*>(m_handle), 0, SEEK_END);
|
||||
}
|
||||
|
||||
size_t FileAPI::File::Printf(const char* fmt, ...)
|
||||
|
@ -20,10 +20,11 @@ public:
|
||||
virtual bool IsOpen() = 0;
|
||||
virtual size_t Read(void* buffer, size_t elementSize, size_t elementCount) = 0;
|
||||
virtual size_t Write(const void* data, size_t elementSize, size_t elementCount) = 0;
|
||||
virtual void Skip(size_t amount) = 0;
|
||||
virtual void Skip(int64_t amount) = 0;
|
||||
virtual size_t Printf(const char* fmt, ...) = 0;
|
||||
virtual int64_t Pos() = 0;
|
||||
virtual void Goto(int64_t pos) = 0;
|
||||
virtual void GotoEnd() = 0;
|
||||
virtual void Close() = 0;
|
||||
};
|
||||
|
||||
@ -44,10 +45,11 @@ public:
|
||||
bool IsOpen() override;
|
||||
size_t Read(void* buffer, size_t elementSize, size_t elementCount) override;
|
||||
size_t Write(const void* data, size_t elementSize, size_t elementCount) override;
|
||||
void Skip(size_t amount) override;
|
||||
void Skip(int64_t amount) override;
|
||||
size_t Printf(const char* fmt, ...) override;
|
||||
int64_t Pos() override;
|
||||
void Goto(int64_t pos) override;
|
||||
void GotoEnd() override;
|
||||
void Close() override;
|
||||
};
|
||||
|
||||
|
26
src/Utils/Utils/TransformIterator.h
Normal file
26
src/Utils/Utils/TransformIterator.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
template <typename BaseIteratorType, typename SourceType, typename TargetType>
|
||||
class TransformIterator
|
||||
{
|
||||
BaseIteratorType m_base;
|
||||
std::function<TargetType(SourceType)> m_transform;
|
||||
|
||||
public:
|
||||
TransformIterator(BaseIteratorType base, std::function<TargetType(SourceType)> transform)
|
||||
: m_base(base), m_transform(transform)
|
||||
{
|
||||
}
|
||||
|
||||
TransformIterator& operator++()
|
||||
{
|
||||
++m_base;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(TransformIterator other) const { return m_base == other.m_base; }
|
||||
bool operator!=(TransformIterator other) const { return !(m_base == other.m_base); }
|
||||
TargetType operator*() { return m_transform(*m_base); }
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user