Extending Editor Pro
The public API is in the Fullscreen.EditorPro2 namespace. It lives in an editor-only assembly, so put integration code in an Editor folder or an editor-only assembly definition.
Register extensions once after Unity loads the editor. InitializeOnLoad is a good fit:
using UnityEditor;
using UnityEngine;
using Fullscreen.EditorPro2;
[InitializeOnLoad]
public static class QuestEditorProSetup
{
static QuestEditorProSetup()
{
Registry.RegisterCategory(
id: "my-game.quests",
displayName: "Quests",
icon: null,
order: 20);
Registry.RegisterTypePolicy(new TypePolicy(
id: "my-game.quest-policy",
appliesTo: type => type == typeof(QuestDefinition),
classification: TypeClassification.Provider,
defaultCategoryId: "my-game.quests",
enabled: true,
creationPriority: 100));
}
}Use stable, unique IDs such as my-game.quest-policy. Registering most ID-based extensions again replaces the old registration. Metadata providers are the exception: each call adds another provider.
Editor Pro catches exceptions from registered predicates and callbacks, writes them to the Unity Console, and keeps the browser running. Keep callbacks quick, especially search, badge, and validation callbacks because the browser calls them while drawing assets.
Registry API
| Method | What it does |
|---|---|
RegisterCategory(string id, string displayName, int order = 0) | Adds a category supplied by code. |
RegisterCategory(string id, string displayName, Texture2D icon, int order = 0) | Same, with a sidebar icon. |
RegisterCreator(Type assetType, Action<ScriptableObject> configure) | Sets up an asset after direct fallback creation. |
RegisterIconProvider(Type assetType, Func<ScriptableObject, Texture2D> provider) | Supplies an icon for an asset type. The asset may be null when Editor Pro needs a generic type icon. |
RegisterCreateAction(Type assetType, string id, string displayName, Action<ScriptableObject, string> configure = null) | Registers a named setup action for direct fallback creation. displayName is available through the registry for integrations; it is not a second button in the built-in create menu. |
RegisterCreationWorkflow(CreationWorkflow workflow) | Gives a type a complete custom creation workflow. |
RegisterAssetAction(AssetAction action) | Adds an item to the asset right-click menu. |
RegisterAssetBadgeProvider(AssetBadgeProvider provider) | Draws small badges on assets. Grid cards show at most two; list rows show at most three. |
RegisterAssetValidator(AssetValidator validator) | Shows info, warning, or error messages above the inspector. A validation can include a Fix button. |
RegisterSearchProvider(SearchProvider provider) | Adds searchable words for matching assets. |
RegisterTypePolicy(TypePolicy policy) | Sets defaults for discovered asset types. |
RegisterInspectorTab(string id, string title, Func<ScriptableObject, bool> appliesTo, Func<ScriptableObject, VisualElement> create) | Adds a tab next to the normal inspector. |
RegisterInspectorHeaderExtension(InspectorHeaderExtension extension) | Adds a UI element to the inspector header, before the built-in action buttons. |
RegisterMetadataProvider(Func<ScriptableObject, IEnumerable<Metadata>> provider) | Adds simple Label: Value lines below the normal inspector. |
RegisteredCategories, RegisteredCreateActions, RegisteredCreationWorkflows, RegisteredInspectorTabs, RegisteredInspectorHeaderExtensions, RegisteredAssetActions, RegisteredAssetBadgeProviders, RegisteredAssetValidators, RegisteredSearchProviders, and RegisteredTypePolicies expose the currently registered items as read-only collections.
The public lookup methods are GetCreator, GetIcon, GetTypePolicy, GetCreationWorkflow, GetAssetActions, GetInspectorHeaderExtensions, GetSearchTerms, GetBadges, GetValidations, and GetMetadata. They are mainly useful when building an integration on top of Editor Pro itself.
For icon providers and creators, Editor Pro uses the exact type first, then the closest registered base type. For a creation workflow, it uses the closest matching base type, then the highest priority. For type policies, it uses the matching policy with the highest priority, then the lowest ID alphabetically. Asset actions and inspector header extensions are ordered by descending priority.
The registry collections use these small read-only data types:
| Type | Public values |
|---|---|
Category | Id, DisplayName, Icon, and Order. This is what RegisterCategory creates. |
CreateAction | AssetType, Id, DisplayName, and Configure. This is what RegisterCreateAction creates. |
InspectorTab | Id, Title, AppliesTo, and Create. This is what RegisterInspectorTab creates. |
Metadata | Label and Value. Create one with new Metadata(label, value). |
AssetBadge | Text, Icon, Color, and Tooltip. Create one with new AssetBadge(...). |
AssetValidation | Severity, Message, Title, FixLabel, and Fix. Create one with new AssetValidation(...). |
MetadataProvider is exposed as a type, but its constructor and provider callback are internal. Register metadata through RegisterMetadataProvider instead of creating one yourself.
Common API data
AssetContext
Every asset callback receives an AssetContext. It gives you:
Asset: the ScriptableObject.AssetType: its runtime type.AssetPathandAssetGuid: Unity asset details.CategoryId: the asset's current category.IsFavourite,IsOpen, andIsActive: its current Editor Pro state.
AssetContext objects are made by Editor Pro. Your code reads them; it does not create them.
TypePolicy
new TypePolicy(
string id,
Func<Type, bool> appliesTo,
TypeClassification? classification = null,
string defaultCategoryId = null,
bool? enabled = null,
bool showInOnboarding = true,
int creationPriority = 0,
int priority = 0)classification is CreateAssetMenu, Provider, Other, or Unknown. defaultCategoryId and enabled are applied to a newly discovered type. Existing user choices are left alone when types are scanned again, except that a policy can update the type classification. showInOnboarding hides the type from the setup screen. creationPriority moves the type higher in the create picker.
Register policies before opening type setup. A category ID used by a policy must already exist, either from Settings or from RegisterCategory.
AssetAction
Registry.RegisterAssetAction(new AssetAction(
id: "my-game.quest.mark-complete",
title: "Mark complete",
execute: context =>
{
var quest = context.Asset as QuestDefinition;
if (quest == null) return;
quest.IsComplete = true;
EditorUtility.SetDirty(quest);
},
appliesTo: context => context.Asset is QuestDefinition,
isEnabled: context => !((QuestDefinition)context.Asset).IsComplete,
icon: null,
priority: 50));appliesTo decides whether the action is listed. isEnabled decides whether it can be clicked. After a registered action runs, Editor Pro saves assets, refreshes its browser, redraws the active inspector, and raises an Updated event. The icon is part of the data object, but the current built-in context menu displays the action title only.
Search, badges, and validation
using System.Collections.Generic;
using UnityEngine;
using Fullscreen.EditorPro2;
// Makes an asset's quest ID searchable.
Registry.RegisterSearchProvider(new SearchProvider(
"my-game.quest-search",
context => context.Asset is QuestDefinition quest
? new[] { quest.QuestId, quest.Author }
: null));
// Shows a small green DONE badge when the quest is complete.
Registry.RegisterAssetBadgeProvider(new AssetBadgeProvider(
"my-game.quest-status",
context => context.Asset is QuestDefinition quest && quest.IsComplete
? new[] { new AssetBadge("DONE", color: Color.green, tooltip: "This quest is complete") }
: null));
// Shows a warning and offers a one-click fix.
Registry.RegisterAssetValidator(new AssetValidator(
"my-game.quest-id",
context =>
{
if (context.Asset is not QuestDefinition quest || !string.IsNullOrWhiteSpace(quest.QuestId))
return null;
return new[]
{
new AssetValidation(
ValidationSeverity.Warning,
"This quest needs an ID.",
title: "Missing ID",
fixLabel: "Make ID",
fix: _ =>
{
quest.QuestId = System.Guid.NewGuid().ToString("N");
UnityEditor.EditorUtility.SetDirty(quest);
})
};
}));SearchProvider takes an ID and Func<AssetContext, IEnumerable<string>>. AssetBadgeProvider takes an ID and returns AssetBadge items. A badge accepts optional text, Texture2D icon, Color color, and tooltip.
AssetValidator takes an ID and returns AssetValidation items. An AssetValidation takes a ValidationSeverity (Info, Warning, or Error), a message, optional title, optional fix button label, and optional fix callback.
Inspector API
using UnityEngine;
using UnityEngine.UIElements;
using Fullscreen.EditorPro2;
Registry.RegisterInspectorHeaderExtension(new InspectorHeaderExtension(
id: "my-game.quest-header",
create: context =>
{
var button = new Button(() => Debug.Log(context.Asset.name))
{
text = "Log quest"
};
return button;
},
appliesTo: context => context.Asset is QuestDefinition,
priority: 10));
Registry.RegisterInspectorTab(
id: "my-game.quest-preview",
title: "Preview",
appliesTo: asset => asset is QuestDefinition,
create: asset => new Label($"Preview for {asset.name}"));
Registry.RegisterMetadataProvider(asset => asset is QuestDefinition quest
? new[] { new Metadata("Quest ID", quest.QuestId) }
: null);InspectorHeaderExtension takes an ID, a function that returns a VisualElement, an optional AssetContext filter, and an optional priority. If the UI you return changes an asset, that button is responsible for marking the asset dirty and saving it when appropriate.
RegisterInspectorTab uses ScriptableObject rather than AssetContext. The normal Unity inspector is always available; registered tabs appear as extra buttons above it. If a custom tab throws an exception while it is created, Editor Pro shows the error in the inspector area.
Metadata is a simple pair of Label and Value strings. Metadata appears below the normal inspector, not inside a custom tab.
Creation API
Use a CreationWorkflow when a type needs its own way to create an asset or needs a custom file name.
using UnityEditor;
using UnityEngine;
using Fullscreen.EditorPro2;
Registry.RegisterCreationWorkflow(new CreationWorkflow(
id: "my-game.quest-creation",
assetType: typeof(QuestDefinition),
create: path =>
{
var quest = ScriptableObject.CreateInstance<QuestDefinition>();
quest.QuestId = System.Guid.NewGuid().ToString("N");
AssetDatabase.CreateAsset(quest, path);
return quest;
},
onCreated: (asset, path) =>
{
EditorUtility.SetDirty(asset);
},
defaultFileName: _ => "New Quest",
priority: 100));CreationWorkflow accepts:
id: a stable unique name for the workflow.assetType: the ScriptableObject type it handles. It can also handle derived types.create: optionalFunc<string, ScriptableObject>. It receives the chosen asset path and should create and return the requested type. Returningnulllets Editor Pro continue with Unity's normal creation route.onCreated: optionalAction<ScriptableObject, string>called after an asset is created.defaultFileName: optionalFunc<Type, string>for the Save dialog's suggested file name.priority: breaks a tie between workflows for the same base type.
RegisterCreator and RegisterCreateAction are smaller hooks for direct fallback creation. RegisterCreator runs one setup callback after ScriptableObject.CreateInstance. RegisterCreateAction runs its configure callback for the exact created type. Neither one runs when Unity's normal Assets/Create command creates the asset. Use CreationWorkflow.onCreated when the setup must run for every creation path.
Events API
Subscribe from editor code when another tool needs to react to what the user did in Editor Pro:
using UnityEditor;
using Fullscreen.EditorPro2;
[InitializeOnLoad]
public static class QuestEditorProEvents
{
static QuestEditorProEvents()
{
Events.AssetChanged += OnAssetChanged;
Events.BrowserRefreshed += OnBrowserRefreshed;
}
private static void OnAssetChanged(AssetChange change)
{
// change.Kind and change.Context describe the new state.
}
private static void OnBrowserRefreshed(BrowserRefresh refresh)
{
// refresh.CategoryId and refresh.VisibleAssetCount describe the view.
}
}Events.AssetChanged sends an AssetChange with:
Kind:Created,Duplicated,Deleted,Moved,Updated,Opened,Favourited, orCategorised.Context: the currentAssetContext. For a deleted asset, this is the context captured just before deletion.PreviousAssetPath: filled for moves and deletion when useful.PreviousCategoryId: filled when an asset changes category.
Events.BrowserRefreshed sends a BrowserRefresh with the current CategoryId and VisibleAssetCount.
Do not manually raise these events. Editor Pro raises them as part of its own workflows.