diff --git a/.changeset/add-behavior-tree-plugin.md b/.changeset/add-behavior-tree-plugin.md new file mode 100644 index 00000000..20f92bda --- /dev/null +++ b/.changeset/add-behavior-tree-plugin.md @@ -0,0 +1,24 @@ +--- +"@esengine/behavior-tree": minor +--- + +feat(behavior-tree): add pure BehaviorTreePlugin class for Cocos/Laya integration + +- Added `BehaviorTreePlugin` class that only depends on `@esengine/ecs-framework` +- Implements `IPlugin` interface with `install()`, `uninstall()`, and `setupScene()` methods +- Removed `esengine/` subdirectory that incorrectly depended on `@esengine/engine-core` +- Updated package documentation with correct usage examples + +Usage: +```typescript +import { Core, Scene } from '@esengine/ecs-framework'; +import { BehaviorTreePlugin, BehaviorTreeBuilder, BehaviorTreeStarter } from '@esengine/behavior-tree'; + +Core.create(); +const plugin = new BehaviorTreePlugin(); +await Core.installPlugin(plugin); + +const scene = new Scene(); +plugin.setupScene(scene); +Core.setScene(scene); +``` diff --git a/packages/framework/behavior-tree/src/BehaviorTreePlugin.ts b/packages/framework/behavior-tree/src/BehaviorTreePlugin.ts new file mode 100644 index 00000000..dc5c6450 --- /dev/null +++ b/packages/framework/behavior-tree/src/BehaviorTreePlugin.ts @@ -0,0 +1,118 @@ +import type { Core, ServiceContainer, IPlugin, IScene } from '@esengine/ecs-framework'; +import { BehaviorTreeExecutionSystem } from './execution/BehaviorTreeExecutionSystem'; +import { BehaviorTreeAssetManager } from './execution/BehaviorTreeAssetManager'; +import { GlobalBlackboardService } from './Services/GlobalBlackboardService'; + +/** + * @zh 行为树插件 + * @en Behavior Tree Plugin + * + * @zh 为 ECS 框架提供行为树支持的插件。 + * 可与任何基于 @esengine/ecs-framework 的引擎集成(Cocos、Laya、Node.js 等)。 + * + * @en Plugin that provides behavior tree support for ECS framework. + * Can be integrated with any engine based on @esengine/ecs-framework (Cocos, Laya, Node.js, etc.). + * + * @example + * ```typescript + * import { Core, Scene } from '@esengine/ecs-framework'; + * import { BehaviorTreePlugin, BehaviorTreeBuilder, BehaviorTreeStarter } from '@esengine/behavior-tree'; + * + * // Initialize + * Core.create(); + * const plugin = new BehaviorTreePlugin(); + * await Core.installPlugin(plugin); + * + * // Setup scene + * const scene = new Scene(); + * plugin.setupScene(scene); + * Core.setScene(scene); + * + * // Create and start behavior tree + * const tree = BehaviorTreeBuilder.create('MyAI') + * .selector('Root') + * .log('Hello from behavior tree!') + * .end() + * .build(); + * + * const entity = scene.createEntity('AIEntity'); + * BehaviorTreeStarter.start(entity, tree); + * ``` + */ +export class BehaviorTreePlugin implements IPlugin { + /** + * @zh 插件名称 + * @en Plugin name + */ + readonly name = '@esengine/behavior-tree'; + + /** + * @zh 插件版本 + * @en Plugin version + */ + readonly version = '1.0.0'; + + /** + * @zh 插件依赖 + * @en Plugin dependencies + */ + readonly dependencies: readonly string[] = []; + + private _services: ServiceContainer | null = null; + + /** + * @zh 安装插件 + * @en Install plugin + * + * @param _core - Core 实例 + * @param services - 服务容器 + */ + install(_core: Core, services: ServiceContainer): void { + this._services = services; + + // Register services + if (!services.isRegistered(GlobalBlackboardService)) { + services.registerSingleton(GlobalBlackboardService); + } + if (!services.isRegistered(BehaviorTreeAssetManager)) { + services.registerSingleton(BehaviorTreeAssetManager); + } + } + + /** + * @zh 卸载插件 + * @en Uninstall plugin + */ + uninstall(): void { + if (this._services) { + const assetManager = this._services.tryResolve(BehaviorTreeAssetManager); + if (assetManager) { + assetManager.dispose(); + } + + const blackboardService = this._services.tryResolve(GlobalBlackboardService); + if (blackboardService) { + blackboardService.dispose(); + } + } + this._services = null; + } + + /** + * @zh 设置场景,添加行为树执行系统 + * @en Setup scene, add behavior tree execution system + * + * @param scene - 要设置的场景 + * + * @example + * ```typescript + * const scene = new Scene(); + * plugin.setupScene(scene); + * Core.setScene(scene); + * ``` + */ + setupScene(scene: IScene): void { + const system = new BehaviorTreeExecutionSystem(this._services ?? undefined); + scene.addSystem(system); + } +} diff --git a/packages/framework/behavior-tree/src/esengine/BehaviorTreeLoader.ts b/packages/framework/behavior-tree/src/esengine/BehaviorTreeLoader.ts deleted file mode 100644 index 3950031e..00000000 --- a/packages/framework/behavior-tree/src/esengine/BehaviorTreeLoader.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @zh ESEngine 资产加载器 - * @en ESEngine asset loader - * - * @zh 实现 IAssetLoader 接口,用于通过 AssetManager 加载行为树文件。 - * 此文件仅在使用 ESEngine 时需要。 - * - * @en Implements IAssetLoader interface for loading behavior tree files via AssetManager. - * This file is only needed when using ESEngine. - */ - -import type { - IAssetLoader, - IAssetParseContext, - IAssetContent, - AssetContentType -} from '@esengine/asset-system'; -import { Core } from '@esengine/ecs-framework'; -import { BehaviorTreeData } from '../execution/BehaviorTreeData'; -import { BehaviorTreeAssetManager } from '../execution/BehaviorTreeAssetManager'; -import { EditorToBehaviorTreeDataConverter } from '../Serialization/EditorToBehaviorTreeDataConverter'; -import { BehaviorTreeAssetType } from '../constants'; - -/** - * @zh 行为树资产接口 - * @en Behavior tree asset interface - */ -export interface IBehaviorTreeAsset { - /** @zh 行为树数据 @en Behavior tree data */ - data: BehaviorTreeData; - /** @zh 文件路径 @en File path */ - path: string; -} - -/** - * @zh 行为树加载器 - * @en Behavior tree loader implementing IAssetLoader interface - */ -export class BehaviorTreeLoader implements IAssetLoader { - readonly supportedType = BehaviorTreeAssetType; - readonly supportedExtensions = ['.btree']; - readonly contentType: AssetContentType = 'text'; - - /** - * @zh 从内容解析行为树资产 - * @en Parse behavior tree asset from content - */ - async parse(content: IAssetContent, context: IAssetParseContext): Promise { - if (!content.text) { - throw new Error('Behavior tree content is empty'); - } - - // Convert to runtime data - const treeData = EditorToBehaviorTreeDataConverter.fromEditorJSON(content.text); - - // Use file path as ID - const assetPath = context.metadata.path; - treeData.id = assetPath; - - // Also register to BehaviorTreeAssetManager for legacy code - const btAssetManager = Core.services.tryResolve(BehaviorTreeAssetManager); - if (btAssetManager) { - btAssetManager.loadAsset(treeData); - } - - return { - data: treeData, - path: assetPath - }; - } - - /** - * @zh 释放资产 - * @en Dispose asset - */ - dispose(asset: IBehaviorTreeAsset): void { - const btAssetManager = Core.services.tryResolve(BehaviorTreeAssetManager); - if (btAssetManager && asset.data) { - btAssetManager.unloadAsset(asset.data.id); - } - } -} diff --git a/packages/framework/behavior-tree/src/esengine/BehaviorTreeRuntimeModule.ts b/packages/framework/behavior-tree/src/esengine/BehaviorTreeRuntimeModule.ts deleted file mode 100644 index 5a08dbcb..00000000 --- a/packages/framework/behavior-tree/src/esengine/BehaviorTreeRuntimeModule.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @zh ESEngine 集成模块 - * @en ESEngine integration module - * - * @zh 此文件包含与 ESEngine 引擎核心集成的代码。 - * 使用 Cocos/Laya 等其他引擎时不需要此文件。 - * - * @en This file contains code for integrating with ESEngine engine-core. - * Not needed when using other engines like Cocos/Laya. - */ - -import type { IScene, ServiceContainer, IComponentRegistry } from '@esengine/ecs-framework'; -import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core'; -import { AssetManagerToken } from '@esengine/asset-system'; - -import { BehaviorTreeRuntimeComponent } from '../execution/BehaviorTreeRuntimeComponent'; -import { BehaviorTreeExecutionSystem } from '../execution/BehaviorTreeExecutionSystem'; -import { BehaviorTreeAssetManager } from '../execution/BehaviorTreeAssetManager'; -import { GlobalBlackboardService } from '../Services/GlobalBlackboardService'; -import { BehaviorTreeLoader } from './BehaviorTreeLoader'; -import { BehaviorTreeAssetType } from '../constants'; -import { BehaviorTreeSystemToken } from '../tokens'; - -// Re-export tokens for ESEngine users -export { BehaviorTreeSystemToken } from '../tokens'; - -class BehaviorTreeRuntimeModule implements IRuntimeModule { - private _loaderRegistered = false; - - registerComponents(registry: IComponentRegistry): void { - registry.register(BehaviorTreeRuntimeComponent); - } - - registerServices(services: ServiceContainer): void { - if (!services.isRegistered(GlobalBlackboardService)) { - services.registerSingleton(GlobalBlackboardService); - } - if (!services.isRegistered(BehaviorTreeAssetManager)) { - services.registerSingleton(BehaviorTreeAssetManager); - } - } - - createSystems(scene: IScene, context: SystemContext): void { - // Get dependencies from service registry - const assetManager = context.services.get(AssetManagerToken); - - if (!this._loaderRegistered && assetManager) { - assetManager.registerLoader(BehaviorTreeAssetType, new BehaviorTreeLoader()); - this._loaderRegistered = true; - } - - // Use ECS service container from context.services - const ecsServices = (context as { ecsServices?: ServiceContainer }).ecsServices; - const behaviorTreeSystem = new BehaviorTreeExecutionSystem(ecsServices); - - if (assetManager) { - behaviorTreeSystem.setAssetManager(assetManager); - } - - if (context.isEditor) { - behaviorTreeSystem.enabled = false; - } - - scene.addSystem(behaviorTreeSystem); - - // Register service to service registry - context.services.register(BehaviorTreeSystemToken, behaviorTreeSystem); - } -} - -const manifest: ModuleManifest = { - id: 'behavior-tree', - name: '@esengine/behavior-tree', - displayName: 'Behavior Tree', - version: '1.0.0', - description: 'AI behavior tree system', - category: 'AI', - icon: 'GitBranch', - isCore: false, - defaultEnabled: false, - isEngineModule: true, - canContainContent: true, - dependencies: ['core'], - exports: { components: ['BehaviorTreeComponent'] }, - editorPackage: '@esengine/behavior-tree-editor' -}; - -export const BehaviorTreePlugin: IRuntimePlugin = { - manifest, - runtimeModule: new BehaviorTreeRuntimeModule() -}; - -export { BehaviorTreeRuntimeModule }; diff --git a/packages/framework/behavior-tree/src/esengine/index.ts b/packages/framework/behavior-tree/src/esengine/index.ts deleted file mode 100644 index a3e7b333..00000000 --- a/packages/framework/behavior-tree/src/esengine/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @zh ESEngine 集成入口 - * @en ESEngine integration entry point - * - * @zh 此模块包含与 ESEngine 引擎核心集成所需的所有代码。 - * 使用 Cocos/Laya 等其他引擎时,只需导入主模块即可。 - * - * @en This module contains all code required for ESEngine engine-core integration. - * When using other engines like Cocos/Laya, just import the main module. - * - * @example ESEngine 使用方式 / ESEngine usage: - * ```typescript - * import { BehaviorTreePlugin } from '@esengine/behavior-tree/esengine'; - * - * // Register with ESEngine plugin system - * engine.registerPlugin(BehaviorTreePlugin); - * ``` - * - * @example Cocos/Laya 使用方式 / Cocos/Laya usage: - * ```typescript - * import { - * BehaviorTreeAssetManager, - * BehaviorTreeExecutionSystem - * } from '@esengine/behavior-tree'; - * - * // Load behavior tree from JSON - * const assetManager = new BehaviorTreeAssetManager(); - * assetManager.loadFromEditorJSON(jsonContent); - * - * // Add system to your ECS world - * world.addSystem(new BehaviorTreeExecutionSystem()); - * ``` - */ - -// Runtime module and plugin -export { BehaviorTreeRuntimeModule, BehaviorTreePlugin, BehaviorTreeSystemToken } from './BehaviorTreeRuntimeModule'; - -// Asset loader for ESEngine asset-system -export { BehaviorTreeLoader, type IBehaviorTreeAsset } from './BehaviorTreeLoader'; diff --git a/packages/framework/behavior-tree/src/index.ts b/packages/framework/behavior-tree/src/index.ts index b64ed331..ac442c9f 100644 --- a/packages/framework/behavior-tree/src/index.ts +++ b/packages/framework/behavior-tree/src/index.ts @@ -4,32 +4,44 @@ * @zh AI 行为树系统,支持运行时执行和可视化编辑 * @en AI Behavior Tree System with runtime execution and visual editor support * - * @zh 此包是通用的行为树实现,可以与任何 ECS 框架配合使用。 - * 对于 ESEngine 集成,请从 '@esengine/behavior-tree/esengine' 导入插件。 + * @zh 此包是通用的行为树实现,可以与任何基于 @esengine/ecs-framework 的引擎集成 + * (Cocos Creator、LayaAir、Node.js 等)。 * - * @en This package is a generic behavior tree implementation that works with any ECS framework. - * For ESEngine integration, import the plugin from '@esengine/behavior-tree/esengine'. + * @en This package is a generic behavior tree implementation that works with any engine + * based on @esengine/ecs-framework (Cocos Creator, LayaAir, Node.js, etc.). * - * @example Cocos/Laya/通用 ECS 使用方式: + * @example * ```typescript + * import { Core, Scene } from '@esengine/ecs-framework'; * import { - * BehaviorTreeAssetManager, - * BehaviorTreeExecutionSystem, - * BehaviorTreeRuntimeComponent + * BehaviorTreePlugin, + * BehaviorTreeBuilder, + * BehaviorTreeStarter * } from '@esengine/behavior-tree'; * - * // 1. Register service - * Core.services.registerSingleton(BehaviorTreeAssetManager); + * // 1. Initialize Core and install plugin + * Core.create(); + * const plugin = new BehaviorTreePlugin(); + * await Core.installPlugin(plugin); * - * // 2. Load behavior tree from JSON - * const assetManager = Core.services.resolve(BehaviorTreeAssetManager); - * assetManager.loadFromEditorJSON(jsonContent); + * // 2. Create scene and setup behavior tree system + * const scene = new Scene(); + * plugin.setupScene(scene); + * Core.setScene(scene); * - * // 3. Add component to entity - * entity.addComponent(new BehaviorTreeRuntimeComponent()); + * // 3. Build behavior tree + * const tree = BehaviorTreeBuilder.create('MyAI') + * .selector('Root') + * .log('Hello!') + * .end() + * .build(); * - * // 4. Add system to scene - * scene.addSystem(new BehaviorTreeExecutionSystem()); + * // 4. Start behavior tree on entity + * const entity = scene.createEntity('AIEntity'); + * BehaviorTreeStarter.start(entity, tree); + * + * // 5. Run game loop + * setInterval(() => Core.update(0.016), 16); * ``` * * @packageDocumentation @@ -65,3 +77,6 @@ export { BlackboardTypes } from './Blackboard/BlackboardTypes'; // Service tokens (using ecs-framework's createServiceToken, not engine-core) export { BehaviorTreeSystemToken } from './tokens'; + +// Plugin +export { BehaviorTreePlugin } from './BehaviorTreePlugin';