修复插件生成代码报错问题
This commit is contained in:
@@ -94,7 +94,7 @@ ${comments}
|
||||
export class ${className} extends ${options.systemType} {
|
||||
|
||||
constructor() {
|
||||
super(${matcherSetup}${options.systemType === 'IntervalSystem' ? ', 1000 / 60 // 60fps' : ''});
|
||||
super(${matcherSetup}${options.systemType === 'IntervalSystem' ? ', 1000 / 60' : ''})${options.systemType === 'IntervalSystem' ? '; // 60fps' : ';'}
|
||||
}
|
||||
|
||||
${processMethod}
|
||||
|
||||
@@ -14,30 +14,21 @@ export class BehaviorTreeHandler {
|
||||
const projectPath = Editor.Project.path;
|
||||
const command = 'npm install @esengine/ai';
|
||||
|
||||
console.log(`Installing Behavior Tree AI to project: ${projectPath}`);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
exec(command, { cwd: projectPath }, (error, stdout, stderr) => {
|
||||
console.log('Install stdout:', stdout);
|
||||
if (stderr) console.log('Install stderr:', stderr);
|
||||
|
||||
if (error) {
|
||||
console.error('Behavior Tree AI installation failed:', error);
|
||||
console.error('AI系统安装失败:', error.message);
|
||||
resolve(false);
|
||||
} else {
|
||||
console.log('Behavior Tree AI installation completed successfully');
|
||||
|
||||
// 验证安装是否成功
|
||||
const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ai');
|
||||
const installSuccess = fs.existsSync(nodeModulesPath);
|
||||
|
||||
if (installSuccess) {
|
||||
console.log('Behavior Tree AI installed successfully');
|
||||
resolve(true);
|
||||
} else {
|
||||
console.warn('Behavior Tree AI directory not found after install');
|
||||
resolve(false);
|
||||
if (!installSuccess) {
|
||||
console.warn('安装完成但未找到AI系统目录,请检查网络连接');
|
||||
}
|
||||
|
||||
resolve(installSuccess);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -50,30 +41,21 @@ export class BehaviorTreeHandler {
|
||||
const projectPath = Editor.Project.path;
|
||||
const command = 'npm update @esengine/ai';
|
||||
|
||||
console.log(`Updating Behavior Tree AI in project: ${projectPath}`);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
exec(command, { cwd: projectPath }, (error, stdout, stderr) => {
|
||||
console.log('Update stdout:', stdout);
|
||||
if (stderr) console.log('Update stderr:', stderr);
|
||||
|
||||
if (error) {
|
||||
console.error('Behavior Tree AI update failed:', error);
|
||||
console.error('AI系统更新失败:', error.message);
|
||||
resolve(false);
|
||||
} else {
|
||||
console.log('Behavior Tree AI update completed successfully');
|
||||
|
||||
// 验证更新是否成功
|
||||
const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ai');
|
||||
const updateSuccess = fs.existsSync(nodeModulesPath);
|
||||
|
||||
if (updateSuccess) {
|
||||
console.log('Behavior Tree AI updated successfully');
|
||||
resolve(true);
|
||||
} else {
|
||||
console.warn('Behavior Tree AI directory not found after update');
|
||||
resolve(false);
|
||||
if (!updateSuccess) {
|
||||
console.warn('更新完成但未找到AI系统目录');
|
||||
}
|
||||
|
||||
resolve(updateSuccess);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -96,7 +78,7 @@ export class BehaviorTreeHandler {
|
||||
|
||||
return '@esengine/ai' in dependencies;
|
||||
} catch (error) {
|
||||
console.error('Error checking Behavior Tree AI installation:', error);
|
||||
console.error('检查AI系统安装状态失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,15 +93,25 @@ export const methods: { [key: string]: (...any: any) => any } = {
|
||||
/**
|
||||
* 安装行为树AI系统
|
||||
*/
|
||||
'install-behavior-tree'() {
|
||||
BehaviorTreeHandler.install();
|
||||
async 'install-behavior-tree'() {
|
||||
try {
|
||||
return await BehaviorTreeHandler.install();
|
||||
} catch (error) {
|
||||
console.error('安装行为树AI系统失败:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新行为树AI系统
|
||||
*/
|
||||
'update-behavior-tree'() {
|
||||
BehaviorTreeHandler.update();
|
||||
async 'update-behavior-tree'() {
|
||||
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(() => {
|
||||
// 自动检查安装状态
|
||||
installation.checkInstallStatus();
|
||||
|
||||
const appContainer = document.querySelector('#behavior-tree-app');
|
||||
if (appContainer) {
|
||||
(appContainer as any).loadFileContent = fileOps.loadFileContent;
|
||||
@@ -457,6 +561,8 @@ export function useBehaviorTreeEditor() {
|
||||
autoLayout,
|
||||
validateTree,
|
||||
clearAllConnections,
|
||||
copyToClipboard,
|
||||
saveToFile,
|
||||
// 节点选择相关
|
||||
selectNode: (nodeId: string) => {
|
||||
// 选中普通节点时,取消条件节点的选中
|
||||
|
||||
@@ -19,6 +19,7 @@ export function useInstallation(
|
||||
isInstalled.value = result.installed;
|
||||
version.value = result.version;
|
||||
} catch (error) {
|
||||
console.error('检查AI系统安装状态失败:', error);
|
||||
isInstalled.value = false;
|
||||
version.value = null;
|
||||
} finally {
|
||||
@@ -30,10 +31,23 @@ export function useInstallation(
|
||||
const handleInstall = async () => {
|
||||
isInstalling.value = true;
|
||||
try {
|
||||
await installBehaviorTreeAI(Editor.Project.path);
|
||||
const result = await installBehaviorTreeAI(Editor.Project.path);
|
||||
|
||||
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) {
|
||||
// 安装失败时静默处理
|
||||
console.error('安装AI系统时发生错误:', error);
|
||||
} finally {
|
||||
isInstalling.value = false;
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ export function getInstallStatusText(
|
||||
isInstalled: boolean,
|
||||
version: string | null
|
||||
): string {
|
||||
if (isChecking) return '检查中...';
|
||||
if (isInstalling) return '安装中...';
|
||||
return isInstalled ? `✅ AI系统已安装 (v${version})` : '❌ AI系统未安装';
|
||||
if (isChecking) return '检查状态中...';
|
||||
if (isInstalling) return '正在安装AI系统...';
|
||||
return isInstalled ? 'AI系统已安装' : 'AI系统未安装';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,19 +70,13 @@ export function getInstallStatusClass(
|
||||
* 安装行为树AI系统
|
||||
* 通过发送消息到主进程来执行真实的npm安装命令
|
||||
*/
|
||||
export async function installBehaviorTreeAI(projectPath: string): Promise<void> {
|
||||
export async function installBehaviorTreeAI(projectPath: string): Promise<boolean> {
|
||||
try {
|
||||
// 通过Editor.Message发送安装消息到主进程
|
||||
// 主进程会执行实际的npm install @esengine/ai命令
|
||||
const result = await Editor.Message.request('cocos-ecs-extension', 'install-behavior-tree');
|
||||
|
||||
if (!result) {
|
||||
throw new Error('安装请求失败,未收到主进程响应');
|
||||
}
|
||||
|
||||
// 安装完成
|
||||
return Boolean(result);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
console.error('请求安装AI系统失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,18 +84,12 @@ export async function installBehaviorTreeAI(projectPath: string): Promise<void>
|
||||
* 更新行为树AI系统
|
||||
* 通过发送消息到主进程来执行真实的npm更新命令
|
||||
*/
|
||||
export async function updateBehaviorTreeAI(projectPath: string): Promise<void> {
|
||||
export async function updateBehaviorTreeAI(projectPath: string): Promise<boolean> {
|
||||
try {
|
||||
// 通过Editor.Message发送更新消息到主进程
|
||||
// 主进程会执行实际的npm update @esengine/ai命令
|
||||
const result = await Editor.Message.request('cocos-ecs-extension', 'update-behavior-tree');
|
||||
|
||||
if (!result) {
|
||||
throw new Error('更新请求失败,未收到主进程响应');
|
||||
}
|
||||
|
||||
// 更新完成
|
||||
return Boolean(result);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
console.error('请求更新AI系统失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -73,3 +73,139 @@
|
||||
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;
|
||||
}
|
||||
|
||||
.tool-btn:hover {
|
||||
.tool-btn:hover:not(:disabled) {
|
||||
background: rgba(255,255,255,0.2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tool-btn.has-changes {
|
||||
background: rgba(255, 107, 107, 0.2);
|
||||
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;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 16px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border-radius: 8px;
|
||||
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;
|
||||
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
|
||||
border: none;
|
||||
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 class="toolbar-right">
|
||||
<div class="install-status-container">
|
||||
<div class="install-status" :class="installStatusClass()">
|
||||
<span>{{ installStatusText() }}</span>
|
||||
<button v-if="!isInstalled" @click="handleInstall" :disabled="isInstalling">
|
||||
{{ isInstalling ? '安装中...' : '安装AI系统' }}
|
||||
<div class="status-info">
|
||||
<span class="status-icon">{{ isInstalled ? '✅' : (isInstalling ? '⏳' : '❌') }}</span>
|
||||
<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 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="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",
|
||||
"resolved": "https://registry.npmjs.org/@esengine/ai/-/ai-2.0.1.tgz",
|
||||
"integrity": "sha512-qGGYc4kYlSJzCkBDJa+p5OruOnDvnL2oJ/ciKSHsPJVdn1tIefPEkUofJyMVGo4my5ubGr2ky6igTLtLYmhzRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user