using System; using GlitchyEngine; using System.IO; using Bon; using GlitchyEngine.Content; using GlitchyEditor.Assets; using GlitchyEditor.Assets.Importers; namespace GlitchyEditor; [BonTarget] class AssetConfig { [BonIgnore] public bool IgnoreFile = false; [BonInclude] public String AssetLoader ~ delete _; [BonInclude] public AssetLoaderConfig Config ~ delete _; [BonInclude] public String Importer ~ delete _; [BonInclude] public AssetImporterConfig ImporterConfig ~ delete _; [BonInclude] public String Processor ~ delete _; [BonInclude] public AssetProcessorConfig ProcessorConfig ~ delete _; [BonInclude] public String Exporter ~ delete _; [BonInclude] public AssetExporterConfig ExporterConfig ~ delete _; [BonInclude] public AssetHandle AssetHandle = .Invalid; } /// Represents an unprocessed asset as it lies in the asset hierarchy. class AssetFile { private EditorContentManager _contentManager; private String _assetConfigPath ~ delete:append _; private AssetNode _assetFile; private AssetConfig _assetConfig ~ delete _; private Asset _loadedAsset; private DateTime _lastAssetEditTime; private DateTime _lastConfigEditTime; public AssetNode AssetFile => _assetFile; public StringView AssetConfigPath => _assetConfigPath; public const String ConfigFileExtension = ".ass"; public AssetConfig AssetConfig => _assetConfig; public Asset LoadedAsset => _loadedAsset; public EditorContentManager ContentManager => _contentManager; public bool UseNewAssetPipeline => _assetConfig?.Importer != null; [AllowAppend] public this(EditorContentManager contentManager, AssetNode assetNode) { String configPathBuffer = append String(assetNode.Path.Length + ConfigFileExtension.Length); configPathBuffer..Append(assetNode.Path).Append(ConfigFileExtension); _assetConfigPath = configPathBuffer; _contentManager = contentManager; _assetFile = assetNode; _lastAssetEditTime = File.GetLastWriteTimeUtc(_assetFile.Path); } public static AssetFile LoadOrCreateAssetFile(EditorContentManager contentManager, AssetNode assetNode) { AssetFile assetFile = new AssetFile(contentManager, assetNode); assetFile.CheckForReprocessing(); return assetFile; } public void CheckForReprocessing() { LoadOrCreateAssetConfig(); // TODO: Remove this check once we only use the new processing pipeline if (!UseNewAssetPipeline) return; CachedAsset cacheEntry = _contentManager.AssetCache.GetCacheEntry(_assetConfig.AssetHandle); _lastAssetEditTime = File.GetLastWriteTimeUtc(_assetFile.Path); _lastConfigEditTime = File.GetLastWriteTimeUtc(_assetConfigPath); if (cacheEntry == null || cacheEntry.CreationTimestamp < _lastAssetEditTime || cacheEntry.CreationTimestamp < _lastConfigEditTime) { _contentManager.AssetConverter.QueueForProcessing(this); } } /// Loads the asset config (.ass) file or creates it. private void LoadOrCreateAssetConfig() { if (File.Exists(_assetConfigPath)) { LoadAssetConfig(); } else if (_assetConfig == null) { CreateDefaultAssetLoader(); } _lastConfigEditTime = File.GetLastWriteTimeUtc(_assetConfigPath); } private void GenerateAssetHandle() { _assetConfig.AssetHandle = .(); } private void CreateDefaultAssetLoader() { String fileExtension = Path.GetExtension(_assetFile.Path, .. scope .()); Log.EngineLogger.Info($"Creating asset config for {_assetFile.Path}"); _assetConfig = new AssetConfig(); GenerateAssetHandle(); IAssetImporter assetImporter = _contentManager.GetAssetImporter(fileExtension); //IAssetProcessor assetProcessor = ?; //_contentManager.GetAssetProcessor(assetImporter.); //IAssetExporter assetExporter = ?; //_contentManager.GetAssetProcessor(assetImporter.); // TODO! //if (assetPipeline case .Err) // return; var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension); if (assetLoader != null || assetImporter != null) { _assetConfig.AssetLoader = new String(); assetLoader.GetType().GetName(_assetConfig.AssetLoader); _assetConfig.Config = assetLoader?.GetDefaultConfig(); _assetConfig.Config?.[Friend]_changed = true; _assetConfig.Importer = new String(); assetImporter?.GetType()?.GetName(_assetConfig.Importer); } // We might not have a loader, but we want to retain the AssetHandle: // e. g. a .txt File can't be reasonably imported, but might still need to be packed into the final // application bundle and be read in a script via AssetHandle. SaveAssetConfig(); } private void LoadAssetConfig() { AssetConfig newAssetConfig = new AssetConfig(); if (Bon.DeserializeFromFile(ref newAssetConfig, _assetConfigPath) case .Err) { Log.EngineLogger.Error($"Failed to load asset config {_assetConfigPath}"); delete newAssetConfig; return; } delete _assetConfig; _assetConfig = newAssetConfig; } public void SaveAssetConfigIfChanged() { if (_assetConfig.Config?.Changed == true || _assetConfig.ImporterConfig?.Changed == true || _assetConfig.ProcessorConfig?.Changed == true || _assetConfig.ExporterConfig?.Changed == true) { SaveAssetConfig(); } } public void SaveAssetConfig() { //BonEnvironment bonEnv = scope .(); var oldFlags = gBonEnv.serializeFlags; gBonEnv.serializeFlags |= .IncludeDefault | .Verbose; Bon.SerializeIntoFile(_assetConfig, _assetConfigPath); _assetConfig.Config?.[Friend]_changed = false; _assetConfig.ImporterConfig?.[Friend]_changed = false; _assetConfig.ProcessorConfig?.[Friend]_changed = false; _assetConfig.ExporterConfig?.[Friend]_changed = false; gBonEnv.serializeFlags = oldFlags; } }