/** * Tileset Panel - Display tileset for selection */ import React, { useEffect, useCallback } from 'react'; import { Core } from '@esengine/ecs-framework'; import { MessageHub } from '@esengine/editor-core'; import { TilemapComponent, type ITilesetData } from '../../../TilemapComponent'; import { useTilemapEditorStore } from '../../stores/TilemapEditorStore'; import { TilesetPreview } from '../TilesetPreview'; import '../../styles/TilemapEditor.css'; // Helper to convert file path to URL function convertFileSrc(path: string): string { if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('asset://')) { return path; } return `asset://localhost/${encodeURIComponent(path)}`; } interface TilesetPanelProps { projectPath?: string | null; } export const TilesetPanel: React.FC = () => { const { entityId, tilesetImageUrl, tilesetColumns, tilesetRows, tileWidth, tileHeight, selectedTiles, setTileset } = useTilemapEditorStore(); // Load tileset from component const loadTilesetFromComponent = useCallback(() => { if (!entityId) return; const scene = Core.scene; if (!scene) return; const foundEntity = scene.findEntityById(parseInt(entityId, 10)); if (!foundEntity) return; const tilemapComp = foundEntity.getComponent(TilemapComponent); if (!tilemapComp) return; // Get tileset source from first tileset const tilesetRef = tilemapComp.tilesets[0]; if (!tilesetRef) return; const tilesetPath = tilesetRef.source; const imageUrl = convertFileSrc(tilesetPath); const currentState = useTilemapEditorStore.getState(); // Check if URL or tile dimensions changed const urlChanged = imageUrl !== currentState.tilesetImageUrl; const dimensionsChanged = tilemapComp.tileWidth !== currentState.tileWidth || tilemapComp.tileHeight !== currentState.tileHeight; if (!urlChanged && !dimensionsChanged) return; const img = new Image(); img.onload = () => { const columns = Math.floor(img.width / tilemapComp.tileWidth); const rows = Math.floor(img.height / tilemapComp.tileHeight); // Create tileset data and set it const tilesetData: ITilesetData = { name: 'tileset', version: 1, image: tilesetPath, imageWidth: img.width, imageHeight: img.height, tileWidth: tilemapComp.tileWidth, tileHeight: tilemapComp.tileHeight, tileCount: columns * rows, columns, rows }; tilemapComp.setTilesetData(0, tilesetData); setTileset(imageUrl, columns, rows, tilemapComp.tileWidth, tilemapComp.tileHeight); }; img.src = imageUrl; }, [entityId, setTileset]); // Load tileset when entityId is set but tilesetImageUrl is not yet loaded useEffect(() => { if (!entityId || tilesetImageUrl) return; loadTilesetFromComponent(); }, [entityId, tilesetImageUrl, loadTilesetFromComponent]); // Listen for scene modifications to reload tileset when property changes useEffect(() => { if (!entityId) return; const messageHub = Core.services.resolve(MessageHub); if (!messageHub) return; const unsubscribe = messageHub.subscribe('scene:modified', () => { loadTilesetFromComponent(); }); return unsubscribe; }, [entityId, loadTilesetFromComponent]); if (!tilesetImageUrl) { return (

Tileset

No tileset loaded.
Select a TilemapComponent to edit.

); } return (

Tileset

{selectedTiles && (
Selected: {selectedTiles.width}×{selectedTiles.height} Tile: {selectedTiles.tiles[0]}
)}
); };