162 lines
5.7 KiB
C++
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
|