feat: 实现可扩展的字段编辑器系统与专业资产选择器 (#227)

This commit is contained in:
YHH
2025-11-19 14:54:03 +08:00
committed by GitHub
parent caed5428d5
commit ecfef727c8
18 changed files with 1330 additions and 11 deletions

View File

@@ -7,7 +7,8 @@ import { BehaviorTreeEditor } from '../BehaviorTreeEditor';
import { BehaviorTreeService } from '../../services/BehaviorTreeService';
import { showToast } from '../../services/NotificationService';
import { FolderOpen } from 'lucide-react';
import type { Node as BehaviorTreeNode } from '../../domain/models/Node';
import { Node as BehaviorTreeNode } from '../../domain/models/Node';
import { BehaviorTree } from '../../domain/models/BehaviorTree';
import './BehaviorTreeEditorPanel.css';
const logger = createLogger('BehaviorTreeEditorPanel');
@@ -69,7 +70,9 @@ export const BehaviorTreeEditorPanel: React.FC<BehaviorTreeEditorPanelProps> = (
useEffect(() => {
try {
const messageHub = Core.services.resolve(MessageHub);
const unsubscribe = messageHub.subscribe('behavior-tree:file-opened', (data: { filePath: string; fileName: string }) => {
// 订阅文件打开事件
const unsubscribeFileOpened = messageHub.subscribe('behavior-tree:file-opened', (data: { filePath: string; fileName: string }) => {
setCurrentFilePath(data.filePath);
setCurrentFileName(data.fileName);
const loadedTree = useBehaviorTreeDataStore.getState().tree;
@@ -77,11 +80,51 @@ export const BehaviorTreeEditorPanel: React.FC<BehaviorTreeEditorPanelProps> = (
setHasUnsavedChanges(false);
});
// 订阅节点属性更改事件
const unsubscribePropertyChanged = messageHub.subscribe('behavior-tree:node-property-changed',
(data: { nodeId: string; propertyName: string; value: any }) => {
const state = useBehaviorTreeDataStore.getState();
const node = state.getNode(data.nodeId);
if (node) {
const newData = { ...node.data, [data.propertyName]: data.value };
// 更新节点数据
const updatedNode = new BehaviorTreeNode(
node.id,
node.template,
newData,
node.position,
Array.from(node.children)
);
// 更新树
const nodes = state.getNodes().map(n =>
n.id === data.nodeId ? updatedNode : n
);
const newTree = new BehaviorTree(
nodes,
state.getConnections(),
state.getBlackboard(),
state.getRootNodeId()
);
state.setTree(newTree);
setHasUnsavedChanges(true);
// 强制刷新画布
state.triggerForceUpdate();
}
}
);
return () => {
unsubscribe();
unsubscribeFileOpened();
unsubscribePropertyChanged();
};
} catch (error) {
logger.error('Failed to subscribe to file-opened event:', error);
logger.error('Failed to subscribe to events:', error);
}
}, []);

View File

@@ -1,5 +1,6 @@
import React, { useState, useCallback } from 'react';
import { IInspectorProvider, InspectorContext, MessageHub } from '@esengine/editor-core';
import { IInspectorProvider, InspectorContext, MessageHub, FieldEditorRegistry, FieldEditorContext } from '@esengine/editor-core';
import { Core } from '@esengine/ecs-framework';
import { Node as BehaviorTreeNode } from '../domain/models/Node';
import { PropertyDefinition } from '@esengine/behavior-tree';
@@ -18,6 +19,49 @@ const PropertyEditor: React.FC<PropertyEditorProps> = ({ property, value, onChan
}, [property.name, onChange]);
const renderInput = () => {
// 特殊处理 treeAssetId 字段使用 asset 编辑器
if (property.name === 'treeAssetId') {
const fieldRegistry = Core.services.resolve(FieldEditorRegistry);
const assetEditor = fieldRegistry.getEditor('asset');
if (assetEditor) {
const context: FieldEditorContext = {
readonly: false,
metadata: {
fileExtension: '.btree',
placeholder: '拖拽或选择行为树文件'
}
};
return assetEditor.render({
label: '',
value: value ?? property.defaultValue ?? null,
onChange: handleChange,
context
});
}
}
// 检查是否有特定的字段编辑器类型
if (property.fieldEditor) {
const fieldRegistry = Core.services.resolve(FieldEditorRegistry);
const editor = fieldRegistry.getEditor(property.fieldEditor.type);
if (editor) {
const context: FieldEditorContext = {
readonly: false,
metadata: property.fieldEditor.options
};
return editor.render({
label: '',
value: value ?? property.defaultValue,
onChange: handleChange,
context
});
}
}
switch (property.type) {
case 'number':
return (