Refactor/clean architecture phase1 (#215)
* refactor(editor): 建立Clean Architecture领域模型层 * refactor(editor): 实现应用层架构 - 命令模式、用例和状态管理 * refactor(editor): 实现展示层核心Hooks * refactor(editor): 实现基础设施层和展示层组件 * refactor(editor): 迁移画布和连接渲染到 Clean Architecture 组件 * feat(editor): 集成应用层架构和命令模式,实现撤销/重做功能 * refactor(editor): UI组件拆分 * refactor(editor): 提取快速创建菜单逻辑 * refactor(editor): 重构BehaviorTreeEditor,提取组件和Hook * refactor(editor): 提取端口连接和键盘事件Hook * refactor(editor): 提取拖放处理Hook * refactor(editor): 提取画布交互Hook和工具函数 * refactor(editor): 完成核心重构 * fix(editor): 修复节点无法创建和连接 * refactor(behavior-tree,editor): 重构节点子节点约束系统,实现元数据驱动的架构
This commit is contained in:
@@ -12,7 +12,11 @@ import { NodeExecutorMetadata } from '../NodeMetadata';
|
||||
nodeType: NodeType.Decorator,
|
||||
displayName: '反转',
|
||||
description: '反转子节点的执行结果',
|
||||
category: 'Decorator'
|
||||
category: 'Decorator',
|
||||
childrenConstraints: {
|
||||
min: 1,
|
||||
max: 1
|
||||
}
|
||||
})
|
||||
export class InverterExecutor implements INodeExecutor {
|
||||
execute(context: NodeExecutionContext): TaskStatus {
|
||||
|
||||
@@ -26,6 +26,9 @@ import { NodeExecutorMetadata } from '../NodeMetadata';
|
||||
description: '失败策略',
|
||||
options: ['all', 'one']
|
||||
}
|
||||
},
|
||||
childrenConstraints: {
|
||||
min: 2
|
||||
}
|
||||
})
|
||||
export class ParallelExecutor implements INodeExecutor {
|
||||
|
||||
@@ -12,7 +12,10 @@ import { NodeExecutorMetadata } from '../NodeMetadata';
|
||||
nodeType: NodeType.Composite,
|
||||
displayName: '随机序列',
|
||||
description: '随机顺序执行子节点,全部成功才成功',
|
||||
category: 'Composite'
|
||||
category: 'Composite',
|
||||
childrenConstraints: {
|
||||
min: 1
|
||||
}
|
||||
})
|
||||
export class RandomSequenceExecutor implements INodeExecutor {
|
||||
execute(context: NodeExecutionContext): TaskStatus {
|
||||
|
||||
@@ -25,6 +25,10 @@ import { NodeExecutorMetadata } from '../NodeMetadata';
|
||||
default: false,
|
||||
description: '子节点失败时是否结束'
|
||||
}
|
||||
},
|
||||
childrenConstraints: {
|
||||
min: 1,
|
||||
max: 1
|
||||
}
|
||||
})
|
||||
export class RepeaterExecutor implements INodeExecutor {
|
||||
|
||||
@@ -12,7 +12,10 @@ import { NodeExecutorMetadata } from '../NodeMetadata';
|
||||
nodeType: NodeType.Composite,
|
||||
displayName: '选择器',
|
||||
description: '按顺序执行子节点,任一成功则成功',
|
||||
category: 'Composite'
|
||||
category: 'Composite',
|
||||
childrenConstraints: {
|
||||
min: 1
|
||||
}
|
||||
})
|
||||
export class SelectorExecutor implements INodeExecutor {
|
||||
execute(context: NodeExecutionContext): TaskStatus {
|
||||
|
||||
@@ -12,7 +12,10 @@ import { NodeExecutorMetadata } from '../NodeMetadata';
|
||||
nodeType: NodeType.Composite,
|
||||
displayName: '序列',
|
||||
description: '按顺序执行子节点,全部成功才成功',
|
||||
category: 'Composite'
|
||||
category: 'Composite',
|
||||
childrenConstraints: {
|
||||
min: 1
|
||||
}
|
||||
})
|
||||
export class SequenceExecutor implements INodeExecutor {
|
||||
execute(context: NodeExecutionContext): TaskStatus {
|
||||
|
||||
@@ -14,6 +14,15 @@ export interface ConfigFieldDefinition {
|
||||
allowMultipleConnections?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 子节点约束配置
|
||||
*/
|
||||
export interface ChildrenConstraints {
|
||||
min?: number;
|
||||
max?: number;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点元数据
|
||||
*/
|
||||
@@ -24,6 +33,26 @@ export interface NodeMetadata {
|
||||
description?: string;
|
||||
category?: string;
|
||||
configSchema?: Record<string, ConfigFieldDefinition>;
|
||||
childrenConstraints?: ChildrenConstraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点元数据默认值
|
||||
*/
|
||||
export class NodeMetadataDefaults {
|
||||
static getDefaultConstraints(nodeType: NodeType): ChildrenConstraints | undefined {
|
||||
switch (nodeType) {
|
||||
case NodeType.Composite:
|
||||
return { min: 1 };
|
||||
case NodeType.Decorator:
|
||||
return { min: 1, max: 1 };
|
||||
case NodeType.Action:
|
||||
case NodeType.Condition:
|
||||
return { max: 0 };
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NodeType } from '../Types/TaskStatus';
|
||||
import { NodeMetadataRegistry, ConfigFieldDefinition } from '../Runtime/NodeMetadata';
|
||||
import { NodeMetadataRegistry, ConfigFieldDefinition, NodeMetadata } from '../Runtime/NodeMetadata';
|
||||
|
||||
/**
|
||||
* 节点数据JSON格式
|
||||
@@ -48,7 +48,7 @@ export const PropertyType = {
|
||||
* type: 'curve-editor'
|
||||
* ```
|
||||
*/
|
||||
export type PropertyType = typeof PropertyType[keyof typeof PropertyType] | string;
|
||||
export type PropertyType = (typeof PropertyType)[keyof typeof PropertyType] | string;
|
||||
|
||||
/**
|
||||
* 属性定义(用于编辑器)
|
||||
@@ -114,7 +114,7 @@ export interface PropertyDefinition {
|
||||
/** 验证失败的提示信息 */
|
||||
message?: string;
|
||||
/** 自定义验证函数 */
|
||||
validator?: string; // 函数字符串,编辑器会解析
|
||||
validator?: string; // 函数字符串,编辑器会解析
|
||||
/** 最小长度(字符串) */
|
||||
minLength?: number;
|
||||
/** 最大长度(字符串) */
|
||||
@@ -141,6 +141,8 @@ export interface NodeTemplate {
|
||||
className?: string;
|
||||
componentClass?: Function;
|
||||
requiresChildren?: boolean;
|
||||
minChildren?: number;
|
||||
maxChildren?: number;
|
||||
defaultConfig: Partial<NodeDataJSON>;
|
||||
properties: PropertyDefinition[];
|
||||
}
|
||||
@@ -183,7 +185,7 @@ export class NodeTemplates {
|
||||
/**
|
||||
* 将NodeMetadata转换为NodeTemplate
|
||||
*/
|
||||
private static convertMetadataToTemplate(metadata: any): NodeTemplate {
|
||||
private static convertMetadataToTemplate(metadata: NodeMetadata): NodeTemplate {
|
||||
const properties = this.convertConfigSchemaToProperties(metadata.configSchema || {});
|
||||
|
||||
const defaultConfig: Partial<NodeDataJSON> = {
|
||||
@@ -217,7 +219,10 @@ export class NodeTemplates {
|
||||
// 根据节点类型生成默认颜色和图标
|
||||
const { icon, color } = this.getIconAndColorByType(metadata.nodeType, metadata.category || '');
|
||||
|
||||
return {
|
||||
// 应用子节点约束
|
||||
const constraints = metadata.childrenConstraints || this.getDefaultConstraintsByNodeType(metadata.nodeType);
|
||||
|
||||
const template: NodeTemplate = {
|
||||
type: metadata.nodeType,
|
||||
displayName: metadata.displayName,
|
||||
category: metadata.category || this.getCategoryByNodeType(metadata.nodeType),
|
||||
@@ -228,6 +233,35 @@ export class NodeTemplates {
|
||||
defaultConfig,
|
||||
properties
|
||||
};
|
||||
|
||||
if (constraints) {
|
||||
if (constraints.min !== undefined) {
|
||||
template.minChildren = constraints.min;
|
||||
template.requiresChildren = constraints.min > 0;
|
||||
}
|
||||
if (constraints.max !== undefined) {
|
||||
template.maxChildren = constraints.max;
|
||||
}
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点类型的默认约束
|
||||
*/
|
||||
private static getDefaultConstraintsByNodeType(nodeType: NodeType): { min?: number; max?: number } | undefined {
|
||||
switch (nodeType) {
|
||||
case NodeType.Composite:
|
||||
return { min: 1 };
|
||||
case NodeType.Decorator:
|
||||
return { min: 1, max: 1 };
|
||||
case NodeType.Action:
|
||||
case NodeType.Condition:
|
||||
return { max: 0 };
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user