修复插件生成代码报错问题
This commit is contained in:
@@ -94,7 +94,7 @@ ${comments}
|
|||||||
export class ${className} extends ${options.systemType} {
|
export class ${className} extends ${options.systemType} {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(${matcherSetup}${options.systemType === 'IntervalSystem' ? ', 1000 / 60 // 60fps' : ''});
|
super(${matcherSetup}${options.systemType === 'IntervalSystem' ? ', 1000 / 60' : ''})${options.systemType === 'IntervalSystem' ? '; // 60fps' : ';'}
|
||||||
}
|
}
|
||||||
|
|
||||||
${processMethod}
|
${processMethod}
|
||||||
|
|||||||
@@ -14,30 +14,21 @@ export class BehaviorTreeHandler {
|
|||||||
const projectPath = Editor.Project.path;
|
const projectPath = Editor.Project.path;
|
||||||
const command = 'npm install @esengine/ai';
|
const command = 'npm install @esengine/ai';
|
||||||
|
|
||||||
console.log(`Installing Behavior Tree AI to project: ${projectPath}`);
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
exec(command, { cwd: projectPath }, (error, stdout, stderr) => {
|
exec(command, { cwd: projectPath }, (error, stdout, stderr) => {
|
||||||
console.log('Install stdout:', stdout);
|
|
||||||
if (stderr) console.log('Install stderr:', stderr);
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Behavior Tree AI installation failed:', error);
|
console.error('AI系统安装失败:', error.message);
|
||||||
resolve(false);
|
resolve(false);
|
||||||
} else {
|
} else {
|
||||||
console.log('Behavior Tree AI installation completed successfully');
|
|
||||||
|
|
||||||
// 验证安装是否成功
|
// 验证安装是否成功
|
||||||
const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ai');
|
const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ai');
|
||||||
const installSuccess = fs.existsSync(nodeModulesPath);
|
const installSuccess = fs.existsSync(nodeModulesPath);
|
||||||
|
|
||||||
if (installSuccess) {
|
if (!installSuccess) {
|
||||||
console.log('Behavior Tree AI installed successfully');
|
console.warn('安装完成但未找到AI系统目录,请检查网络连接');
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
console.warn('Behavior Tree AI directory not found after install');
|
|
||||||
resolve(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve(installSuccess);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -50,30 +41,21 @@ export class BehaviorTreeHandler {
|
|||||||
const projectPath = Editor.Project.path;
|
const projectPath = Editor.Project.path;
|
||||||
const command = 'npm update @esengine/ai';
|
const command = 'npm update @esengine/ai';
|
||||||
|
|
||||||
console.log(`Updating Behavior Tree AI in project: ${projectPath}`);
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
exec(command, { cwd: projectPath }, (error, stdout, stderr) => {
|
exec(command, { cwd: projectPath }, (error, stdout, stderr) => {
|
||||||
console.log('Update stdout:', stdout);
|
|
||||||
if (stderr) console.log('Update stderr:', stderr);
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Behavior Tree AI update failed:', error);
|
console.error('AI系统更新失败:', error.message);
|
||||||
resolve(false);
|
resolve(false);
|
||||||
} else {
|
} else {
|
||||||
console.log('Behavior Tree AI update completed successfully');
|
|
||||||
|
|
||||||
// 验证更新是否成功
|
// 验证更新是否成功
|
||||||
const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ai');
|
const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ai');
|
||||||
const updateSuccess = fs.existsSync(nodeModulesPath);
|
const updateSuccess = fs.existsSync(nodeModulesPath);
|
||||||
|
|
||||||
if (updateSuccess) {
|
if (!updateSuccess) {
|
||||||
console.log('Behavior Tree AI updated successfully');
|
console.warn('更新完成但未找到AI系统目录');
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
console.warn('Behavior Tree AI directory not found after update');
|
|
||||||
resolve(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve(updateSuccess);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -96,7 +78,7 @@ export class BehaviorTreeHandler {
|
|||||||
|
|
||||||
return '@esengine/ai' in dependencies;
|
return '@esengine/ai' in dependencies;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking Behavior Tree AI installation:', error);
|
console.error('检查AI系统安装状态失败:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,15 +93,25 @@ export const methods: { [key: string]: (...any: any) => any } = {
|
|||||||
/**
|
/**
|
||||||
* 安装行为树AI系统
|
* 安装行为树AI系统
|
||||||
*/
|
*/
|
||||||
'install-behavior-tree'() {
|
async 'install-behavior-tree'() {
|
||||||
BehaviorTreeHandler.install();
|
try {
|
||||||
|
return await BehaviorTreeHandler.install();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('安装行为树AI系统失败:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新行为树AI系统
|
* 更新行为树AI系统
|
||||||
*/
|
*/
|
||||||
'update-behavior-tree'() {
|
async 'update-behavior-tree'() {
|
||||||
BehaviorTreeHandler.update();
|
try {
|
||||||
|
return await BehaviorTreeHandler.update();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新行为树AI系统失败:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -347,9 +347,113 @@ export function useBehaviorTreeEditor() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 复制到剪贴板
|
||||||
|
const copyToClipboard = async () => {
|
||||||
|
try {
|
||||||
|
const code = computedProps.exportedCode();
|
||||||
|
await navigator.clipboard.writeText(code);
|
||||||
|
|
||||||
|
// 显示成功消息
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
background: #4caf50;
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
z-index: 10001;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(100%);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
`;
|
||||||
|
toast.textContent = '已复制到剪贴板!';
|
||||||
|
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.opacity = '1';
|
||||||
|
toast.style.transform = 'translateX(0)';
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.opacity = '0';
|
||||||
|
toast.style.transform = 'translateX(100%)';
|
||||||
|
setTimeout(() => {
|
||||||
|
if (document.body.contains(toast)) {
|
||||||
|
document.body.removeChild(toast);
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}, 2000);
|
||||||
|
} catch (error) {
|
||||||
|
alert('复制到剪贴板失败: ' + error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存到文件
|
||||||
|
const saveToFile = () => {
|
||||||
|
const code = computedProps.exportedCode();
|
||||||
|
const format = appState.exportFormat.value;
|
||||||
|
const extension = format === 'json' ? '.json' : '.ts';
|
||||||
|
const mimeType = format === 'json' ? 'application/json' : 'text/typescript';
|
||||||
|
|
||||||
|
// 创建文件并下载
|
||||||
|
const blob = new Blob([code], { type: mimeType });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `behavior_tree_config${extension}`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
// 显示成功消息
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
background: #4caf50;
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
z-index: 10001;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(100%);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
`;
|
||||||
|
toast.textContent = `文件已保存: behavior_tree_config${extension}`;
|
||||||
|
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.opacity = '1';
|
||||||
|
toast.style.transform = 'translateX(0)';
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.opacity = '0';
|
||||||
|
toast.style.transform = 'translateX(100%)';
|
||||||
|
setTimeout(() => {
|
||||||
|
if (document.body.contains(toast)) {
|
||||||
|
document.body.removeChild(toast);
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// 自动检查安装状态
|
||||||
|
installation.checkInstallStatus();
|
||||||
|
|
||||||
const appContainer = document.querySelector('#behavior-tree-app');
|
const appContainer = document.querySelector('#behavior-tree-app');
|
||||||
if (appContainer) {
|
if (appContainer) {
|
||||||
(appContainer as any).loadFileContent = fileOps.loadFileContent;
|
(appContainer as any).loadFileContent = fileOps.loadFileContent;
|
||||||
@@ -457,6 +561,8 @@ export function useBehaviorTreeEditor() {
|
|||||||
autoLayout,
|
autoLayout,
|
||||||
validateTree,
|
validateTree,
|
||||||
clearAllConnections,
|
clearAllConnections,
|
||||||
|
copyToClipboard,
|
||||||
|
saveToFile,
|
||||||
// 节点选择相关
|
// 节点选择相关
|
||||||
selectNode: (nodeId: string) => {
|
selectNode: (nodeId: string) => {
|
||||||
// 选中普通节点时,取消条件节点的选中
|
// 选中普通节点时,取消条件节点的选中
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export function useInstallation(
|
|||||||
isInstalled.value = result.installed;
|
isInstalled.value = result.installed;
|
||||||
version.value = result.version;
|
version.value = result.version;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('检查AI系统安装状态失败:', error);
|
||||||
isInstalled.value = false;
|
isInstalled.value = false;
|
||||||
version.value = null;
|
version.value = null;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -30,10 +31,23 @@ export function useInstallation(
|
|||||||
const handleInstall = async () => {
|
const handleInstall = async () => {
|
||||||
isInstalling.value = true;
|
isInstalling.value = true;
|
||||||
try {
|
try {
|
||||||
await installBehaviorTreeAI(Editor.Project.path);
|
const result = await installBehaviorTreeAI(Editor.Project.path);
|
||||||
await checkInstallStatus();
|
|
||||||
|
if (result) {
|
||||||
|
// 等待文件系统更新
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
await checkInstallStatus();
|
||||||
|
|
||||||
|
// 如果第一次检查失败,再次尝试
|
||||||
|
if (!isInstalled.value) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
await checkInstallStatus();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('AI系统安装失败');
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 安装失败时静默处理
|
console.error('安装AI系统时发生错误:', error);
|
||||||
} finally {
|
} finally {
|
||||||
isInstalling.value = false;
|
isInstalling.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ export function getInstallStatusText(
|
|||||||
isInstalled: boolean,
|
isInstalled: boolean,
|
||||||
version: string | null
|
version: string | null
|
||||||
): string {
|
): string {
|
||||||
if (isChecking) return '检查中...';
|
if (isChecking) return '检查状态中...';
|
||||||
if (isInstalling) return '安装中...';
|
if (isInstalling) return '正在安装AI系统...';
|
||||||
return isInstalled ? `✅ AI系统已安装 (v${version})` : '❌ AI系统未安装';
|
return isInstalled ? 'AI系统已安装' : 'AI系统未安装';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,19 +70,13 @@ export function getInstallStatusClass(
|
|||||||
* 安装行为树AI系统
|
* 安装行为树AI系统
|
||||||
* 通过发送消息到主进程来执行真实的npm安装命令
|
* 通过发送消息到主进程来执行真实的npm安装命令
|
||||||
*/
|
*/
|
||||||
export async function installBehaviorTreeAI(projectPath: string): Promise<void> {
|
export async function installBehaviorTreeAI(projectPath: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
// 通过Editor.Message发送安装消息到主进程
|
|
||||||
// 主进程会执行实际的npm install @esengine/ai命令
|
|
||||||
const result = await Editor.Message.request('cocos-ecs-extension', 'install-behavior-tree');
|
const result = await Editor.Message.request('cocos-ecs-extension', 'install-behavior-tree');
|
||||||
|
return Boolean(result);
|
||||||
if (!result) {
|
|
||||||
throw new Error('安装请求失败,未收到主进程响应');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 安装完成
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
console.error('请求安装AI系统失败:', error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,18 +84,12 @@ export async function installBehaviorTreeAI(projectPath: string): Promise<void>
|
|||||||
* 更新行为树AI系统
|
* 更新行为树AI系统
|
||||||
* 通过发送消息到主进程来执行真实的npm更新命令
|
* 通过发送消息到主进程来执行真实的npm更新命令
|
||||||
*/
|
*/
|
||||||
export async function updateBehaviorTreeAI(projectPath: string): Promise<void> {
|
export async function updateBehaviorTreeAI(projectPath: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
// 通过Editor.Message发送更新消息到主进程
|
|
||||||
// 主进程会执行实际的npm update @esengine/ai命令
|
|
||||||
const result = await Editor.Message.request('cocos-ecs-extension', 'update-behavior-tree');
|
const result = await Editor.Message.request('cocos-ecs-extension', 'update-behavior-tree');
|
||||||
|
return Boolean(result);
|
||||||
if (!result) {
|
|
||||||
throw new Error('更新请求失败,未收到主进程响应');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新完成
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
console.error('请求更新AI系统失败:', error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,4 +72,140 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 编辑器容器禁用状态 */
|
||||||
|
.editor-container.disabled {
|
||||||
|
position: relative;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: blur(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 安装遮罩层 */
|
||||||
|
.install-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(26, 32, 44, 0.95);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 1000;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-content {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 20px;
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
max-width: 400px;
|
||||||
|
width: 90%;
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-icon {
|
||||||
|
font-size: 60px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
animation: float 3s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translateY(0px); }
|
||||||
|
50% { transform: translateY(-10px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-content h3 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-content p {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-actions {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-install-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 14px 28px;
|
||||||
|
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-install-btn:hover:not(:disabled) {
|
||||||
|
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 25px rgba(34, 197, 94, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-install-btn:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-install-btn.installing {
|
||||||
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
|
||||||
|
animation: installing-glow 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes installing-glow {
|
||||||
|
0%, 100% {
|
||||||
|
box-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-top: 2px solid white;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-note {
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(59, 130, 246, 0.1);
|
||||||
|
border: 1px solid rgba(59, 130, 246, 0.3);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-note small {
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
@@ -59,11 +59,13 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-btn:hover {
|
.tool-btn:hover:not(:disabled) {
|
||||||
background: rgba(255,255,255,0.2);
|
background: rgba(255,255,255,0.2);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tool-btn.has-changes {
|
.tool-btn.has-changes {
|
||||||
background: rgba(255, 107, 107, 0.2);
|
background: rgba(255, 107, 107, 0.2);
|
||||||
border-color: #ff6b6b;
|
border-color: #ff6b6b;
|
||||||
@@ -79,11 +81,176 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-right .install-status {
|
/* 安装状态容器 */
|
||||||
|
.install-status-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border: 1px solid rgba(255,255,255,0.2);
|
||||||
|
border-radius: 12px;
|
||||||
|
min-width: 280px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-status:hover {
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
border-color: rgba(255,255,255,0.3);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态信息 */
|
||||||
|
.status-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-text {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-text {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255,255,255,0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 安装按钮 */
|
||||||
|
.install-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
background: rgba(255,255,255,0.1);
|
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
|
||||||
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-btn:hover:not(:disabled) {
|
||||||
|
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(34, 197, 94, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-btn:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-btn.installing {
|
||||||
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-text {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载点动画 */
|
||||||
|
.loading-dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-dots span {
|
||||||
|
width: 3px;
|
||||||
|
height: 3px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: loading-dots 1.4s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-dots span:nth-child(1) { animation-delay: -0.32s; }
|
||||||
|
.loading-dots span:nth-child(2) { animation-delay: -0.16s; }
|
||||||
|
|
||||||
|
@keyframes loading-dots {
|
||||||
|
0%, 80%, 100% {
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 刷新按钮 */
|
||||||
|
.refresh-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border: 1px solid rgba(255,255,255,0.2);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-btn:hover {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态颜色 */
|
||||||
|
.install-status.installed {
|
||||||
|
border-color: rgba(34, 197, 94, 0.5);
|
||||||
|
background: rgba(34, 197, 94, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-status.not-installed {
|
||||||
|
border-color: rgba(239, 68, 68, 0.5);
|
||||||
|
background: rgba(239, 68, 68, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-status.installing {
|
||||||
|
border-color: rgba(59, 130, 246, 0.5);
|
||||||
|
background: rgba(59, 130, 246, 0.1);
|
||||||
|
animation: installing-pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes installing-pulse {
|
||||||
|
0%, 100% {
|
||||||
|
box-shadow: 0 0 5px rgba(59, 130, 246, 0.3);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 15px rgba(59, 130, 246, 0.6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,16 +24,64 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbar-right">
|
<div class="toolbar-right">
|
||||||
<div class="install-status" :class="installStatusClass()">
|
<div class="install-status-container">
|
||||||
<span>{{ installStatusText() }}</span>
|
<div class="install-status" :class="installStatusClass()">
|
||||||
<button v-if="!isInstalled" @click="handleInstall" :disabled="isInstalling">
|
<div class="status-info">
|
||||||
{{ isInstalling ? '安装中...' : '安装AI系统' }}
|
<span class="status-icon">{{ isInstalled ? '✅' : (isInstalling ? '⏳' : '❌') }}</span>
|
||||||
</button>
|
<div class="status-text">
|
||||||
|
<span class="main-text">{{ installStatusText() }}</span>
|
||||||
|
<span v-if="version && isInstalled" class="version-text">版本 {{ version }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
v-if="!isInstalled"
|
||||||
|
@click="handleInstall"
|
||||||
|
:disabled="isInstalling"
|
||||||
|
class="install-btn"
|
||||||
|
:class="{ 'installing': isInstalling }"
|
||||||
|
>
|
||||||
|
<span class="btn-icon">{{ isInstalling ? '⏳' : '📦' }}</span>
|
||||||
|
<span class="btn-text">{{ isInstalling ? '安装中...' : '立即安装' }}</span>
|
||||||
|
<div v-if="isInstalling" class="loading-dots">
|
||||||
|
<span></span><span></span><span></span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="isInstalled && !checkingStatus"
|
||||||
|
@click="checkInstallStatus"
|
||||||
|
class="refresh-btn"
|
||||||
|
title="检查更新"
|
||||||
|
>
|
||||||
|
🔄
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-container">
|
<div class="editor-container" :class="{ 'disabled': !isInstalled }">
|
||||||
|
<!-- 未安装遮罩 -->
|
||||||
|
<div v-if="!isInstalled" class="install-overlay">
|
||||||
|
<div class="overlay-content">
|
||||||
|
<div class="overlay-icon">🤖</div>
|
||||||
|
<h3>需要安装AI系统</h3>
|
||||||
|
<p>行为树编辑器需要安装AI系统才能正常使用</p>
|
||||||
|
<div class="overlay-actions">
|
||||||
|
<button
|
||||||
|
@click="handleInstall"
|
||||||
|
:disabled="isInstalling"
|
||||||
|
class="overlay-install-btn"
|
||||||
|
:class="{ 'installing': isInstalling }"
|
||||||
|
>
|
||||||
|
<span>{{ isInstalling ? '⏳ 安装中...' : '📦 立即安装AI系统' }}</span>
|
||||||
|
<div v-if="isInstalling" class="loading-spinner"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="overlay-note">
|
||||||
|
<small>📝 安装完成后编辑器将自动可用</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 左侧节点面板 -->
|
<!-- 左侧节点面板 -->
|
||||||
<div class="nodes-panel">
|
<div class="nodes-panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
|
|||||||
1
extensions/cocos/cocos-ecs/package-lock.json
generated
1
extensions/cocos/cocos-ecs/package-lock.json
generated
@@ -14,6 +14,7 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@esengine/ai/-/ai-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@esengine/ai/-/ai-2.0.1.tgz",
|
||||||
"integrity": "sha512-qGGYc4kYlSJzCkBDJa+p5OruOnDvnL2oJ/ciKSHsPJVdn1tIefPEkUofJyMVGo4my5ubGr2ky6igTLtLYmhzRg==",
|
"integrity": "sha512-qGGYc4kYlSJzCkBDJa+p5OruOnDvnL2oJ/ciKSHsPJVdn1tIefPEkUofJyMVGo4my5ubGr2ky6igTLtLYmhzRg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user