MetaCore/Source/MetaCoreScene/Private/MetaCoreScenePackage.cpp

162 lines
5.7 KiB
C++

#include "MetaCoreScene/MetaCoreScenePackage.h"
#include "MetaCoreFoundation/MetaCoreGeneratedReflection.h"
#include "MetaCoreFoundation/MetaCoreHash.h"
#include "MetaCoreFoundation/MetaCorePackage.h"
#include "MetaCoreFoundation/MetaCoreProject.h"
#include <fstream>
#include <sstream>
namespace MetaCore {
namespace {
[[nodiscard]] MetaCorePackageDocument MetaCoreBuildTypedScenePackage(
const MetaCoreAssetGuid& assetGuid,
const std::string& objectName,
std::vector<std::byte> payload
) {
MetaCorePackageDocument document;
document.Header.PackageType = MetaCorePackageType::Scene;
document.Header.PackageGuid = assetGuid;
document.Header.SourceHash = MetaCoreHashBytes(std::span<const std::byte>(payload.data(), payload.size()));
document.NameTable = {objectName, "MetaCoreSceneDocument"};
document.Exports.push_back(MetaCoreExportEntry{
assetGuid,
objectName,
MetaCoreMakeTypeId("MetaCoreSceneDocument"),
0,
static_cast<std::uint64_t>(payload.size())
});
document.PayloadSections.push_back(std::move(payload));
return document;
}
template <typename T>
[[nodiscard]] std::optional<T> MetaCoreReadTypedPayload(
const MetaCorePackageDocument& document,
const MetaCoreTypeRegistry& registry,
std::string_view expectedTypeName
) {
if (document.Exports.empty() || document.PayloadSections.empty()) {
return std::nullopt;
}
const MetaCoreExportEntry& exportEntry = document.Exports.front();
if (exportEntry.TypeId != MetaCoreMakeTypeId(expectedTypeName) ||
exportEntry.PayloadIndex >= document.PayloadSections.size()) {
return std::nullopt;
}
T payload{};
if (!MetaCoreDeserializeFromBytes(document.PayloadSections[exportEntry.PayloadIndex], payload, registry)) {
return std::nullopt;
}
return payload;
}
[[nodiscard]] std::optional<std::string> MetaCoreFindJsonStringValue(std::string_view json, std::string_view key) {
const std::string needle = "\"" + std::string(key) + "\"";
std::size_t keyPosition = json.find(needle);
if (keyPosition == std::string_view::npos) {
return std::nullopt;
}
std::size_t colonPosition = json.find(':', keyPosition + needle.size());
if (colonPosition == std::string_view::npos) {
return std::nullopt;
}
std::size_t firstQuote = json.find('"', colonPosition + 1);
if (firstQuote == std::string_view::npos) {
return std::nullopt;
}
std::size_t secondQuote = firstQuote + 1;
while (secondQuote < json.size()) {
secondQuote = json.find('"', secondQuote);
if (secondQuote == std::string_view::npos) {
return std::nullopt;
}
if (secondQuote == firstQuote + 1 || json[secondQuote - 1] != '\\') {
break;
}
++secondQuote;
}
return std::string(json.substr(firstQuote + 1, secondQuote - firstQuote - 1));
}
} // namespace
MetaCoreTypeRegistry MetaCoreBuildScenePackageTypeRegistry() {
MetaCoreTypeRegistry registry;
MetaCoreRegisterFoundationGeneratedTypes(registry);
MetaCoreRegisterSceneGeneratedTypes(registry);
return registry;
}
bool MetaCoreWriteScenePackage(
const std::filesystem::path& path,
const MetaCoreSceneDocument& document
) {
const MetaCoreTypeRegistry registry = MetaCoreBuildScenePackageTypeRegistry();
const auto payload = MetaCoreSerializeToBytes(document, registry);
if (!payload.has_value()) {
return false;
}
const std::string objectName = path.stem().string().empty() ? "Scene" : path.stem().string();
MetaCorePackageDocument package = MetaCoreBuildTypedScenePackage(
MetaCoreAssetGuid::Generate(),
objectName,
*payload
);
return MetaCoreWritePackageFile(path, std::move(package), registry);
}
std::optional<MetaCoreSceneDocument> MetaCoreReadScenePackage(const std::filesystem::path& path) {
const MetaCoreTypeRegistry registry = MetaCoreBuildScenePackageTypeRegistry();
const auto package = MetaCoreReadPackageFile(path, registry);
if (!package.has_value() || package->Header.PackageType != MetaCorePackageType::Scene) {
return std::nullopt;
}
return MetaCoreReadTypedPayload<MetaCoreSceneDocument>(*package, registry, "MetaCoreSceneDocument");
}
std::optional<std::filesystem::path> MetaCoreResolveStartupScenePackagePath(const std::filesystem::path& projectFilePath) {
const auto projectDocument = MetaCoreReadProjectFile(projectFilePath);
if (!projectDocument.has_value() || projectDocument->StartupScenePath.empty()) {
return std::nullopt;
}
const std::filesystem::path relativeStartupScenePath = projectDocument->StartupScenePath.lexically_normal();
const std::filesystem::path projectRoot = projectFilePath.parent_path();
std::vector<std::filesystem::path> candidates;
if (relativeStartupScenePath.extension() == ".json") {
candidates.push_back((projectRoot / relativeStartupScenePath).replace_extension(""));
}
candidates.push_back(projectRoot / relativeStartupScenePath);
for (const std::filesystem::path& candidate : candidates) {
std::error_code errorCode;
if (std::filesystem::exists(candidate, errorCode)) {
return std::filesystem::weakly_canonical(candidate, errorCode);
}
}
return (projectRoot / relativeStartupScenePath).lexically_normal();
}
std::optional<MetaCoreSceneDocument> MetaCoreLoadStartupSceneDocument(const std::filesystem::path& projectFilePath) {
const auto startupScenePath = MetaCoreResolveStartupScenePackagePath(projectFilePath);
if (!startupScenePath.has_value()) {
return std::nullopt;
}
return MetaCoreReadScenePackage(*startupScenePath);
}
} // namespace MetaCore