import { NodeTemplate } from '@esengine/behavior-tree'; import { BehaviorTreeNode } from '../../stores/behaviorTreeStore'; import { LucideIcon } from 'lucide-react'; import React from 'react'; export interface INodeRenderer { canRender(node: BehaviorTreeNode): boolean; render(node: BehaviorTreeNode, context: NodeRenderContext): React.ReactElement; } export interface NodeRenderContext { isSelected: boolean; isExecuting: boolean; onNodeClick: (e: React.MouseEvent, node: BehaviorTreeNode) => void; onContextMenu: (e: React.MouseEvent, node: BehaviorTreeNode) => void; } export interface IPropertyEditor { canEdit(propertyType: string): boolean; render(property: PropertyEditorProps): React.ReactElement; } export type PropertyValue = string | number | boolean | object | null | undefined; export interface PropertyEditorProps { propertyName: string; propertyType: string; value: T; onChange: (value: T) => void; config?: Record; } export interface INodeProvider { getNodeTemplates(): NodeTemplate[]; getCategory(): string; getIcon(): string | LucideIcon; } export interface IToolbarButton { id: string; label: string; icon: LucideIcon; tooltip?: string; onClick: () => void; isVisible?: () => boolean; isEnabled?: () => boolean; } export interface IPanelProvider { id: string; title: string; icon?: LucideIcon; render(): React.ReactElement; canActivate?(): boolean; } export interface IValidator { name: string; validate(nodes: BehaviorTreeNode[]): ValidationResult[]; } export interface ValidationResult { severity: 'error' | 'warning' | 'info'; nodeId?: string; message: string; code?: string; } export interface ICommandProvider { getCommandId(): string; getCommandName(): string; getShortcut?(): string; canExecute?(): boolean; execute(context: CommandExecutionContext): void | Promise; } export interface CommandExecutionContext { selectedNodeIds: string[]; nodes: BehaviorTreeNode[]; currentFile?: string; } export class EditorExtensionRegistry { private nodeRenderers: Set = new Set(); private propertyEditors: Set = new Set(); private nodeProviders: Set = new Set(); private toolbarButtons: Set = new Set(); private panelProviders: Set = new Set(); private validators: Set = new Set(); private commandProviders: Set = new Set(); registerNodeRenderer(renderer: INodeRenderer): void { this.nodeRenderers.add(renderer); } unregisterNodeRenderer(renderer: INodeRenderer): void { this.nodeRenderers.delete(renderer); } getNodeRenderer(node: BehaviorTreeNode): INodeRenderer | undefined { for (const renderer of this.nodeRenderers) { if (renderer.canRender(node)) { return renderer; } } return undefined; } registerPropertyEditor(editor: IPropertyEditor): void { this.propertyEditors.add(editor); } unregisterPropertyEditor(editor: IPropertyEditor): void { this.propertyEditors.delete(editor); } getPropertyEditor(propertyType: string): IPropertyEditor | undefined { for (const editor of this.propertyEditors) { if (editor.canEdit(propertyType)) { return editor; } } return undefined; } registerNodeProvider(provider: INodeProvider): void { this.nodeProviders.add(provider); } unregisterNodeProvider(provider: INodeProvider): void { this.nodeProviders.delete(provider); } getAllNodeTemplates(): NodeTemplate[] { const templates: NodeTemplate[] = []; this.nodeProviders.forEach((provider) => { templates.push(...provider.getNodeTemplates()); }); return templates; } registerToolbarButton(button: IToolbarButton): void { this.toolbarButtons.add(button); } unregisterToolbarButton(button: IToolbarButton): void { this.toolbarButtons.delete(button); } getToolbarButtons(): IToolbarButton[] { return Array.from(this.toolbarButtons).filter((btn) => { return btn.isVisible ? btn.isVisible() : true; }); } registerPanelProvider(provider: IPanelProvider): void { this.panelProviders.add(provider); } unregisterPanelProvider(provider: IPanelProvider): void { this.panelProviders.delete(provider); } getPanelProviders(): IPanelProvider[] { return Array.from(this.panelProviders).filter((panel) => { return panel.canActivate ? panel.canActivate() : true; }); } registerValidator(validator: IValidator): void { this.validators.add(validator); } unregisterValidator(validator: IValidator): void { this.validators.delete(validator); } async validateTree(nodes: BehaviorTreeNode[]): Promise { const results: ValidationResult[] = []; for (const validator of this.validators) { try { const validationResults = validator.validate(nodes); results.push(...validationResults); } catch (error) { console.error(`Error in validator ${validator.name}:`, error); results.push({ severity: 'error', message: `Validator ${validator.name} failed: ${error}`, code: 'VALIDATOR_ERROR' }); } } return results; } registerCommandProvider(provider: ICommandProvider): void { this.commandProviders.add(provider); } unregisterCommandProvider(provider: ICommandProvider): void { this.commandProviders.delete(provider); } getCommandProvider(commandId: string): ICommandProvider | undefined { for (const provider of this.commandProviders) { if (provider.getCommandId() === commandId) { return provider; } } return undefined; } getAllCommandProviders(): ICommandProvider[] { return Array.from(this.commandProviders); } clear(): void { this.nodeRenderers.clear(); this.propertyEditors.clear(); this.nodeProviders.clear(); this.toolbarButtons.clear(); this.panelProviders.clear(); this.validators.clear(); this.commandProviders.clear(); } } let globalExtensionRegistry: EditorExtensionRegistry | null = null; export function getGlobalExtensionRegistry(): EditorExtensionRegistry { if (!globalExtensionRegistry) { globalExtensionRegistry = new EditorExtensionRegistry(); } return globalExtensionRegistry; } export function resetGlobalExtensionRegistry(): void { globalExtensionRegistry = null; }