using Ghost.Core;
using System.Text.Json;
namespace Ghost.Editor.Core.AssetHandle;
public static partial class AssetDatabase
{
///
/// Get the relative path from the assets directory.
///
private static Result GetRelativePath(string fullPath)
{
if (AssetsDirectory == null)
{
return Result.Failure("AssetsDirectory not initialized");
}
if (!fullPath.StartsWith(AssetsDirectory.FullName, StringComparison.OrdinalIgnoreCase))
{
return Result.Failure("Path is not within assets directory");
}
return Path.GetRelativePath(AssetsDirectory.FullName, fullPath);
}
///
/// Get the full path from a relative path.
///
private static Result GetFullPath(string relativePath)
{
if (AssetsDirectory == null)
{
return Result.Failure("AssetsDirectory not initialized");
}
return Path.Combine(AssetsDirectory.FullName, relativePath);
}
///
/// Find GUID by asset path.
///
/// Full or relative path to the asset.
/// The GUID of the asset if found.
public static Result PathToGuid(string assetPath)
{
var relativePath = assetPath;
// Convert to relative path if it's a full path
if (Path.IsPathRooted(assetPath))
{
var relResult = GetRelativePath(assetPath);
if (relResult.IsFailure)
{
return Result.Failure(relResult.Message);
}
relativePath = relResult.Value;
}
// Normalize path separators
relativePath = relativePath.Replace('\\', '/');
lock (s_dbLock)
{
if (s_pathAssetLookup.TryGetValue(relativePath, out var guid))
{
return guid;
}
}
return Result.Failure("Asset not found in database");
}
///
/// Find path by GUID.
///
/// GUID of the asset.
/// The relative path to the asset if found.
public static Result GuidToPath(Guid guid)
{
lock (s_dbLock)
{
if (s_assetPathLookup.TryGetValue(guid, out var path))
{
return path;
}
}
return Result.Failure("Asset GUID not found in database");
}
///
/// Load asset by GUID with caching.
///
/// Type of asset to load.
/// GUID of the asset.
/// The loaded asset.
public static Result LoadAsset(Guid guid) where T : Asset
{
// Implemented in AssetDatabase.Loader.cs
return LoadAssetInternal(guid);
}
///
/// Get asset tags by GUID.
///
/// GUID of the asset.
/// List of tags associated with the asset.
public static async ValueTask>> GetAssetTagsAsync(Guid guid, CancellationToken token = default)
{
var pathResult = GuidToPath(guid);
if (pathResult.IsFailure)
{
return Result>.Failure(pathResult.Message);
}
var fullPathResult = GetFullPath(pathResult.Value);
if (fullPathResult.IsFailure)
{
return Result>.Failure(fullPathResult.Message);
}
var metaResult = await ReadMetaFileAsync(fullPathResult.Value, token);
if (metaResult.IsFailure)
{
return Result>.Failure(metaResult.Message);
}
return metaResult.Value.Tags;
}
///
/// Set asset tags by GUID.
///
/// GUID of the asset.
/// New tags for the asset.
/// Result indicating success or failure.
public static async ValueTask SetAssetTagsAsync(Guid guid, List tags, CancellationToken token = default)
{
var pathResult = GuidToPath(guid);
if (pathResult.IsFailure)
{
return Result.Failure(pathResult.Message);
}
var fullPathResult = GetFullPath(pathResult.Value);
if (fullPathResult.IsFailure)
{
return Result.Failure(fullPathResult.Message);
}
var metaResult = await ReadMetaFileAsync(fullPathResult.Value, token);
if (metaResult.IsFailure)
{
return Result.Failure(metaResult.Message);
}
metaResult.Value.Tags = tags;
// Write updated metadata to .gmeta file
var writeResult = await WriteMetaFileAsync(fullPathResult.Value + Utilities.FileExtensions.META_FILE_EXTENSION, metaResult.Value, token);
if (writeResult.IsFailure)
{
return writeResult;
}
// Update database with new tags
var fileHash = await CalculateFileHashAsync(fullPathResult.Value, token);
return await UpsertAssetAsync(fullPathResult.Value, metaResult.Value, fileHash, null, token);
}
///
/// Search assets by name pattern.
/// Supports SQL LIKE wildcards: * (any characters) and ? (single character).
///
/// Search pattern (e.g., "*.txt", "player?", "test*").
/// List of matching asset GUIDs.
public static async Task> FindAssetsByNameAsync(string namePattern, CancellationToken token = default)
{
return await GetAssetsByNameAsync(namePattern, token);
}
///
/// Find assets by tag.
///
/// Tag to search for.
/// List of asset GUIDs with the specified tag.
public static async Task> FindAssetsByTagAsync(string tag, CancellationToken token = default)
{
return await GetAssetsByTagAsync(tag, token);
}
///
/// Get all assets in the database.
///
/// Dictionary mapping GUIDs to relative paths.
public static IReadOnlyDictionary GetAllAssets()
{
lock (s_dbLock)
{
return s_assetPathLookup.AsReadOnly();
}
}
}