Skip to content

Commit

Permalink
Uses a struct in in mResourceCache in the ResourceManager. (#740)
Browse files Browse the repository at this point in the history
* Now uses a struct in ResourceManager cache map key.

* Adds logic to be able to load a raw File from specific Archive via ResourceManager

* Fixes issue of setting the hash function for ResourceCacheData in the incorrect place.

* Remove whitespace in ResourceManager.h

* Changes bind to lambda in LoadResourceAsync.

* clang-format

* Rename ResourceCachdData -> ResourceIdentifier

* Moves Archive to ResourceInitData and renames ResourceIdentifier.LoadArchvie -> Parent

* Removing more whitespace.

* clang-format

* CacheData -> Identifier

* Simplify ArchiveManager.LoadFile

* Caching the hash on construction of ResourceIdentifier.

* clang-format

* ResourceCacheDataHash -> ResourceIdentifierHash

* Uses a better function for combining multiple hashes.

* ResourceIdentifier.GetHash to private.
  • Loading branch information
Kenix3 authored Dec 12, 2024
1 parent 27cd261 commit 275b0d3
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 103 deletions.
2 changes: 1 addition & 1 deletion src/resource/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Archive;
#define RESOURCE_FORMAT_XML 1

struct ResourceInitData {
std::shared_ptr<Archive> Parent;
std::string Path;
Endianness ByteOrder;
uint32_t Type;
Expand All @@ -26,7 +27,6 @@ struct ResourceInitData {
};

struct File {
std::shared_ptr<Archive> Parent;
std::shared_ptr<ResourceInitData> InitData;
std::shared_ptr<std::vector<char>> Buffer;
std::variant<std::shared_ptr<tinyxml2::XMLDocument>, std::shared_ptr<BinaryReader>> Reader;
Expand Down
216 changes: 143 additions & 73 deletions src/resource/ResourceManager.cpp

Large diffs are not rendered by default.

78 changes: 58 additions & 20 deletions src/resource/ResourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,37 @@
#include <variant>
#include "resource/Resource.h"
#include "resource/ResourceLoader.h"
#include "resource/archive/Archive.h"
#include "resource/archive/ArchiveManager.h"

#define BS_THREAD_POOL_ENABLE_PRIORITY
#define BS_THREAD_POOL_ENABLE_PAUSE

#include <BS_thread_pool.hpp>

namespace Ship {
struct File;

// Resource manager caches any and all files it comes across into memory. This will be unoptimal in the future when
// modifications have gigabytes of assets. It works with the original game's assets because the entire ROM is 64MB and
// fits into RAM of any semi-modern PC.
struct ResourceIdentifier {
friend class ResourceIdentifierHash;

ResourceIdentifier(const std::string& path, const uintptr_t owner, const std::shared_ptr<Archive> parent);
bool operator==(const ResourceIdentifier& rhs) const;

// Path can either be a Path or a Search Mask including globs depending on usage.
const std::string Path = "";
const uintptr_t Owner = 0;
const std::shared_ptr<Archive> Parent = nullptr;

private:
size_t GetHash() const;
size_t CalculateHash();
size_t mHash;
};

struct ResourceIdentifierHash {
size_t operator()(const ResourceIdentifier& rcd) const;
};

class ResourceManager {
typedef enum class ResourceLoadError { None, NotCached, NotFound } ResourceLoadError;

Expand All @@ -33,44 +51,64 @@ class ResourceManager {
std::shared_ptr<ArchiveManager> GetArchiveManager();
std::shared_ptr<ResourceLoader> GetResourceLoader();

std::shared_ptr<IResource> GetCachedResource(const std::string& filePath, uintptr_t owner = 0,
bool loadExact = false);
std::shared_ptr<IResource> LoadResource(const std::string& filePath, uintptr_t owner = 0, bool loadExact = false,
std::shared_ptr<IResource> GetCachedResource(const ResourceIdentifier& identifier, bool loadExact = false);
std::shared_ptr<IResource> LoadResource(const ResourceIdentifier& identifier, bool loadExact = false,
std::shared_ptr<ResourceInitData> initData = nullptr);
std::shared_ptr<IResource> LoadResourceProcess(const std::string& filePath, uintptr_t owner = 0,
bool loadExact = false,
std::shared_ptr<IResource> LoadResourceProcess(const ResourceIdentifier& identifier, bool loadExact = false,
std::shared_ptr<ResourceInitData> initData = nullptr);
size_t UnloadResource(const std::string& filePath, uintptr_t owner = 0);
size_t UnloadResource(const ResourceIdentifier& identifier);
std::shared_future<std::shared_ptr<IResource>>
LoadResourceAsync(const std::string& filePath, uintptr_t owner = 0, bool loadExact = false,
LoadResourceAsync(const ResourceIdentifier& identifier, bool loadExact = false,
BS::priority_t priority = BS::pr::normal, std::shared_ptr<ResourceInitData> initData = nullptr);
std::shared_ptr<std::vector<std::shared_ptr<IResource>>> LoadDirectory(const std::string& searchMask,
uintptr_t owner = 0);
std::shared_ptr<std::vector<std::shared_ptr<IResource>>> LoadDirectory(const ResourceIdentifier& identifier);
std::shared_ptr<std::vector<std::shared_future<std::shared_ptr<IResource>>>>
LoadDirectoryAsync(const std::string& searchMask, uintptr_t owner = 0, BS::priority_t priority = BS::pr::normal);
void DirtyDirectory(const std::string& searchMask, uintptr_t owner = 0);
void UnloadDirectory(const std::string& searchMask, uintptr_t owner = 0);
LoadDirectoryAsync(const ResourceIdentifier& identifier, BS::priority_t priority = BS::pr::normal);
void DirtyDirectory(const ResourceIdentifier& identifier);
void UnloadDirectory(const ResourceIdentifier& identifier);

std::shared_ptr<IResource> GetCachedResource(const std::string& filePath, bool loadExact = false);
std::shared_ptr<IResource> LoadResource(const std::string& filePath, bool loadExact = false,
std::shared_ptr<ResourceInitData> initData = nullptr);
std::shared_ptr<IResource> LoadResourceProcess(const std::string& filePath, bool loadExact = false,
std::shared_ptr<ResourceInitData> initData = nullptr);
size_t UnloadResource(const std::string& filePath);
std::shared_future<std::shared_ptr<IResource>>
LoadResourceAsync(const std::string& filePath, bool loadExact = false, BS::priority_t priority = BS::pr::normal,
std::shared_ptr<ResourceInitData> initData = nullptr);
std::shared_ptr<std::vector<std::shared_ptr<IResource>>> LoadDirectory(const std::string& searchMask);
std::shared_ptr<std::vector<std::shared_future<std::shared_ptr<IResource>>>>
LoadDirectoryAsync(const std::string& searchMask, BS::priority_t priority = BS::pr::normal);
void DirtyDirectory(const std::string& searchMask);
void UnloadDirectory(const std::string& searchMask);

bool DidLoadSuccessfully();
bool OtrSignatureCheck(const char* fileName);
bool IsAltAssetsEnabled();
void SetAltAssetsEnabled(bool isEnabled);

protected:
std::variant<ResourceLoadError, std::shared_ptr<IResource>> CheckCache(const ResourceIdentifier& cacheData,
bool loadExact = false);
std::shared_ptr<File> LoadFileProcess(const ResourceIdentifier& cacheData,
std::shared_ptr<ResourceInitData> initData = nullptr);
std::variant<ResourceLoadError, std::shared_ptr<IResource>> CheckCache(const std::string& filePath,
bool loadExact = false);

std::shared_ptr<File> LoadFileProcess(const std::string& filePath,
std::shared_ptr<ResourceInitData> initData = nullptr);
std::shared_ptr<IResource> GetCachedResource(std::variant<ResourceLoadError, std::shared_ptr<IResource>> cacheLine);
std::variant<ResourceLoadError, std::shared_ptr<IResource>> CheckCache(const std::string& filePath,
uintptr_t owner = 0, bool loadExact = false);

private:
std::unordered_map<uintptr_t,
std::unordered_map<std::string, std::variant<ResourceLoadError, std::shared_ptr<IResource>>>>
std::unordered_map<ResourceIdentifier, std::variant<ResourceLoadError, std::shared_ptr<IResource>>,
ResourceIdentifierHash>
mResourceCache;
std::shared_ptr<ResourceLoader> mResourceLoader;
std::shared_ptr<ArchiveManager> mArchiveManager;
std::shared_ptr<BS::thread_pool> mThreadPool;
std::mutex mMutex;
bool mAltAssetsEnabled = false;
// Private information for which owner and archive are default.
uintptr_t mDefaultCacheOwner = 0;
std::shared_ptr<Archive> mDefaultCacheArchive = nullptr;
};
} // namespace Ship
6 changes: 6 additions & 0 deletions src/resource/archive/Archive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Archive::~Archive() {
SPDLOG_TRACE("destruct archive: {}", GetPath());
}

bool Archive::operator==(const Archive& rhs) const {
return mPath == rhs.mPath;
}

void Archive::Load() {
bool opened = Open();

Expand Down Expand Up @@ -233,6 +237,8 @@ std::shared_ptr<File> Archive::LoadFile(const std::string& filePath, std::shared
break;
}

fileToLoad->InitData->Parent = shared_from_this();

return fileToLoad;
}

Expand Down
4 changes: 3 additions & 1 deletion src/resource/archive/Archive.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ namespace Ship {
struct File;
struct ResourceInitData;

class Archive {
class Archive : public std::enable_shared_from_this<Archive> {
friend class ArchiveManager;

public:
Archive(const std::string& path);
~Archive();

bool operator==(const Archive& rhs) const;

void Load();
void Unload();

Expand Down
6 changes: 2 additions & 4 deletions src/resource/archive/ArchiveManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,12 @@ std::shared_ptr<File> ArchiveManager::LoadFile(const std::string& filePath,
}

std::shared_ptr<File> ArchiveManager::LoadFile(uint64_t hash, std::shared_ptr<ResourceInitData> initData) {
const auto archive = mFileToArchive[hash];
auto archive = mFileToArchive[hash];
if (archive == nullptr) {
return nullptr;
}

auto file = archive->LoadFile(hash, initData);
file->Parent = archive;
return file;
return archive->LoadFile(hash, initData);
}

bool ArchiveManager::HasFile(const std::string& filePath) {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ float clamp(float d, float min, float max) {
return t > max ? max : t;
}

size_t HashCombine(size_t lhs, size_t rhs) {
if constexpr (sizeof(size_t) >= 8) {
lhs ^= rhs + 0x517cc1b727220a95 + (lhs << 6) + (lhs >> 2);
} else {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
}
return lhs;
}
} // namespace Math

std::vector<std::string> splitText(const std::string text, char separator = ' ', bool keepQuotes = false) {
Expand Down
1 change: 1 addition & 0 deletions src/utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Ship {

namespace Math {
float clamp(float d, float min, float max);
size_t HashCombine(size_t lhs, size_t rhs);
template <typename Numeric> bool IsNumber(const std::string& s) {
Numeric n;
return ((std::istringstream(s) >> n >> std::ws).eof());
Expand Down
22 changes: 20 additions & 2 deletions src/window/gui/GameOverlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,33 @@ GameOverlay::~GameOverlay() {
SPDLOG_TRACE("destruct game overlay");
}

void GameOverlay::LoadFont(const std::string& name, float fontSize, const std::string& path, uintptr_t owner) {
void GameOverlay::LoadFont(const std::string& name, float fontSize, const ResourceIdentifier& identifier) {
ImGuiIO& io = ImGui::GetIO();
auto initData = std::make_shared<ResourceInitData>();
initData->Format = RESOURCE_FORMAT_BINARY;
initData->Type = static_cast<uint32_t>(RESOURCE_TYPE_FONT);
initData->ResourceVersion = 0;
initData->Path = identifier.Path;
std::shared_ptr<Font> font = std::static_pointer_cast<Font>(
Context::GetInstance()->GetResourceManager()->LoadResource(identifier, false, initData));

if (font == nullptr) {
SPDLOG_ERROR("Failed to load font: {}", name);
return;
}

mFonts[name] = io.Fonts->AddFontFromMemoryTTF(font->Data, font->DataSize, fontSize);
}

void GameOverlay::LoadFont(const std::string& name, float fontSize, const std::string& path) {
ImGuiIO& io = ImGui::GetIO();
auto initData = std::make_shared<ResourceInitData>();
initData->Format = RESOURCE_FORMAT_BINARY;
initData->Type = static_cast<uint32_t>(RESOURCE_TYPE_FONT);
initData->ResourceVersion = 0;
initData->Path = path;
std::shared_ptr<Font> font = std::static_pointer_cast<Font>(
Context::GetInstance()->GetResourceManager()->LoadResource(path, owner, false, initData));
Context::GetInstance()->GetResourceManager()->LoadResource(path, false, initData));

if (font == nullptr) {
SPDLOG_ERROR("Failed to load font: {}", name);
Expand Down
4 changes: 3 additions & 1 deletion src/window/gui/GameOverlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#endif
#include <imgui.h>
#include <unordered_map>
#include "resource/ResourceManager.h"

namespace Ship {

Expand All @@ -27,7 +28,8 @@ class GameOverlay {
~GameOverlay();

void Init();
void LoadFont(const std::string& name, float fontSize, const std::string& path, uintptr_t owner = 0);
void LoadFont(const std::string& name, float fontSize, const ResourceIdentifier& identifier);
void LoadFont(const std::string& name, float fontSize, const std::string& path);
void SetCurrentFont(const std::string& name);
void Draw();
void DrawSettings();
Expand Down
2 changes: 1 addition & 1 deletion src/window/gui/Gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ void Gui::LoadTextureFromRawImage(const std::string& name, const std::string& pa
initData->ResourceVersion = 0;
initData->Path = path;
auto guiTexture = std::static_pointer_cast<GuiTexture>(
Context::GetInstance()->GetResourceManager()->LoadResource(path, 0, false, initData));
Context::GetInstance()->GetResourceManager()->LoadResource(path, false, initData));

GfxRenderingAPI* api = gfx_get_current_rendering_api();

Expand Down

0 comments on commit 275b0d3

Please sign in to comment.