OpenRCT2/src/openrct2/AssetPackManager.cpp

212 lines
5.7 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "AssetPackManager.h"
#include "AssetPack.h"
#include "Context.h"
#include "PlatformEnvironment.h"
#include "config/Config.h"
#include "core/Console.hpp"
#include "core/FileSystem.hpp"
#include "core/Path.hpp"
#include "core/String.hpp"
#include "object/AudioSampleTable.h"
#include <algorithm>
#include <cstdio>
using namespace OpenRCT2;
AssetPackManager::AssetPackManager()
{
}
AssetPackManager::~AssetPackManager()
{
}
size_t AssetPackManager::GetCount() const
{
return _assetPacks.size();
}
AssetPack* AssetPackManager::GetAssetPack(size_t index)
{
if (index >= _assetPacks.size())
return nullptr;
return _assetPacks[index].get();
}
AssetPack* AssetPackManager::GetAssetPack(std::string_view id)
{
auto index = GetAssetPackIndex(id);
if (index != std::numeric_limits<size_t>::max())
return _assetPacks[index].get();
return nullptr;
}
size_t AssetPackManager::GetAssetPackIndex(std::string_view id)
{
auto it = std::find_if(_assetPacks.begin(), _assetPacks.end(), [&](const std::unique_ptr<AssetPack>& assetPack) {
return assetPack != nullptr ? assetPack->Id == id : false;
});
if (it == _assetPacks.end())
return std::numeric_limits<size_t>::max();
return std::distance(_assetPacks.begin(), it);
}
void AssetPackManager::Scan()
{
ClearAssetPacks();
auto context = GetContext();
auto env = context->GetPlatformEnvironment();
auto openrct2Dir = fs::u8path(env->GetDirectoryPath(DIRBASE::OPENRCT2, DIRID::ASSET_PACK));
Scan(openrct2Dir);
auto userDirectory = fs::u8path(env->GetDirectoryPath(DIRBASE::USER, DIRID::ASSET_PACK));
Path::CreateDirectory(userDirectory.u8string());
Scan(userDirectory);
}
void AssetPackManager::Scan(const fs::path& directory)
{
// Recursively scan for .parkap files
std::error_code ec;
for (const fs::directory_entry& entry : fs::recursive_directory_iterator(directory, ec))
{
if (!entry.is_directory())
{
auto path = entry.path().u8string();
if (String::EndsWith(path, ".parkap", true))
{
AddAssetPack(path);
}
}
}
}
void AssetPackManager::Reload()
{
for (auto& assetPack : _assetPacks)
{
assetPack->Load();
}
}
void AssetPackManager::Swap(size_t index, size_t otherIndex)
{
if (index < _assetPacks.size() && otherIndex < _assetPacks.size() && index != otherIndex)
{
std::swap(_assetPacks[index], _assetPacks[otherIndex]);
}
}
void AssetPackManager::LoadSamplesForObject(std::string_view id, AudioSampleTable& objectTable)
{
std::for_each(_assetPacks.rbegin(), _assetPacks.rend(), [&](auto& assetPack) {
if (assetPack->IsEnabled() && assetPack->ContainsObject(id))
{
assetPack->LoadSamplesForObject(id, objectTable);
}
});
}
void AssetPackManager::ClearAssetPacks()
{
_assetPacks.clear();
}
void AssetPackManager::AddAssetPack(const fs::path& path)
{
auto szPath = path.u8string();
LOG_VERBOSE("Scanning asset pack: %s", szPath.c_str());
try
{
auto ap = std::make_unique<AssetPack>(path);
ap->Fetch();
_assetPacks.push_back(std::move(ap));
}
catch (const std::exception& e)
{
auto fileName = path.filename().u8string();
Console::Error::WriteFormat("Unable to load asset pack: %s (%s)", fileName.c_str(), e.what());
}
}
template<typename TFunc> static void EnumerateCommaSeparatedList(std::string_view csl, TFunc func)
{
size_t elStart = 0;
for (size_t i = 0; i <= csl.size(); i++)
{
if (i == csl.size() || csl[i] == ',')
{
auto el = csl.substr(elStart, i - elStart);
if (el.size() != 0)
func(el);
elStart = i + 1;
}
}
}
void AssetPackManager::LoadEnabledAssetPacks()
{
// Re-order asset packs
std::vector<std::unique_ptr<AssetPack>> newAssetPacks;
EnumerateCommaSeparatedList(Config::Get().general.AssetPackOrder, [&](std::string_view id) {
auto index = GetAssetPackIndex(id);
if (index != std::numeric_limits<size_t>::max())
{
newAssetPacks.push_back(std::move(_assetPacks[index]));
}
});
for (auto& assetPack : _assetPacks)
{
if (assetPack != nullptr)
{
newAssetPacks.push_back(std::move(assetPack));
}
}
_assetPacks = std::move(newAssetPacks);
// Set which asset packs are enabled
EnumerateCommaSeparatedList(Config::Get().general.EnabledAssetPacks, [&](std::string_view id) {
auto assetPack = GetAssetPack(id);
if (assetPack != nullptr)
{
assetPack->SetEnabled(true);
}
});
}
void AssetPackManager::SaveEnabledAssetPacks()
{
u8string orderList;
u8string enabledList;
for (const auto& assetPack : _assetPacks)
{
orderList.append(assetPack->Id);
orderList.push_back(',');
if (assetPack->IsEnabled())
{
enabledList.append(assetPack->Id);
enabledList.push_back(',');
}
}
if (orderList.size() > 0)
orderList.pop_back();
if (enabledList.size() > 0)
enabledList.pop_back();
Config::Get().general.AssetPackOrder = orderList;
Config::Get().general.EnabledAssetPacks = enabledList;
Config::Save();
}