mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Universal AssetHandles. Serialize AssetHandle instead of AssetIdentifier
A bit unstable
This commit is contained in:
@@ -17,6 +17,9 @@ class AssetConfig
|
||||
|
||||
[BonInclude]
|
||||
public AssetLoaderConfig Config ~ delete _;
|
||||
|
||||
[BonInclude]
|
||||
public AssetHandle AssetHandle = .Invalid;
|
||||
}
|
||||
|
||||
class AssetFile
|
||||
@@ -79,11 +82,19 @@ class AssetFile
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateAssetHandle()
|
||||
{
|
||||
_assetConfig.AssetHandle = .();
|
||||
}
|
||||
|
||||
private void CreateDefaultAssetLoader()
|
||||
{
|
||||
String fileExtension = Path.GetExtension(_path, .. scope .());
|
||||
|
||||
_assetConfig = new AssetConfig();
|
||||
|
||||
GenerateAssetHandle();
|
||||
|
||||
var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension);
|
||||
|
||||
// We don't have a loader -> we don't need a config
|
||||
@@ -96,6 +107,7 @@ class AssetFile
|
||||
_assetConfig.Config = assetLoader?.GetDefaultConfig();
|
||||
_assetConfig.Config?.[Friend]_changed = true;
|
||||
|
||||
|
||||
SaveAssetConfig();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEditor.Assets;
|
||||
|
||||
@@ -96,6 +97,7 @@ class AssetHierarchy
|
||||
internal TreeNode<AssetNode> _assetsDirectoryNode = null;
|
||||
private append Dictionary<StringView, TreeNode<AssetNode>> _pathToAssetNode = .();
|
||||
private append Dictionary<StringView, TreeNode<AssetNode>> _identifierToAssetNode = .();
|
||||
private append Dictionary<AssetHandle, TreeNode<AssetNode>> _handleToAssetNode = .();
|
||||
|
||||
private append String _resourcesDirectory = .();
|
||||
private append String _assetsDirectory = .();
|
||||
@@ -166,7 +168,8 @@ class AssetHierarchy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Sets path to the directory that contains the engine assets.
|
||||
public void SetResourcesDirectory(StringView fileName)
|
||||
{
|
||||
ResourcesDirectory = fileName;
|
||||
@@ -206,6 +209,7 @@ class AssetHierarchy
|
||||
Update();
|
||||
}
|
||||
|
||||
/// Sets path to the directory that contains the game assets.
|
||||
public void SetAssetsDirectory(StringView fileName)
|
||||
{
|
||||
AssetsDirectory = fileName;
|
||||
@@ -225,7 +229,6 @@ class AssetHierarchy
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
AssetNode assetNode = new AssetNode();
|
||||
assetNode.Path = new String(AssetsDirectory);
|
||||
assetNode.Name = new String();
|
||||
@@ -239,7 +242,6 @@ class AssetHierarchy
|
||||
|
||||
Log.EngineLogger.Trace($"Created directory node for: \"{AssetsDirectory}\"");
|
||||
|
||||
|
||||
_fileSystemDirty = true;
|
||||
|
||||
SetupFileSystemWatcher();
|
||||
@@ -297,7 +299,7 @@ class AssetHierarchy
|
||||
return .Err;
|
||||
}
|
||||
|
||||
/// Gets the tree node for the given filePath or .Err, if the file/directory doesn't exist.
|
||||
/// Gets the tree node for the given asset identifier or .Err, if the file/directory doesn't exist.
|
||||
/// @param filePath the path for which to return the tree node.
|
||||
/// @remarks Do not hold a reference to the TreeNode because it can become invalid when the file hierarchy changes.
|
||||
public Result<TreeNode<AssetNode>> GetNodeFromIdentifier(StringView identifier)
|
||||
@@ -310,6 +312,19 @@ class AssetHierarchy
|
||||
return .Err;
|
||||
}
|
||||
|
||||
/// Gets the tree node for the given asset handle; or .Err, if no file exists with the given handle.
|
||||
/// @param filePath the path for which to return the tree node.
|
||||
/// @remarks Do not hold a reference to the TreeNode because it can become invalid when the file hierarchy changes.
|
||||
public Result<TreeNode<AssetNode>> GetNodeFromAssetHandle(AssetHandle assetHandle)
|
||||
{
|
||||
if (_handleToAssetNode.TryGetValue(assetHandle, let treeNode))
|
||||
{
|
||||
return treeNode;
|
||||
}
|
||||
|
||||
return .Err;
|
||||
}
|
||||
|
||||
public bool FileExists(StringView filePath)
|
||||
{
|
||||
return _pathToAssetNode.ContainsKey(filePath);
|
||||
@@ -399,6 +414,8 @@ class AssetHierarchy
|
||||
//GrabSubAssets(node);
|
||||
HandleFile(treeNode.Value);
|
||||
|
||||
_handleToAssetNode.Add(assetNode.AssetFile.AssetConfig.AssetHandle, treeNode);
|
||||
|
||||
Log.EngineLogger.Trace($"Created file node for: \"{assetNode.Path}\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,10 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
{
|
||||
for (let texture in effect.Textures)
|
||||
{
|
||||
ImGui.Button(texture.key);
|
||||
ImGui.TextUnformatted(texture.key);
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Button("Texture");
|
||||
|
||||
if (ImGui.BeginDragDropTarget())
|
||||
{
|
||||
@@ -315,7 +318,8 @@ class MaterialFile
|
||||
{
|
||||
public String Effect ~ delete _;
|
||||
|
||||
public Dictionary<String, String> Textures ~ DeleteDictionaryAndKeysAndValues!(_);
|
||||
//public Dictionary<String, String> Textures ~ DeleteDictionaryAndKeysAndValues!(_);
|
||||
public Dictionary<String, AssetHandle<Texture>> Textures ~ DeleteDictionaryAndKeys!(_);
|
||||
public Dictionary<String, VariableValue> Variables ~
|
||||
{
|
||||
if (_ != null)
|
||||
@@ -417,14 +421,13 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
|
||||
Material material = new Material(fx);
|
||||
|
||||
for (let (slotName, textureIdentifier) in materialFile.Textures)
|
||||
for (let (slotName, textureHandle) in materialFile.Textures)
|
||||
{
|
||||
|
||||
AssetHandle<Texture> texture = contentManager.LoadAsset(textureIdentifier);
|
||||
AssetHandle<Texture> texture = contentManager.LoadAsset(textureHandle);
|
||||
|
||||
if (texture.IsInvalid)
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
|
||||
Log.EngineLogger.Error($"Failed to load texture \"{textureHandle}\".");
|
||||
}
|
||||
|
||||
material.SetTexture(slotName, texture);
|
||||
@@ -475,9 +478,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
|
||||
for (let (slotName, texture) in material.[Friend]_textures)
|
||||
{
|
||||
Texture textureAsset = texture.Handle.Get();
|
||||
|
||||
materialFile.Textures.Add(new String(slotName), new String(textureAsset?.Identifier ?? ""));
|
||||
materialFile.Textures.Add(new String(slotName), texture.Handle);
|
||||
}
|
||||
|
||||
Effect effect = material.Effect;
|
||||
|
||||
@@ -1064,7 +1064,7 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
GeometryBinding mesh = meshComponent.Mesh;
|
||||
|
||||
StringView identifier = mesh?.Identifier ?? "None";
|
||||
StringView identifier = mesh?.Identifier ?? (meshComponent.Mesh.IsValid ? "<Missing Asset>" : "None");
|
||||
ImGui.Button(identifier.ToScopeCStr!());
|
||||
|
||||
if (ImGui.BeginDragDropTarget())
|
||||
|
||||
@@ -141,8 +141,18 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
if (payload != null)
|
||||
{
|
||||
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
||||
_editor.RequestOpenScene(this, path);
|
||||
StringView assetIdentifier = .((char8*)payload.Data, (int)payload.DataSize);
|
||||
|
||||
let treeNode = _editor.ContentManager.AssetHierarchy.GetNodeFromIdentifier(assetIdentifier);
|
||||
|
||||
if (treeNode case .Err)
|
||||
{
|
||||
Log.EngineLogger.Error($"Dragged Asset doesn't exist. {assetIdentifier}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_editor.RequestOpenScene(this, treeNode->Value.Path);
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
|
||||
@@ -221,7 +221,10 @@ class EditorContentManager : IContentManager
|
||||
{
|
||||
Asset asset = null;
|
||||
|
||||
_handleToAsset.TryGetValue(handle, out asset);
|
||||
if (!_handleToAsset.TryGetValue(handle, out asset))
|
||||
{
|
||||
LoadAsset(handle);
|
||||
}
|
||||
|
||||
if (var placeholder = asset as PlaceholderAsset)
|
||||
{
|
||||
@@ -339,7 +342,92 @@ class EditorContentManager : IContentManager
|
||||
private append List<(PlaceholderAsset placeholder, Asset newAsset)> _finishedEntries = .();
|
||||
|
||||
private class MissingAsset : Asset {}
|
||||
|
||||
/// Loads the Asset that is represented by the given AssetHandle.
|
||||
/// @returns The AssetHandle of the loaded asset or .Invalid if no asset exists with the given handle.
|
||||
public AssetHandle LoadAsset(AssetHandle handle, bool blocking = false)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
if (handle.IsInvalid)
|
||||
return .Invalid;
|
||||
|
||||
// If _handleToAsset contains handle, we for sure have an asset for it.
|
||||
if (_handleToAsset.ContainsKey(handle))
|
||||
return handle;
|
||||
|
||||
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromAssetHandle(handle);
|
||||
|
||||
if (resultNode case .Err)
|
||||
{
|
||||
Log.EngineLogger.Error($"Could not find asset with handle {handle}.");
|
||||
return .Invalid;
|
||||
}
|
||||
|
||||
String filePath = scope String(resultNode->Value.Path);
|
||||
|
||||
AssetFile file = resultNode->Value.AssetFile;
|
||||
|
||||
GetResourceAndSubassetName(file.Identifier, let resourceName, let subassetName);
|
||||
|
||||
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||
|
||||
// TODO: what are we supposed to do if we don't find a loader? Surely not crash...
|
||||
//Log.EngineLogger.AssertDebug(assetLoader != null);
|
||||
if (assetLoader == null)
|
||||
{
|
||||
Log.EngineLogger.Error($"No asset loader registered for asset \"{resultNode->Value.Identifier}\" ({handle}).");
|
||||
return .Invalid;
|
||||
}
|
||||
|
||||
Asset loadedAsset;
|
||||
|
||||
// TODO: Support lazy loading for all asset types
|
||||
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
|
||||
{
|
||||
Stream stream = OpenStream(filePath, true);
|
||||
|
||||
loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||
|
||||
delete stream;
|
||||
|
||||
if (loadedAsset == null)
|
||||
return .Invalid;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaceholderAsset placeholder = new PlaceholderAsset(file, assetLoader, .Loading);
|
||||
|
||||
String filePath2 = new String(filePath);
|
||||
String newResourceName = new String(resourceName);
|
||||
String newSesourceName = subassetName == null ? null : new String(subassetName.Value);
|
||||
|
||||
placeholder.LoadingTask = new Task(new () => {
|
||||
AsyncLoadAsset(placeholder, filePath2, assetLoader, file,
|
||||
newResourceName, newSesourceName);
|
||||
});
|
||||
|
||||
ThreadPool.QueueUserWorkItem(placeholder.LoadingTask);
|
||||
|
||||
loadedAsset = placeholder;
|
||||
}
|
||||
|
||||
loadedAsset.Identifier = file.Identifier;
|
||||
|
||||
_handleToAsset.Add(handle, loadedAsset);
|
||||
|
||||
loadedAsset.[Friend]_contentManager = this;
|
||||
loadedAsset.[Friend]_handle = handle;
|
||||
|
||||
// Add to Identifier -> Handle map
|
||||
_identiferToHandle.Add(loadedAsset.Identifier, handle);
|
||||
|
||||
file.[Friend]_loadedAsset = loadedAsset;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// Loads the Asset with the given asset identifier
|
||||
public AssetHandle LoadAsset(StringView identifier, bool blocking = false)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
@@ -347,10 +435,31 @@ class EditorContentManager : IContentManager
|
||||
// It's valid to request no entity, but no entity is obviously invalid.
|
||||
if (identifier.IsWhiteSpace)
|
||||
return .Invalid;
|
||||
|
||||
|
||||
// We allow backslashes as well as forward slashes. Some Path stuff like /./ is also allowed.
|
||||
String fixedIdentifier = scope String(identifier);
|
||||
AssetIdentifier.Fixup(fixedIdentifier);
|
||||
|
||||
// If we have an identifier -> handle mapping, we for sure have the asset and are done.
|
||||
if (_identiferToHandle.TryGetValue(fixedIdentifier, let asset))
|
||||
return asset;
|
||||
|
||||
if (AssetHierarchy.GetNodeFromIdentifier(fixedIdentifier) case .Ok(let assetNode))
|
||||
{
|
||||
return LoadAsset(assetNode->AssetFile.AssetConfig.AssetHandle, blocking);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Error($"Could not get asset node for asset {fixedIdentifier}");
|
||||
|
||||
return .Invalid;
|
||||
}
|
||||
|
||||
//Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromIdentifier(fixedIdentifier);
|
||||
|
||||
//resultNode.
|
||||
|
||||
/*
|
||||
if (_identiferToHandle.TryGetValue(fixedIdentifier, let asset))
|
||||
return asset;
|
||||
|
||||
@@ -411,7 +520,24 @@ class EditorContentManager : IContentManager
|
||||
}
|
||||
|
||||
loadedAsset.Identifier = fixedIdentifier;
|
||||
AssetHandle handle = ManageAsset(loadedAsset);
|
||||
|
||||
AssetHandle handle = .Invalid;
|
||||
|
||||
if (file.AssetConfig.AssetHandle == .Invalid)
|
||||
{
|
||||
handle = ManageAsset(loadedAsset);
|
||||
// TODO: Does this ever happen?
|
||||
file.AssetConfig.AssetHandle = handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
handle = file.AssetConfig.AssetHandle;
|
||||
_handleToAsset.Add(handle, loadedAsset);
|
||||
|
||||
loadedAsset.[Friend]_contentManager = this;
|
||||
loadedAsset.[Friend]_handle = handle;
|
||||
}
|
||||
|
||||
// ManageAsset increases RefCount, but this scope also holds a reference.
|
||||
loadedAsset.ReleaseRef();
|
||||
|
||||
@@ -420,7 +546,7 @@ class EditorContentManager : IContentManager
|
||||
|
||||
file.[Friend]_loadedAsset = loadedAsset;
|
||||
|
||||
return handle;
|
||||
return handle;*/
|
||||
}
|
||||
|
||||
private void AsyncLoadAsset(PlaceholderAsset placeholder, String filePath, IAssetLoader assetLoader, AssetFile file, String resourceName, String subassetName)
|
||||
|
||||
@@ -235,10 +235,7 @@ namespace GlitchyEditor
|
||||
_editor.EditorSceneRenderer = _editorSceneRenderer;
|
||||
|
||||
_editor.RequestOpenScene.Add(new (s, fileName) => {
|
||||
String fullName = scope .();
|
||||
Path.Combine(fullName, _currentProject.AssetsFolder, fileName);
|
||||
|
||||
LoadSceneFile(fullName);
|
||||
LoadSceneFile(fileName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1105,7 +1102,7 @@ namespace GlitchyEditor
|
||||
|
||||
private void ShowOpenRecentSceneMenu()
|
||||
{
|
||||
if (_currentProject == null)
|
||||
if (_currentProject == null || _currentProject.UserSettings.RecentScenes == null)
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
|
||||
Reference in New Issue
Block a user