Feature/runtime cdn and plugin loader (#240)

* feat(ui): 完善 UI 布局系统和编辑器可视化工具

* refactor: 移除 ModuleRegistry,统一使用 PluginManager 插件系统

* fix: 修复 CodeQL 警告并提升测试覆盖率

* refactor: 分离运行时入口点,解决 runtime bundle 包含 React 的问题

* fix(ci): 添加 editor-core 和 editor-runtime 到 CI 依赖构建步骤

* docs: 完善 ServiceContainer 文档,新增 Symbol.for 模式和 @InjectProperty 说明

* fix(ci): 修复 type-check 失败问题

* fix(ci): 修复类型检查失败问题

* fix(ci): 修复类型检查失败问题

* fix(ci): behavior-tree 构建添加 @tauri-apps 外部依赖

* fix(ci): behavior-tree 添加 @tauri-apps/plugin-fs 类型依赖

* fix(ci): platform-web 添加缺失的 behavior-tree 依赖

* fix(lint): 移除正则表达式中不必要的转义字符
This commit is contained in:
YHH
2025-11-27 20:42:46 +08:00
committed by GitHub
parent 71869b1a58
commit 107439d70c
367 changed files with 10661 additions and 12473 deletions

View File

@@ -1,17 +1,20 @@
import { useState, useEffect } from 'react';
import { X, Settings as SettingsIcon, ChevronRight } from 'lucide-react';
import { Core } from '@esengine/ecs-framework';
import { SettingsService } from '../services/SettingsService';
import { SettingsRegistry, SettingCategory, SettingDescriptor } from '@esengine/editor-core';
import { SettingsRegistry, SettingCategory, SettingDescriptor, ProjectService, PluginManager, IPluginManager } from '@esengine/editor-core';
import { PluginListSetting } from './PluginListSetting';
import '../styles/SettingsWindow.css';
interface SettingsWindowProps {
onClose: () => void;
settingsRegistry: SettingsRegistry;
initialCategoryId?: string;
}
export function SettingsWindow({ onClose, settingsRegistry }: SettingsWindowProps) {
export function SettingsWindow({ onClose, settingsRegistry, initialCategoryId }: SettingsWindowProps) {
const [categories, setCategories] = useState<SettingCategory[]>([]);
const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(null);
const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(initialCategoryId || null);
const [values, setValues] = useState<Map<string, any>>(new Map());
const [errors, setErrors] = useState<Map<string, string>>(new Map());
@@ -20,19 +23,42 @@ export function SettingsWindow({ onClose, settingsRegistry }: SettingsWindowProp
setCategories(allCategories);
if (allCategories.length > 0 && !selectedCategoryId) {
const firstCategory = allCategories[0];
if (firstCategory) {
setSelectedCategoryId(firstCategory.id);
// 如果有 initialCategoryId尝试使用它
if (initialCategoryId && allCategories.some(c => c.id === initialCategoryId)) {
setSelectedCategoryId(initialCategoryId);
} else {
const firstCategory = allCategories[0];
if (firstCategory) {
setSelectedCategoryId(firstCategory.id);
}
}
}
const settings = SettingsService.getInstance();
const projectService = Core.services.tryResolve<ProjectService>(ProjectService);
const allSettings = settingsRegistry.getAllSettings();
const initialValues = new Map<string, any>();
for (const [key, descriptor] of allSettings.entries()) {
const value = settings.get(key, descriptor.defaultValue);
initialValues.set(key, value);
// Project-scoped settings are loaded from ProjectService
if (key.startsWith('project.') && projectService) {
if (key === 'project.uiDesignResolution.width') {
const resolution = projectService.getUIDesignResolution();
initialValues.set(key, resolution.width);
} else if (key === 'project.uiDesignResolution.height') {
const resolution = projectService.getUIDesignResolution();
initialValues.set(key, resolution.height);
} else if (key === 'project.uiDesignResolution.preset') {
const resolution = projectService.getUIDesignResolution();
initialValues.set(key, `${resolution.width}x${resolution.height}`);
} else {
// For other project settings, use default
initialValues.set(key, descriptor.defaultValue);
}
} else {
const value = settings.get(key, descriptor.defaultValue);
initialValues.set(key, value);
}
}
setValues(initialValues);
@@ -52,17 +78,48 @@ export function SettingsWindow({ onClose, settingsRegistry }: SettingsWindowProp
setErrors(newErrors);
};
const handleSave = () => {
const handleSave = async () => {
if (errors.size > 0) {
return;
}
const settings = SettingsService.getInstance();
const projectService = Core.services.tryResolve<ProjectService>(ProjectService);
const changedSettings: Record<string, any> = {};
// Track UI resolution changes for batch saving
let uiResolutionChanged = false;
let newWidth = 1920;
let newHeight = 1080;
for (const [key, value] of values.entries()) {
settings.set(key, value);
changedSettings[key] = value;
// Project-scoped settings are saved to ProjectService
if (key.startsWith('project.') && projectService) {
if (key === 'project.uiDesignResolution.width') {
newWidth = value;
uiResolutionChanged = true;
} else if (key === 'project.uiDesignResolution.height') {
newHeight = value;
uiResolutionChanged = true;
} else if (key === 'project.uiDesignResolution.preset') {
// Preset changes width and height together
const [w, h] = value.split('x').map(Number);
if (w && h) {
newWidth = w;
newHeight = h;
uiResolutionChanged = true;
}
}
changedSettings[key] = value;
} else {
settings.set(key, value);
changedSettings[key] = value;
}
}
// Save UI resolution if changed
if (uiResolutionChanged && projectService) {
await projectService.setUIDesignResolution({ width: newWidth, height: newHeight });
}
window.dispatchEvent(new CustomEvent('settings:changed', {
@@ -216,6 +273,23 @@ export function SettingsWindow({ onClose, settingsRegistry }: SettingsWindowProp
</div>
);
case 'pluginList': {
const pluginManager = Core.services.tryResolve<PluginManager>(IPluginManager);
if (!pluginManager) {
return (
<div className="settings-field settings-field-full">
<p className="settings-error">PluginManager </p>
</div>
);
}
return (
<div className="settings-field settings-field-full">
<PluginListSetting pluginManager={pluginManager} />
{error && <span className="settings-error">{error}</span>}
</div>
);
}
default:
return null;
}