174 lines
6.5 KiB
C++
174 lines
6.5 KiB
C++
#include "MetaCoreFoundation/MetaCoreAssetRegistry.h"
|
|
|
|
#include <nlohmann/json.hpp>
|
|
#include <fstream>
|
|
#include <algorithm>
|
|
|
|
namespace MetaCore {
|
|
|
|
MetaCoreAssetRegistry& MetaCoreAssetRegistry::Get() {
|
|
static MetaCoreAssetRegistry instance;
|
|
return instance;
|
|
}
|
|
|
|
void MetaCoreAssetRegistry::ScanDirectory(const std::filesystem::path& rootPath) {
|
|
if (!std::filesystem::exists(rootPath) || !std::filesystem::is_directory(rootPath)) {
|
|
return;
|
|
}
|
|
|
|
// 遍历指定目录下的所有文件,寻找 .mcmeta 文件
|
|
for (const auto& entry : std::filesystem::recursive_directory_iterator(rootPath)) {
|
|
if (!entry.is_regular_file() || entry.path().extension() != ".mcmeta") {
|
|
continue;
|
|
}
|
|
|
|
std::ifstream file(entry.path());
|
|
if (!file.is_open()) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
nlohmann::json json;
|
|
file >> json;
|
|
|
|
if (json.contains("guid") && json["guid"].is_string() &&
|
|
json.contains("source_path") && json["source_path"].is_string()) {
|
|
|
|
const std::string guidStr = json["guid"].get<std::string>();
|
|
const std::string sourcePathStr = json["source_path"].get<std::string>();
|
|
|
|
auto parsedGuid = MetaCoreAssetGuid::Parse(guidStr);
|
|
if (parsedGuid.has_value()) {
|
|
// 规格化路径,确保斜杠在跨平台的一致性
|
|
std::filesystem::path portablePath(sourcePathStr);
|
|
RegisterAsset(*parsedGuid, portablePath);
|
|
|
|
// 顺便注册该主模型派生的所有子资产(如 mesh, material 等)
|
|
if (json.contains("sub_assets") && json["sub_assets"].is_array()) {
|
|
for (const auto& subAssetJson : json["sub_assets"]) {
|
|
if (subAssetJson.contains("guid") && subAssetJson["guid"].is_string()) {
|
|
const std::string subGuidStr = subAssetJson["guid"].get<std::string>();
|
|
auto parsedSubGuid = MetaCoreAssetGuid::Parse(subGuidStr);
|
|
if (parsedSubGuid.has_value()) {
|
|
RegisterSubAsset(*parsedSubGuid, portablePath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (...) {
|
|
// 尝试作为二进制 mcmeta 包后备解析 (对标旧资源兼容)
|
|
try {
|
|
std::ifstream binFile(entry.path(), std::ios::binary);
|
|
if (binFile.is_open()) {
|
|
char headerBytes[32];
|
|
if (binFile.read(headerBytes, 32)) {
|
|
std::uint32_t magic = 0;
|
|
std::uint32_t formatVersion = 0;
|
|
std::memcpy(&magic, headerBytes, 4);
|
|
std::memcpy(&formatVersion, headerBytes + 4, 4);
|
|
|
|
if (magic == 0x4D434F52U && formatVersion == 1U) {
|
|
MetaCoreAssetGuid packageGuid{};
|
|
std::memcpy(packageGuid.Bytes.data(), headerBytes + 16, 16);
|
|
if (packageGuid.IsValid()) {
|
|
std::filesystem::path mcmetaPath = entry.path();
|
|
std::filesystem::path sourceRelativePath = mcmetaPath.parent_path() / mcmetaPath.stem();
|
|
std::filesystem::path relativeToProject = sourceRelativePath.lexically_relative(rootPath.parent_path());
|
|
RegisterAsset(packageGuid, relativeToProject);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (...) {
|
|
// 彻底忽略损坏的文件
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MetaCoreAssetRegistry::RegisterAsset(const MetaCoreAssetGuid& guid, const std::filesystem::path& relativePath) {
|
|
if (!guid.IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
UnregisterAsset(guid);
|
|
const std::string keyPath = NormalizePathKey(relativePath);
|
|
GuidToPath_[guid] = relativePath;
|
|
PathToGuid_[keyPath] = guid;
|
|
PrimaryAssetGuids_.insert(guid);
|
|
return true;
|
|
}
|
|
|
|
bool MetaCoreAssetRegistry::RegisterSubAsset(const MetaCoreAssetGuid& guid, const std::filesystem::path& relativePath) {
|
|
if (!guid.IsValid()) {
|
|
return false;
|
|
}
|
|
UnregisterAsset(guid);
|
|
GuidToPath_[guid] = relativePath;
|
|
return true;
|
|
}
|
|
|
|
void MetaCoreAssetRegistry::UnregisterAsset(const MetaCoreAssetGuid& guid) {
|
|
const auto iterator = GuidToPath_.find(guid);
|
|
if (iterator == GuidToPath_.end()) {
|
|
return;
|
|
}
|
|
|
|
const std::string keyPath = NormalizePathKey(iterator->second);
|
|
if (const auto pathIterator = PathToGuid_.find(keyPath);
|
|
pathIterator != PathToGuid_.end() && pathIterator->second == guid) {
|
|
PathToGuid_.erase(pathIterator);
|
|
}
|
|
GuidToPath_.erase(iterator);
|
|
PrimaryAssetGuids_.erase(guid);
|
|
}
|
|
|
|
bool MetaCoreAssetRegistry::MoveAsset(const MetaCoreAssetGuid& guid, const std::filesystem::path& newRelativePath) {
|
|
if (!guid.IsValid() || !GuidToPath_.contains(guid)) {
|
|
return false;
|
|
}
|
|
const bool isPrimaryAsset = PrimaryAssetGuids_.contains(guid);
|
|
return isPrimaryAsset ? RegisterAsset(guid, newRelativePath) : RegisterSubAsset(guid, newRelativePath);
|
|
}
|
|
|
|
void MetaCoreAssetRegistry::Clear() {
|
|
GuidToPath_.clear();
|
|
PathToGuid_.clear();
|
|
PrimaryAssetGuids_.clear();
|
|
}
|
|
|
|
std::filesystem::path MetaCoreAssetRegistry::ResolveGuidToPath(const MetaCoreAssetGuid& guid) const {
|
|
const auto it = GuidToPath_.find(guid);
|
|
if (it != GuidToPath_.end()) {
|
|
return it->second;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
MetaCoreAssetGuid MetaCoreAssetRegistry::ResolvePathToGuid(const std::filesystem::path& relativePath) const {
|
|
const std::string keyPath = NormalizePathKey(relativePath);
|
|
const auto it = PathToGuid_.find(keyPath);
|
|
if (it != PathToGuid_.end()) {
|
|
return it->second;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
std::string MetaCoreAssetRegistry::NormalizePathKey(const std::filesystem::path& path) {
|
|
std::string keyPath = path.lexically_normal().generic_string();
|
|
#if defined(_WIN32)
|
|
std::transform(keyPath.begin(), keyPath.end(), keyPath.begin(), [](unsigned char value) {
|
|
return value >= 'A' && value <= 'Z' ? static_cast<char>(value - 'A' + 'a') : static_cast<char>(value);
|
|
});
|
|
#endif
|
|
return keyPath;
|
|
}
|
|
|
|
bool MetaCoreAssetRegistry::HasAsset(const MetaCoreAssetGuid& guid) const {
|
|
return GuidToPath_.count(guid) > 0;
|
|
}
|
|
|
|
} // namespace MetaCore
|