Implement initial Unity-style asset library cache

This commit is contained in:
2026-04-02 03:03:36 +08:00
parent 619856ab22
commit 4c167bec0e
29 changed files with 4818 additions and 73 deletions

View File

@@ -13,21 +13,54 @@ std::string ToStdString(const Containers::String& value) {
return std::string(value.CStr());
}
std::string EncodeAssetRef(const Resources::AssetRef& assetRef) {
if (!assetRef.IsValid()) {
return std::string();
}
return ToStdString(assetRef.assetGuid.ToString()) + "," +
std::to_string(assetRef.localID) + "," +
std::to_string(static_cast<int>(assetRef.resourceType));
}
bool TryDecodeAssetRef(const std::string& value, Resources::AssetRef& outRef) {
const size_t firstComma = value.find(',');
const size_t secondComma = firstComma == std::string::npos ? std::string::npos : value.find(',', firstComma + 1);
if (firstComma == std::string::npos || secondComma == std::string::npos) {
return false;
}
const Containers::String guidText(value.substr(0, firstComma).c_str());
outRef.assetGuid = Resources::AssetGUID::ParseOrDefault(guidText);
outRef.localID = static_cast<Resources::LocalID>(std::stoull(value.substr(firstComma + 1, secondComma - firstComma - 1)));
outRef.resourceType = static_cast<Resources::ResourceType>(std::stoi(value.substr(secondComma + 1)));
return outRef.IsValid();
}
} // namespace
void MeshFilterComponent::SetMeshPath(const std::string& meshPath) {
m_meshPath = meshPath;
if (m_meshPath.empty()) {
m_mesh.Reset();
m_meshRef.Reset();
return;
}
m_mesh = Resources::ResourceManager::Get().Load<Resources::Mesh>(m_meshPath.c_str());
if (!Resources::ResourceManager::Get().TryGetAssetRef(m_meshPath.c_str(), Resources::ResourceType::Mesh, m_meshRef)) {
m_meshRef.Reset();
}
}
void MeshFilterComponent::SetMesh(const Resources::ResourceHandle<Resources::Mesh>& mesh) {
m_mesh = mesh;
m_meshPath = mesh.Get() != nullptr ? ToStdString(mesh->GetPath()) : std::string();
if (m_meshPath.empty()) {
m_meshRef.Reset();
} else if (!Resources::ResourceManager::Get().TryGetAssetRef(m_meshPath.c_str(), Resources::ResourceType::Mesh, m_meshRef)) {
m_meshRef.Reset();
}
}
void MeshFilterComponent::SetMesh(Resources::Mesh* mesh) {
@@ -37,17 +70,22 @@ void MeshFilterComponent::SetMesh(Resources::Mesh* mesh) {
void MeshFilterComponent::ClearMesh() {
m_mesh.Reset();
m_meshPath.clear();
m_meshRef.Reset();
}
void MeshFilterComponent::Serialize(std::ostream& os) const {
os << "mesh=" << m_meshPath << ";";
os << "meshRef=" << EncodeAssetRef(m_meshRef) << ";";
}
void MeshFilterComponent::Deserialize(std::istream& is) {
m_mesh.Reset();
m_meshPath.clear();
m_meshRef.Reset();
std::string token;
std::string pendingMeshPath;
Resources::AssetRef pendingMeshRef;
while (std::getline(is, token, ';')) {
if (token.empty()) {
continue;
@@ -62,9 +100,23 @@ void MeshFilterComponent::Deserialize(std::istream& is) {
const std::string value = token.substr(eqPos + 1);
if (key == "mesh") {
SetMeshPath(value);
pendingMeshPath = value;
} else if (key == "meshRef") {
TryDecodeAssetRef(value, pendingMeshRef);
}
}
if (pendingMeshRef.IsValid()) {
m_meshRef = pendingMeshRef;
m_mesh = Resources::ResourceManager::Get().Load<Resources::Mesh>(pendingMeshRef);
if (m_mesh.Get() != nullptr) {
m_meshPath = ToStdString(m_mesh->GetPath());
} else {
m_meshPath = pendingMeshPath;
}
} else if (!pendingMeshPath.empty()) {
SetMeshPath(pendingMeshPath);
}
}
} // namespace Components

View File

@@ -13,6 +13,29 @@ std::string ToStdString(const Containers::String& value) {
return std::string(value.CStr());
}
std::string EncodeAssetRef(const Resources::AssetRef& assetRef) {
if (!assetRef.IsValid()) {
return std::string();
}
return ToStdString(assetRef.assetGuid.ToString()) + "," +
std::to_string(assetRef.localID) + "," +
std::to_string(static_cast<int>(assetRef.resourceType));
}
bool TryDecodeAssetRef(const std::string& value, Resources::AssetRef& outRef) {
const size_t firstComma = value.find(',');
const size_t secondComma = firstComma == std::string::npos ? std::string::npos : value.find(',', firstComma + 1);
if (firstComma == std::string::npos || secondComma == std::string::npos) {
return false;
}
outRef.assetGuid = Resources::AssetGUID::ParseOrDefault(Containers::String(value.substr(0, firstComma).c_str()));
outRef.localID = static_cast<Resources::LocalID>(std::stoull(value.substr(firstComma + 1, secondComma - firstComma - 1)));
outRef.resourceType = static_cast<Resources::ResourceType>(std::stoi(value.substr(secondComma + 1)));
return outRef.IsValid();
}
std::vector<std::string> SplitMaterialPaths(const std::string& value) {
std::vector<std::string> paths;
if (value.empty()) {
@@ -34,6 +57,32 @@ std::vector<std::string> SplitMaterialPaths(const std::string& value) {
return paths;
}
std::vector<Resources::AssetRef> SplitMaterialRefs(const std::string& value) {
std::vector<Resources::AssetRef> refs;
if (value.empty()) {
return refs;
}
size_t start = 0;
while (true) {
const size_t separator = value.find('|', start);
const std::string token = separator == std::string::npos
? value.substr(start)
: value.substr(start, separator - start);
Resources::AssetRef ref;
TryDecodeAssetRef(token, ref);
refs.push_back(ref);
if (separator == std::string::npos) {
break;
}
start = separator + 1;
}
return refs;
}
} // namespace
Resources::Material* MeshRendererComponent::GetMaterial(size_t index) const {
@@ -55,16 +104,24 @@ void MeshRendererComponent::SetMaterialPath(size_t index, const std::string& mat
m_materialPaths[index] = materialPath;
if (materialPath.empty()) {
m_materials[index].Reset();
m_materialRefs[index].Reset();
return;
}
m_materials[index] = Resources::ResourceManager::Get().Load<Resources::Material>(materialPath.c_str());
if (!Resources::ResourceManager::Get().TryGetAssetRef(materialPath.c_str(), Resources::ResourceType::Material, m_materialRefs[index])) {
m_materialRefs[index].Reset();
}
}
void MeshRendererComponent::SetMaterial(size_t index, const Resources::ResourceHandle<Resources::Material>& material) {
EnsureMaterialSlot(index);
m_materials[index] = material;
m_materialPaths[index] = MaterialPathFromHandle(material);
if (m_materialPaths[index].empty() ||
!Resources::ResourceManager::Get().TryGetAssetRef(m_materialPaths[index].c_str(), Resources::ResourceType::Material, m_materialRefs[index])) {
m_materialRefs[index].Reset();
}
}
void MeshRendererComponent::SetMaterial(size_t index, Resources::Material* material) {
@@ -74,14 +131,20 @@ void MeshRendererComponent::SetMaterial(size_t index, Resources::Material* mater
void MeshRendererComponent::SetMaterials(const std::vector<Resources::ResourceHandle<Resources::Material>>& materials) {
m_materials = materials;
m_materialPaths.resize(materials.size());
m_materialRefs.resize(materials.size());
for (size_t i = 0; i < materials.size(); ++i) {
m_materialPaths[i] = MaterialPathFromHandle(materials[i]);
if (m_materialPaths[i].empty() ||
!Resources::ResourceManager::Get().TryGetAssetRef(m_materialPaths[i].c_str(), Resources::ResourceType::Material, m_materialRefs[i])) {
m_materialRefs[i].Reset();
}
}
}
void MeshRendererComponent::ClearMaterials() {
m_materials.clear();
m_materialPaths.clear();
m_materialRefs.clear();
}
void MeshRendererComponent::Serialize(std::ostream& os) const {
@@ -93,6 +156,14 @@ void MeshRendererComponent::Serialize(std::ostream& os) const {
os << m_materialPaths[i];
}
os << ";";
os << "materialRefs=";
for (size_t i = 0; i < m_materialRefs.size(); ++i) {
if (i > 0) {
os << "|";
}
os << EncodeAssetRef(m_materialRefs[i]);
}
os << ";";
os << "castShadows=" << (m_castShadows ? 1 : 0) << ";";
os << "receiveShadows=" << (m_receiveShadows ? 1 : 0) << ";";
os << "renderLayer=" << m_renderLayer << ";";
@@ -105,6 +176,7 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
m_renderLayer = 0;
std::string token;
std::vector<Resources::AssetRef> pendingMaterialRefs;
while (std::getline(is, token, ';')) {
if (token.empty()) {
continue;
@@ -121,9 +193,9 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
if (key == "materials") {
m_materialPaths = SplitMaterialPaths(value);
m_materials.resize(m_materialPaths.size());
for (size_t i = 0; i < m_materialPaths.size(); ++i) {
SetMaterialPath(i, m_materialPaths[i]);
}
m_materialRefs.resize(m_materialPaths.size());
} else if (key == "materialRefs") {
pendingMaterialRefs = SplitMaterialRefs(value);
} else if (key == "castShadows") {
m_castShadows = (std::stoi(value) != 0);
} else if (key == "receiveShadows") {
@@ -132,12 +204,32 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
m_renderLayer = static_cast<uint32_t>(std::stoul(value));
}
}
if (pendingMaterialRefs.size() > m_materialPaths.size()) {
m_materialPaths.resize(pendingMaterialRefs.size());
m_materials.resize(pendingMaterialRefs.size());
m_materialRefs.resize(pendingMaterialRefs.size());
}
for (size_t i = 0; i < m_materialPaths.size(); ++i) {
if (i < pendingMaterialRefs.size() && pendingMaterialRefs[i].IsValid()) {
m_materialRefs[i] = pendingMaterialRefs[i];
m_materials[i] = Resources::ResourceManager::Get().Load<Resources::Material>(pendingMaterialRefs[i]);
if (m_materials[i].Get() != nullptr) {
m_materialPaths[i] = MaterialPathFromHandle(m_materials[i]);
continue;
}
}
SetMaterialPath(i, m_materialPaths[i]);
}
}
void MeshRendererComponent::EnsureMaterialSlot(size_t index) {
if (index >= m_materials.size()) {
m_materials.resize(index + 1);
m_materialPaths.resize(index + 1);
m_materialRefs.resize(index + 1);
}
}