using System.IO; namespace Editor; public static class CreateAsset { public struct Entry { public string Name { get; init; } public string Icon { get; init; } public Pixmap IconImage { get; init; } public string Category { get; init; } // Should these show at the top outside of category views? public bool Pinned { get; init; } public Action Action { get; init; } public string Default { get; init; } public void Execute( DirectoryInfo folder ) { if ( Action is not null ) { Action( folder ); return; } if ( !string.IsNullOrEmpty( Default ) ) { CreateFromTemplate( Name, Default, folder ); } } } static CreateAsset() { } internal static void AddOptions( Menu parent, LocalAssetBrowser.Location location ) { var folder = new DirectoryInfo( location.Path ); parent.AddOption( "Folder", "folder", () => Dialog.AskStringFolder( ( string foldername ) => { folder.CreateSubdirectory( foldername ); EditorEvent.Run( "assetsystem.newfolder" ); }, "New folder name..", "Create Folder" ) ); parent.AddSeparator(); var gameResources = EditorTypeLibrary.GetAttributes().Select( x => new Entry() { Name = x.Name, Category = x.Category, IconImage = AssetType.FromType( x.TargetType )?.Icon64, Action = ( DirectoryInfo d ) => CreateGameResource( x, d ), Pinned = x.Extension == "sound" || x.Extension == "prefab" || x.Extension == "scene" } ); var entries = new List(); if ( location.Type is LocalAssetBrowser.LocationType.Localization ) { entries.Add( new Entry { Name = "Empty JSON File", Icon = "data_object", Default = "localization.json", Pinned = true } ); } else if ( location.Type is LocalAssetBrowser.LocationType.Code ) { entries.Add( new Entry { Name = "Empty C# File", Icon = "description", Default = "default.cs", Category = "Code", Pinned = true } ); entries.Add( new Entry { Name = "Component", Icon = "sports_esports", Default = "component.cs", Category = "Code", Pinned = true } ); entries.Add( new Entry { Name = "Panel Component", Icon = "desktop_windows", Default = "default.razor", Category = "Razor" } ); entries.Add( new Entry { Name = "Style Sheet", Icon = "brush", Default = "default.scss", Category = "Razor" } ); } else if ( location.Type is LocalAssetBrowser.LocationType.Assets ) { entries.Add( new Entry { Name = "Material", IconImage = AssetType.FromType( typeof( Material ) )?.Icon64, Default = "default.vmat", Category = "Rendering", Pinned = true } ); entries.Add( new Entry { Name = "Model", IconImage = AssetType.FromType( typeof( Model ) )?.Icon64, Default = "default.vmdl", Category = "Rendering", Pinned = true } ); entries.Add( new Entry { Name = "Map", Icon = "hardware", Default = "default.vmap", Category = "World" } ); entries.Add( new Entry { Name = "Standard Material Shader", Icon = "brush", Default = "material.shader", Category = "Shader" } ); entries.Add( new Entry { Name = "Unlit Shader", Icon = "brush", Default = "unlit.shader", Category = "Shader" } ); entries.Add( new Entry { Name = "Compute Shader", Icon = "brush", Default = "compute.shader", Category = "Shader" } ); entries.Add( new Entry { Name = "Shader Graph", Icon = "account_tree", Default = "default.shdrgrph", Category = "Shader" } ); entries.Add( new Entry { Name = "Shader Graph Function", Icon = "account_tree", Default = "subgraph.shdrfunc", Category = "Shader" } ); entries.AddRange( gameResources ); } foreach ( var entry in entries.Where( x => x.Pinned ).OrderBy( x => x.Name ) ) { if ( entry.IconImage != null ) parent.AddOptionWithImage( entry.Name, entry.IconImage, () => entry.Execute( folder ) ); else parent.AddOption( entry.Name, entry.Icon, () => entry.Execute( folder ) ); } parent.AddSeparator(); var grouped = entries.OrderBy( x => x.Name ).GroupBy( x => x.Category ).OrderBy( x => x.Key ); foreach ( var group in grouped.Where( x => x.Key is not null ) ) { var menu = parent.FindOrCreateMenu( group.Key ); foreach ( var entry in group ) { if ( entry.IconImage != null ) menu.AddOptionWithImage( entry.Name, entry.IconImage, () => entry.Execute( folder ) ); else menu.AddOption( entry.Name, entry.Icon, () => entry.Execute( folder ) ); } } } static string GetNewFilename( DirectoryInfo folder, string typeName, string extension ) { typeName = typeName.ToLower(); string destName = $"new {typeName}{extension}"; int i = 1; while ( File.Exists( Path.Combine( folder.FullName, destName ) ) ) { destName = $"new {typeName} {i++}{extension}"; } return destName; } static void CreateFromTemplate( string name, string defaultFile, DirectoryInfo folder ) { var extension = System.IO.Path.GetExtension( defaultFile ); var sourceFile = FileSystem.Root.GetFullPath( $"/templates/{defaultFile}" ); if ( !System.IO.File.Exists( sourceFile ) ) { Log.Error( $"Can't create asset! Missing template: {defaultFile}" ); return; } string destName = GetNewFilename( folder, name, extension ); string destPath = Path.Combine( folder.FullName, destName ); System.IO.File.Copy( sourceFile, destPath ); var asset = AssetSystem.RegisterFile( destPath ); MainAssetBrowser.Instance?.Local.OnAssetCreated( asset, destPath ); } public static void CreateGameResource( AssetTypeAttribute gameResource, DirectoryInfo folder ) { int slash = gameResource.Name.LastIndexOf( '/' ); string name = slash == -1 ? gameResource.Name : gameResource.Name.Substring( slash + 1, gameResource.Name.Length - slash - 1 ); string destName = GetNewFilename( folder, name, $".{gameResource.Extension}" ); string destPath = Path.Combine( folder.FullName, destName ); var asset = AssetSystem.CreateResource( gameResource.Extension, destPath ); MainAssetBrowser.Instance?.Local.OnAssetCreated( asset, destPath ); } }