OpenRCT2/src/openrct2/AssetPack.cpp

190 lines
5.0 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 "AssetPack.h"
#include "Context.h"
#include "core/Json.hpp"
#include "core/Path.hpp"
#include "core/Zip.h"
#include "drawing/Image.h"
#include "localisation/LocalisationService.h"
#include "object/Object.h"
using namespace OpenRCT2;
constexpr std::string_view ManifestFileName = "manifest.json";
AssetPack::AssetPack(const fs::path& path)
: Path(path)
{
}
AssetPack::~AssetPack()
{
}
bool AssetPack::IsEnabled() const
{
return _enabled;
}
void AssetPack::SetEnabled(bool value)
{
_enabled = value;
}
void AssetPack::Fetch()
{
auto archive = Zip::Open(Path.u8string(), ZIP_ACCESS::READ);
if (!archive->Exists(ManifestFileName))
{
throw std::runtime_error("Manifest does not exist.");
}
auto manifestJson = archive->GetFileData(ManifestFileName);
auto jManifest = Json::FromVector(manifestJson);
Id = jManifest["id"].get<std::string>();
Version = jManifest["version"].get<std::string>();
// TODO use a better string table class that can be used for objects, park files and asset packs
auto& localisationService = GetContext()->GetLocalisationService();
auto locale = std::string(localisationService.GetCurrentLanguageLocale());
Name = GetString(jManifest, "name", locale);
Description = GetString(jManifest, "description", locale);
}
std::string AssetPack::GetString(json_t& jManifest, const std::string& key, const std::string& locale)
{
if (jManifest.contains("strings"))
{
auto& jStrings = jManifest["strings"];
if (jStrings.contains(key))
{
auto& jKey = jStrings[key];
if (jKey.contains(locale))
{
return jKey[locale].get<std::string>();
}
if (jKey.contains("en-GB"))
{
return jKey["en-GB"].get<std::string>();
}
if (jKey.contains("en-US"))
{
return jKey["en-US"].get<std::string>();
}
}
}
return {};
}
bool AssetPack::ContainsObject(std::string_view id) const
{
auto it = std::find_if(_entries.begin(), _entries.end(), [id](const Entry& entry) { return entry.ObjectId == id; });
return it != _entries.end();
}
void AssetPack::LoadSamplesForObject(std::string_view id, AudioSampleTable& objectTable)
{
auto it = std::find_if(_entries.begin(), _entries.end(), [id](const Entry& entry) { return entry.ObjectId == id; });
if (it != _entries.end())
{
objectTable.LoadFrom(_sampleTable, it->TableIndex, it->TableLength);
}
}
class AssetPackLoadContext : public IReadObjectContext
{
private:
std::string _zipPath;
IZipArchive* _zipArchive;
public:
AssetPackLoadContext(std::string_view zipPath, IZipArchive* zipArchive)
: _zipPath(zipPath)
, _zipArchive(zipArchive)
{
}
virtual ~AssetPackLoadContext() override
{
}
std::string_view GetObjectIdentifier() override
{
throw std::runtime_error("Not implemented");
}
IObjectRepository& GetObjectRepository() override
{
throw std::runtime_error("Not implemented");
}
bool ShouldLoadImages() override
{
return true;
}
std::vector<uint8_t> GetData(std::string_view path) override
{
return _zipArchive->GetFileData(path);
}
ObjectAsset GetAsset(std::string_view path) override
{
if (Path::IsAbsolute(path))
return ObjectAsset(path);
return ObjectAsset(_zipPath, path);
}
void LogVerbose(ObjectError code, const utf8* text) override
{
}
void LogWarning(ObjectError code, const utf8* text) override
{
}
void LogError(ObjectError code, const utf8* text) override
{
}
};
void AssetPack::Load()
{
auto path = Path.u8string();
auto archive = Zip::Open(path, ZIP_ACCESS::READ);
if (!archive->Exists(ManifestFileName))
{
throw std::runtime_error("Manifest does not exist.");
}
AssetPackLoadContext loadContext(path, archive.get());
auto manifestJson = archive->GetFileData(ManifestFileName);
auto jManifest = Json::FromVector(manifestJson);
auto& jObjects = jManifest["objects"];
_entries.clear();
for (auto& jObject : jObjects)
{
Entry entry;
entry.ObjectId = jObject["id"].get<std::string>();
if (jObject.contains("samples"))
{
entry.TableIndex = _sampleTable.GetCount();
_sampleTable.ReadFromJson(&loadContext, jObject);
entry.TableLength = _sampleTable.GetCount() - entry.TableIndex;
}
_entries.push_back(entry);
}
}