Here’s a real example from ~/workspace/source/Plugins/DuplicationPlugin/DuplicateContextMenuItem.cs:613:
using Frosty.Core;using FrostySdk;using System.Windows.Media;namespace DuplicationPlugin{ public class DuplicateContextMenuItem : DataExplorerContextMenuExtension { // The text displayed in the context menu public override string ContextItemName => "Duplicate"; // Optional icon for the menu item public override ImageSource Icon => new ImageSourceConverter().ConvertFromString( "pack://application:,,,/FrostyEditor;component/Images/Add.png") as ImageSource; // The action to perform when clicked public override RelayCommand ContextItemClicked => new RelayCommand((o) => { // Get the selected asset EbxAssetEntry entry = App.SelectedAsset as EbxAssetEntry; // Show a dialog to configure duplication DuplicateAssetWindow win = new DuplicateAssetWindow(entry); if (win.ShowDialog() == false) return; string newName = win.SelectedPath + "/" + win.SelectedName; newName = newName.Trim('/'); // Perform the duplication FrostyTaskWindow.Show("Duplicating asset", "", (task) => { DuplicateAsset(entry, newName); }); // Refresh the Data Explorer App.EditorWindow.DataExplorer.RefreshAll(); }); private void DuplicateAsset(EbxAssetEntry entry, string newName) { // Implementation } }}
From ~/workspace/source/Plugins/BiowareLocalizationPlugin/BioWareLocalizedStringEditorMenuExtension.cs:
using Frosty.Core;using FrostySdk;namespace BiowareLocalizationPlugin{ public class BioWareLocalizedStringEditorMenuExtension : MenuExtension { // Top-level menu to add to public override string TopLevelMenuName => "View"; // Submenu (null for top-level) public override string SubLevelMenuName => null; // Menu item text public override string MenuItemName => "Bioware Localized String Editor"; // Action when clicked public override RelayCommand MenuItemClicked => new RelayCommand((o) => { // Open a custom editor window var textDb = (BiowareLocalizedStringDatabase)LocalizedStringDatabase.Current; App.EditorWindow.OpenEditor( "Bioware Localized String Editor", new BiowareLocalizedStringEditor(textDb)); }); }}
From ~/workspace/source/FrostyPlugin/Extensions/MenuExtension.cs:10:
public abstract class MenuExtension{ // Top-level menu name (e.g., "File", "Edit", "View") public virtual string TopLevelMenuName { get; } // Submenu name (null for top-level) public virtual string SubLevelMenuName { get; } // Menu item display name public virtual string MenuItemName { get; } // Optional icon public virtual ImageSource Icon { get; } // Click handler public virtual RelayCommand MenuItemClicked { get; }}
using Frosty.Core.Attributes;// Register for Editor only[assembly: RegisterMenuExtension(typeof(MyMenuExtension))]// Register for both Editor and Mod Manager[assembly: RegisterMenuExtension(typeof(MyMenuExtension), PluginManagerType.Both)]
From ~/workspace/source/FrostyPlugin/Attributes/RegisterMenuExtensionAttribute.cs:25:
using Frosty.Core;using System.Windows.Controls;namespace MyPlugin{ public class MyTabExtension : TabExtension { public override string TabItemName => "My Custom Tab"; public override FrostyBaseEditor CreateEditor() { return new MyCustomTabEditor(); } } public class MyCustomTabEditor : FrostyBaseEditor { public MyCustomTabEditor() { // Create your custom UI } }}
Startup actions run when Frosty first launches, before any profile is loaded:
using Frosty.Core;namespace MyPlugin{ public class MyStartupAction : StartupAction { public override void Execute() { // Runs at application startup // Initialize global resources, register services, etc. } }}
Always provide feedback for long-running operations:
FrostyTaskWindow.Show("Processing", "", (task) =>{ task.Update("Step 1..."); // Do work task.Update("Step 2...", 50); // 50% progress // Do more work});
Error Handling
Catch and log errors appropriately:
try{ // Risky operation}catch (Exception ex){ App.Logger.LogError($"Failed to process: {ex.Message}");}