2025-11-27 20:42:46 +08:00
|
|
|
/**
|
|
|
|
|
* Scene Inspector Plugin
|
|
|
|
|
* 场景检视器插件
|
|
|
|
|
*/
|
|
|
|
|
|
2025-12-08 21:23:37 +08:00
|
|
|
import { Core, Entity } from '@esengine/esengine';
|
|
|
|
|
import type { ServiceContainer } from '@esengine/esengine';
|
2025-11-27 20:42:46 +08:00
|
|
|
import type {
|
2025-12-01 22:28:51 +08:00
|
|
|
IPlugin,
|
2025-11-27 20:42:46 +08:00
|
|
|
IEditorModuleLoader,
|
2025-12-03 22:15:22 +08:00
|
|
|
ModuleManifest,
|
2025-11-27 20:42:46 +08:00
|
|
|
PanelDescriptor,
|
|
|
|
|
MenuItemDescriptor,
|
|
|
|
|
ToolbarItemDescriptor,
|
|
|
|
|
EntityCreationTemplate
|
|
|
|
|
} from '@esengine/editor-core';
|
|
|
|
|
import { PanelPosition, EntityStoreService, MessageHub } from '@esengine/editor-core';
|
2025-12-01 22:28:51 +08:00
|
|
|
import { TransformComponent } from '@esengine/engine-core';
|
|
|
|
|
import { SpriteComponent, SpriteAnimatorComponent } from '@esengine/sprite';
|
|
|
|
|
import { CameraComponent } from '@esengine/camera';
|
2025-11-27 20:42:46 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Scene Inspector 编辑器模块
|
|
|
|
|
*/
|
|
|
|
|
class SceneInspectorEditorModule implements IEditorModuleLoader {
|
|
|
|
|
async install(_services: ServiceContainer): Promise<void> {
|
|
|
|
|
// Installed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async uninstall(): Promise<void> {
|
|
|
|
|
// Uninstalled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getPanels(): PanelDescriptor[] {
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
id: 'panel-scene-hierarchy',
|
|
|
|
|
title: 'Scene Hierarchy',
|
|
|
|
|
position: PanelPosition.Left,
|
|
|
|
|
defaultSize: 250,
|
|
|
|
|
resizable: true,
|
|
|
|
|
closable: false,
|
|
|
|
|
icon: 'List',
|
|
|
|
|
order: 10
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'panel-entity-inspector',
|
|
|
|
|
title: 'Entity Inspector',
|
|
|
|
|
position: PanelPosition.Right,
|
|
|
|
|
defaultSize: 300,
|
|
|
|
|
resizable: true,
|
|
|
|
|
closable: false,
|
|
|
|
|
icon: 'Search',
|
|
|
|
|
order: 10
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getMenuItems(): MenuItemDescriptor[] {
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
id: 'view-scene-inspector',
|
|
|
|
|
label: 'Scene Inspector',
|
|
|
|
|
parentId: 'view',
|
|
|
|
|
shortcut: 'Ctrl+Shift+I'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'scene-create-entity',
|
|
|
|
|
label: 'Create Entity',
|
|
|
|
|
parentId: 'scene',
|
|
|
|
|
shortcut: 'Ctrl+N'
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getToolbarItems(): ToolbarItemDescriptor[] {
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
id: 'toolbar-create-entity',
|
|
|
|
|
label: 'New Entity',
|
|
|
|
|
icon: 'Plus',
|
|
|
|
|
tooltip: 'Create new entity',
|
|
|
|
|
execute: () => {}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'toolbar-delete-entity',
|
|
|
|
|
label: 'Delete Entity',
|
|
|
|
|
icon: 'Trash2',
|
|
|
|
|
tooltip: 'Delete selected entity',
|
|
|
|
|
execute: () => {}
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getEntityCreationTemplates(): EntityCreationTemplate[] {
|
|
|
|
|
return [
|
|
|
|
|
// Sprite
|
|
|
|
|
{
|
|
|
|
|
id: 'create-sprite-entity',
|
|
|
|
|
label: 'Sprite',
|
|
|
|
|
icon: 'Image',
|
|
|
|
|
category: 'rendering',
|
|
|
|
|
order: 10,
|
|
|
|
|
create: (): number => {
|
|
|
|
|
return this.createEntity('Sprite', (entity) => {
|
|
|
|
|
entity.addComponent(new TransformComponent());
|
|
|
|
|
entity.addComponent(new SpriteComponent());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// Animated Sprite
|
|
|
|
|
{
|
|
|
|
|
id: 'create-animated-sprite-entity',
|
|
|
|
|
label: '动画 Sprite',
|
|
|
|
|
icon: 'Film',
|
|
|
|
|
category: 'rendering',
|
|
|
|
|
order: 11,
|
|
|
|
|
create: (): number => {
|
|
|
|
|
return this.createEntity('AnimatedSprite', (entity) => {
|
|
|
|
|
entity.addComponent(new TransformComponent());
|
|
|
|
|
entity.addComponent(new SpriteAnimatorComponent());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// Camera
|
|
|
|
|
{
|
|
|
|
|
id: 'create-camera-entity',
|
|
|
|
|
label: '相机',
|
|
|
|
|
icon: 'Camera',
|
|
|
|
|
category: 'rendering',
|
|
|
|
|
order: 12,
|
|
|
|
|
create: (): number => {
|
|
|
|
|
return this.createEntity('Camera', (entity) => {
|
|
|
|
|
entity.addComponent(new TransformComponent());
|
|
|
|
|
entity.addComponent(new CameraComponent());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private createEntity(baseName: string, setupFn: (entity: Entity) => void): number {
|
|
|
|
|
const scene = Core.scene;
|
|
|
|
|
if (!scene) {
|
|
|
|
|
throw new Error('Scene not available');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const entityStore = Core.services.resolve(EntityStoreService);
|
|
|
|
|
const messageHub = Core.services.resolve(MessageHub);
|
|
|
|
|
|
|
|
|
|
if (!entityStore || !messageHub) {
|
|
|
|
|
throw new Error('EntityStoreService or MessageHub not available');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计数已有同类实体
|
|
|
|
|
const count = entityStore.getAllEntities()
|
|
|
|
|
.filter((e: Entity) => e.name.startsWith(`${baseName} `)).length;
|
|
|
|
|
const entityName = `${baseName} ${count + 1}`;
|
|
|
|
|
|
|
|
|
|
const entity = scene.createEntity(entityName);
|
|
|
|
|
setupFn(entity);
|
|
|
|
|
|
|
|
|
|
entityStore.addEntity(entity);
|
|
|
|
|
messageHub.publish('entity:added', { entity });
|
|
|
|
|
messageHub.publish('scene:modified', {});
|
|
|
|
|
entityStore.selectEntity(entity);
|
|
|
|
|
|
|
|
|
|
return entity.id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async onEditorReady(): Promise<void> {}
|
|
|
|
|
async onProjectOpen(_projectPath: string): Promise<void> {}
|
|
|
|
|
async onProjectClose(): Promise<void> {}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-03 22:15:22 +08:00
|
|
|
const manifest: ModuleManifest = {
|
2025-11-27 20:42:46 +08:00
|
|
|
id: '@esengine/scene-inspector',
|
2025-12-03 22:15:22 +08:00
|
|
|
name: '@esengine/scene-inspector',
|
|
|
|
|
displayName: 'Scene Inspector',
|
2025-11-27 20:42:46 +08:00
|
|
|
version: '1.0.0',
|
|
|
|
|
description: 'Scene hierarchy and entity inspector',
|
2025-12-03 22:15:22 +08:00
|
|
|
category: 'Other',
|
2025-11-27 20:42:46 +08:00
|
|
|
icon: 'Search',
|
|
|
|
|
isCore: true,
|
2025-12-03 22:15:22 +08:00
|
|
|
defaultEnabled: true,
|
|
|
|
|
isEngineModule: true,
|
|
|
|
|
canContainContent: false,
|
|
|
|
|
dependencies: ['engine-core'],
|
|
|
|
|
exports: {
|
|
|
|
|
other: ['SceneHierarchy', 'EntityInspector']
|
|
|
|
|
}
|
2025-11-27 20:42:46 +08:00
|
|
|
};
|
|
|
|
|
|
2025-12-01 22:28:51 +08:00
|
|
|
export const SceneInspectorPlugin: IPlugin = {
|
2025-12-03 22:15:22 +08:00
|
|
|
manifest,
|
2025-11-27 20:42:46 +08:00
|
|
|
editorModule: new SceneInspectorEditorModule()
|
|
|
|
|
};
|