import { useState, useEffect } from 'react'; import { Entity } from '@esengine/ecs-framework'; import { EntityStoreService, MessageHub } from '@esengine/editor-core'; import { useLocale } from '../hooks/useLocale'; import { Box, Layers, Wifi } from 'lucide-react'; import { ProfilerService, RemoteEntity } from '../services/ProfilerService'; import '../styles/SceneHierarchy.css'; interface SceneHierarchyProps { entityStore: EntityStoreService; messageHub: MessageHub; } export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps) { const [entities, setEntities] = useState([]); const [remoteEntities, setRemoteEntities] = useState([]); const [isRemoteConnected, setIsRemoteConnected] = useState(false); const [selectedId, setSelectedId] = useState(null); const { t } = useLocale(); // Subscribe to local entity changes useEffect(() => { const updateEntities = () => { setEntities(entityStore.getRootEntities()); }; const handleSelection = (data: { entity: Entity | null }) => { setSelectedId(data.entity?.id ?? null); }; updateEntities(); const unsubAdd = messageHub.subscribe('entity:added', updateEntities); const unsubRemove = messageHub.subscribe('entity:removed', updateEntities); const unsubClear = messageHub.subscribe('entities:cleared', updateEntities); const unsubSelect = messageHub.subscribe('entity:selected', handleSelection); return () => { unsubAdd(); unsubRemove(); unsubClear(); unsubSelect(); }; }, [entityStore, messageHub]); // Subscribe to remote entity data from ProfilerService useEffect(() => { const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined; if (!profilerService) { return; } const unsubscribe = profilerService.subscribe((data) => { const connected = profilerService.isConnected(); setIsRemoteConnected(connected); if (connected && data.entities && data.entities.length > 0) { setRemoteEntities(data.entities); } else { setRemoteEntities([]); } }); return () => unsubscribe(); }, []); const handleEntityClick = (entity: Entity) => { entityStore.selectEntity(entity); }; const handleRemoteEntityClick = (entity: RemoteEntity) => { setSelectedId(entity.id); // 请求完整的实体详情(包含组件属性) const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined; if (profilerService) { profilerService.requestEntityDetails(entity.id); } // 先发布基本信息,详细信息稍后通过 ProfilerService 异步返回 messageHub.publish('remote-entity:selected', { entity: { id: entity.id, name: entity.name, enabled: entity.enabled, componentCount: entity.componentCount, componentTypes: entity.componentTypes } }); }; // Determine which entities to display const displayEntities = isRemoteConnected ? remoteEntities : entities; const showRemoteIndicator = isRemoteConnected && remoteEntities.length > 0; return (

{t('hierarchy.title')}

{showRemoteIndicator && (
)}
{displayEntities.length === 0 ? (
{t('hierarchy.empty')}
{isRemoteConnected ? 'No entities in remote game' : 'Create an entity to get started'}
) : isRemoteConnected ? (
    {remoteEntities.map(entity => (
  • handleRemoteEntityClick(entity)} > {entity.name} {entity.componentCount > 0 && ( {entity.componentCount} )}
  • ))}
) : (
    {entities.map(entity => (
  • handleEntityClick(entity)} > Entity {entity.id}
  • ))}
)}
); }