* feat(engine): 添加编辑器模式标志控制编辑器UI显示 - 在 Rust 引擎中添加 isEditor 标志,控制网格、gizmos、坐标轴指示器的显示 - 运行时模式下自动隐藏所有编辑器专用 UI - 编辑器预览和浏览器运行时通过 setEditorMode(false) 禁用编辑器 UI - 添加 Scene.isEditorMode 延迟组件生命周期回调,直到 begin() 调用 - 修复用户组件注册到 Core ComponentRegistry 以支持序列化 - 修复 Run in Browser 时用户组件加载问题 * fix: 复制引擎模块的类型定义文件到 dist/engine * fix: 修复用户项目 tsconfig paths 类型定义路径 - 从 module.json 读取实际包名而不是使用目录名 - 修复 .d.ts 文件复制逻辑,支持 .mjs 扩展名
240 lines
6.4 KiB
TypeScript
240 lines
6.4 KiB
TypeScript
/**
|
||
* Browser Runtime
|
||
* 浏览器运行时
|
||
*
|
||
* Lightweight runtime for web game builds.
|
||
* Uses dynamic plugin loading via import maps.
|
||
*
|
||
* 轻量级 Web 游戏运行时。
|
||
* 通过 import maps 动态加载插件。
|
||
*/
|
||
|
||
import { Core } from '@esengine/ecs-framework';
|
||
import {
|
||
GameRuntime,
|
||
createGameRuntime,
|
||
BrowserPlatformAdapter,
|
||
runtimePluginManager,
|
||
BrowserFileSystemService,
|
||
type IPlugin
|
||
} from '@esengine/runtime-core';
|
||
import type { IAssetManager } from '@esengine/asset-system';
|
||
import { BrowserAssetReader } from './BrowserAssetReader';
|
||
|
||
/**
|
||
* Runtime configuration
|
||
* 运行时配置
|
||
*/
|
||
export interface RuntimeConfig {
|
||
/** Canvas element ID */
|
||
canvasId: string;
|
||
/** Canvas width (defaults to window.innerWidth) */
|
||
width?: number;
|
||
/** Canvas height (defaults to window.innerHeight) */
|
||
height?: number;
|
||
/** Asset catalog file URL (defaults to '/asset-catalog.json') */
|
||
assetCatalogUrl?: string;
|
||
/** Asset base URL (defaults to '/assets') */
|
||
assetBaseUrl?: string;
|
||
}
|
||
|
||
/**
|
||
* Browser Runtime
|
||
* 浏览器运行时
|
||
*
|
||
* Main entry point for running games in browser.
|
||
* Supports dynamic plugin registration.
|
||
*/
|
||
export class BrowserRuntime {
|
||
private _runtime: GameRuntime | null = null;
|
||
private _canvasId: string;
|
||
private _width: number;
|
||
private _height: number;
|
||
private _assetCatalogUrl: string;
|
||
private _assetBaseUrl: string;
|
||
private _fileSystem: BrowserFileSystemService | null = null;
|
||
private _assetReader: BrowserAssetReader | null = null;
|
||
private _initialized = false;
|
||
|
||
constructor(config: RuntimeConfig) {
|
||
this._canvasId = config.canvasId;
|
||
this._width = config.width ?? window.innerWidth;
|
||
this._height = config.height ?? window.innerHeight;
|
||
this._assetCatalogUrl = config.assetCatalogUrl ?? '/asset-catalog.json';
|
||
this._assetBaseUrl = config.assetBaseUrl ?? '/assets';
|
||
}
|
||
|
||
/**
|
||
* Register a plugin dynamically
|
||
* 动态注册插件
|
||
*
|
||
* Call this before initialize() to register plugins.
|
||
*/
|
||
registerPlugin(plugin: IPlugin): void {
|
||
if (plugin) {
|
||
runtimePluginManager.register(plugin);
|
||
runtimePluginManager.enable(plugin.manifest.id);
|
||
console.log(`[Runtime] Registered plugin: ${plugin.manifest.id}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Register multiple plugins
|
||
* 注册多个插件
|
||
*/
|
||
registerPlugins(plugins: IPlugin[]): void {
|
||
for (const plugin of plugins) {
|
||
this.registerPlugin(plugin);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Initialize the runtime
|
||
* 初始化运行时
|
||
*
|
||
* @param wasmModule - Optional WASM module (from es_engine.js)
|
||
*/
|
||
async initialize(wasmModule?: unknown): Promise<void> {
|
||
if (this._initialized) {
|
||
console.warn('[Runtime] Already initialized');
|
||
return;
|
||
}
|
||
|
||
// Initialize browser file system service
|
||
this._fileSystem = new BrowserFileSystemService({
|
||
baseUrl: this._assetBaseUrl,
|
||
catalogUrl: this._assetCatalogUrl,
|
||
enableCache: true
|
||
});
|
||
await this._fileSystem.initialize();
|
||
|
||
// Initialize asset reader
|
||
this._assetReader = new BrowserAssetReader(this._assetBaseUrl);
|
||
|
||
// Create browser platform adapter
|
||
const platform = new BrowserPlatformAdapter({
|
||
wasmModule: wasmModule ?? undefined
|
||
});
|
||
|
||
// Create game runtime
|
||
this._runtime = createGameRuntime({
|
||
platform,
|
||
canvasId: this._canvasId,
|
||
width: this._width,
|
||
height: this._height,
|
||
autoStartRenderLoop: false
|
||
});
|
||
|
||
await this._runtime.initialize();
|
||
|
||
// Register file system service
|
||
const IFileSystemServiceKey = Symbol.for('IFileSystemService');
|
||
if (!Core.services.isRegistered(IFileSystemServiceKey)) {
|
||
Core.services.registerInstance(IFileSystemServiceKey, this._fileSystem);
|
||
}
|
||
|
||
// Set asset reader for AssetManager
|
||
if (this._runtime.assetManager && this._assetReader) {
|
||
this._runtime.assetManager.setReader(this._assetReader);
|
||
}
|
||
|
||
// Disable editor mode (hides grid, gizmos, axis indicator)
|
||
// 禁用编辑器模式(隐藏网格、gizmos、坐标轴指示器)
|
||
this._runtime.setEditorMode(false);
|
||
|
||
this._initialized = true;
|
||
console.log('[Runtime] Initialized');
|
||
}
|
||
|
||
/**
|
||
* Load a scene from URL
|
||
* 从 URL 加载场景
|
||
*/
|
||
async loadScene(sceneUrl: string): Promise<void> {
|
||
if (!this._runtime) {
|
||
throw new Error('Runtime not initialized. Call initialize() first.');
|
||
}
|
||
await this._runtime.loadSceneFromUrl(sceneUrl);
|
||
}
|
||
|
||
/**
|
||
* Start the game loop
|
||
* 启动游戏循环
|
||
*/
|
||
start(): void {
|
||
this._runtime?.start();
|
||
}
|
||
|
||
/**
|
||
* Stop the game loop
|
||
* 停止游戏循环
|
||
*/
|
||
stop(): void {
|
||
this._runtime?.stop();
|
||
}
|
||
|
||
/**
|
||
* Handle window resize
|
||
* 处理窗口大小变化
|
||
*/
|
||
handleResize(width: number, height: number): void {
|
||
this._runtime?.resize(width, height);
|
||
}
|
||
|
||
/**
|
||
* Get the underlying GameRuntime
|
||
* 获取底层 GameRuntime
|
||
*/
|
||
get gameRuntime(): GameRuntime | null {
|
||
return this._runtime;
|
||
}
|
||
|
||
/**
|
||
* Get the asset manager
|
||
* 获取资产管理器
|
||
*
|
||
* @returns The asset manager instance, or null if not initialized
|
||
*/
|
||
get assetManager(): IAssetManager | null {
|
||
return this._runtime?.assetManager ?? null;
|
||
}
|
||
|
||
/**
|
||
* Check if runtime is initialized
|
||
* 检查运行时是否已初始化
|
||
*/
|
||
get isInitialized(): boolean {
|
||
return this._initialized;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create a browser runtime instance
|
||
* 创建浏览器运行时实例
|
||
*/
|
||
export function create(config: RuntimeConfig): BrowserRuntime {
|
||
return new BrowserRuntime(config);
|
||
}
|
||
|
||
/**
|
||
* Default export for convenient usage
|
||
* 默认导出,便于使用
|
||
*
|
||
* Usage in game HTML:
|
||
* ```js
|
||
* const ECSRuntime = (await import('@esengine/platform-web')).default;
|
||
* const runtime = ECSRuntime.create({ canvasId: 'game-canvas' });
|
||
* ```
|
||
*/
|
||
export default {
|
||
create,
|
||
BrowserRuntime,
|
||
BrowserAssetReader,
|
||
// Re-export useful types from dependencies
|
||
Core,
|
||
GameRuntime,
|
||
createGameRuntime,
|
||
BrowserPlatformAdapter,
|
||
runtimePluginManager
|
||
};
|