1.4.2来啦!
This commit is contained in:
parent
39c5292bef
commit
bf3cf73fd8
135
main.js
135
main.js
|
|
@ -655,9 +655,82 @@ ipcMain.handle('cancel-close', () => {
|
|||
|
||||
// 取消启动游戏
|
||||
let launchCancelFlag = false;
|
||||
ipcMain.handle('cancel-launch', () => {
|
||||
let currentGameProcess = null;
|
||||
let currentGamePid = null;
|
||||
|
||||
function killGameProcessTree(pid) {
|
||||
try {
|
||||
const result = spawnSync('taskkill', ['/pid', String(pid), '/T', '/F'], { windowsHide: true, timeout: 5000 });
|
||||
if (result.status === 0) {
|
||||
writeLog(`[启动] 已终止进程树 PID: ${pid}`);
|
||||
return true;
|
||||
}
|
||||
writeLog(`[启动] taskkill PID ${pid} 返回: ${result.status}, ${result.stderr?.toString().trim()}`);
|
||||
} catch (e) {
|
||||
writeLog(`[启动] taskkill 失败: ${e.message}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function findAndKillMinecraftJavaProcesses() {
|
||||
try {
|
||||
const script = `
|
||||
$javaProcs = Get-Process -Name "java","javaw" -ErrorAction SilentlyContinue
|
||||
if ($javaProcs) {
|
||||
foreach ($p in $javaProcs) {
|
||||
try {
|
||||
$cmdLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$($p.Id)" -ErrorAction SilentlyContinue).CommandLine
|
||||
if ($cmdLine -and ($cmdLine -like '*net.minecraft*' -or $cmdLine -like '*minecraft*' -or $cmdLine -like '*forge*' -or $cmdLine -like '*fabric*' -or $cmdLine -like '*optifine*')) {
|
||||
Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue
|
||||
Write-Output "KILLED:$($p.Id)"
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const result = spawnSync('powershell', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 8000, encoding: 'utf8' });
|
||||
const output = (result.stdout || '').trim();
|
||||
if (output) {
|
||||
const pids = output.split('\n').filter(l => l.startsWith('KILLED:')).map(l => l.replace('KILLED:', ''));
|
||||
writeLog(`[启动] 通过命令行匹配杀死了 ${pids.length} 个Minecraft Java进程: ${pids.join(', ')}`);
|
||||
return pids.length > 0;
|
||||
}
|
||||
} catch (e) {
|
||||
writeLog(`[启动] 查找Minecraft进程失败: ${e.message}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ipcMain.handle('cancel-launch', async () => {
|
||||
launchCancelFlag = true;
|
||||
writeLog('[启动] 用户取消启动');
|
||||
|
||||
let killed = false;
|
||||
|
||||
if (currentGameProcess) {
|
||||
try {
|
||||
const pid = currentGameProcess.pid;
|
||||
if (pid) {
|
||||
writeLog(`[启动] 尝试终止游戏进程 PID: ${pid}`);
|
||||
killed = killGameProcessTree(pid);
|
||||
try { currentGameProcess.kill(); } catch {}
|
||||
}
|
||||
} catch (e) {
|
||||
writeLog(`[启动] 终止游戏进程异常: ${e.message}`);
|
||||
}
|
||||
currentGameProcess = null;
|
||||
currentGamePid = null;
|
||||
}
|
||||
|
||||
if (!killed) {
|
||||
writeLog('[启动] 未找到已保存的游戏进程,尝试通过命令行匹配查找Minecraft Java进程');
|
||||
findAndKillMinecraftJavaProcesses();
|
||||
}
|
||||
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('game-closed', -1);
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
|
|
@ -670,6 +743,7 @@ ipcMain.handle('check-for-updates', async () => {
|
|||
|
||||
https.get(url, (res) => {
|
||||
let data = '';
|
||||
res.setEncoding('utf8');
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
|
|
@ -694,16 +768,7 @@ ipcMain.handle('check-for-updates', async () => {
|
|||
|
||||
// 获取当前版本号(从package.json读取)
|
||||
ipcMain.handle('get-app-version', () => {
|
||||
try {
|
||||
const packagePath = path.join(__dirname, 'package.json');
|
||||
if (fs.existsSync(packagePath)) {
|
||||
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||
return pkg.version || '1.0.0';
|
||||
}
|
||||
} catch (e) {
|
||||
writeLog('[版本] 读取package.json失败: ' + e.message);
|
||||
}
|
||||
return '1.0.0';
|
||||
return APP_VERSION || app.getVersion() || '1.0.0';
|
||||
});
|
||||
|
||||
// 打开外部链接
|
||||
|
|
@ -2492,18 +2557,38 @@ ipcMain.handle('launch-minecraft', async (_, opt) => {
|
|||
}
|
||||
}
|
||||
|
||||
currentGameProcess = proc;
|
||||
currentGamePid = proc.pid;
|
||||
|
||||
// 如果已经被取消,立即杀死
|
||||
if (launchCancelFlag) {
|
||||
writeLog('[启动] 进程已启动但取消标志已设置,立即终止');
|
||||
killGameProcessTree(proc.pid);
|
||||
try { proc.kill(); } catch {}
|
||||
currentGameProcess = null;
|
||||
currentGamePid = null;
|
||||
return { success: false, error: '启动已取消', cancelled: true };
|
||||
}
|
||||
|
||||
// 检测游戏窗口创建成功
|
||||
await detectGameWindow(proc.pid);
|
||||
|
||||
// 检测结束后再次检查取消标志(可能在窗口检测期间被取消)
|
||||
if (launchCancelFlag) {
|
||||
writeLog('[启动] 窗口检测结束后检测到取消标志');
|
||||
return { success: false, error: '启动已取消', cancelled: true };
|
||||
}
|
||||
|
||||
// 捕获输出用于调试
|
||||
let stdoutData = '';
|
||||
let stderrData = '';
|
||||
proc.stdout?.on('data', d => {
|
||||
const text = d.toString();
|
||||
stdoutData += text;
|
||||
mainWindow.webContents.send('game-log', text);
|
||||
|
||||
// 检测Minecraft窗口创建成功的标志
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('game-log', text);
|
||||
}
|
||||
|
||||
if (text.includes('LWJGL Version') || text.includes('OpenGL version') || text.includes('Window')) {
|
||||
writeLog(`[启动] 检测到窗口初始化日志`);
|
||||
if (mainWindow) {
|
||||
|
|
@ -2514,9 +2599,10 @@ ipcMain.handle('launch-minecraft', async (_, opt) => {
|
|||
proc.stderr?.on('data', d => {
|
||||
const text = d.toString();
|
||||
stderrData += text;
|
||||
mainWindow.webContents.send('game-log', text);
|
||||
|
||||
// 检测Minecraft窗口创建成功的标志
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('game-log', text);
|
||||
}
|
||||
|
||||
if (text.includes('LWJGL Version') || text.includes('OpenGL version') || text.includes('Window')) {
|
||||
writeLog(`[启动] 检测到窗口初始化日志`);
|
||||
if (mainWindow) {
|
||||
|
|
@ -2532,6 +2618,13 @@ ipcMain.handle('launch-minecraft', async (_, opt) => {
|
|||
if (code !== 0 && stderrData) {
|
||||
writeLog(`[启动] 错误输出: ${stderrData.slice(0, 1000)}`);
|
||||
}
|
||||
if (currentGamePid === proc.pid) {
|
||||
currentGameProcess = null;
|
||||
currentGamePid = null;
|
||||
}
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('game-closed', code);
|
||||
}
|
||||
});
|
||||
|
||||
return { success: true, pid: proc.pid };
|
||||
|
|
@ -2555,9 +2648,15 @@ async function detectGameWindow(pid) {
|
|||
|
||||
const cancelCheck = setInterval(() => {
|
||||
if (launchCancelFlag) {
|
||||
writeLog(`[启动] 窗口检测期间检测到取消标志,立即退出`);
|
||||
writeLog(`[启动] 窗口检测期间检测到取消标志,立即终止游戏进程并退出`);
|
||||
clearInterval(cancelCheck);
|
||||
try { detector.kill(); } catch {}
|
||||
killGameProcessTree(pid);
|
||||
try {
|
||||
if (currentGameProcess) { currentGameProcess.kill(); }
|
||||
} catch {}
|
||||
currentGameProcess = null;
|
||||
currentGamePid = null;
|
||||
done();
|
||||
}
|
||||
}, 100);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "gpcl",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gpcl",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.5.17",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gpcl",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"description": "GoodPlanCraftLauncher",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* CaelLab BY-SA Code License
|
||||
* Copyright (c) 2026 Yunyun(云云) By 虚舟实验室(CaelLab) / CaelLabGameTS
|
||||
|
||||
|
|
@ -2424,10 +2424,7 @@ launchBtn.addEventListener('click', launchGame);
|
|||
checkUpdateBtn.classList.add('new-version');
|
||||
|
||||
if (updateStatus) {
|
||||
updateStatus.innerHTML = `
|
||||
<div class="update-log-title">发现 ${allNewerVersions.length} 个新版本!</div>
|
||||
${renderUpdateVersionCards(allNewerVersions)}
|
||||
`;
|
||||
updateStatus.innerHTML = `<div class="update-log-title">发现 ${allNewerVersions.length} 个新版本!</div>${renderUpdateVersionCards(allNewerVersions)}`;
|
||||
updateStatus.classList.add('show', 'has-update');
|
||||
}
|
||||
|
||||
|
|
@ -3055,22 +3052,12 @@ function renderUpdateVersionCards(newerVersions) {
|
|||
|
||||
const cards = newerVersions.map((v, index) => {
|
||||
const isNewest = index === newerVersions.length - 1;
|
||||
const titleHtml = v.title
|
||||
? `<div class="update-card-title">${v.title}</div>`
|
||||
: '';
|
||||
const logHtml = v.log
|
||||
? `<div class="update-card-log">${v.log}</div>`
|
||||
: '';
|
||||
return `
|
||||
<div class="update-version-card ${isNewest ? 'newest' : ''}">
|
||||
<div class="update-card-header">
|
||||
<span class="update-card-version">${v.version}</span>
|
||||
${isNewest ? '<span class="update-card-badge">最新</span>' : ''}
|
||||
</div>
|
||||
${titleHtml}
|
||||
${logHtml}
|
||||
</div>
|
||||
`;
|
||||
const titleHtml = v.title ? `<div class="update-card-title">${v.title}</div>` : '';
|
||||
const logHtml = v.log ? `<div class="update-card-log">${v.log}</div>` : '';
|
||||
return `<div class="update-version-card ${isNewest ? 'newest' : ''}">` +
|
||||
`<div class="update-card-header"><span class="update-card-version">${v.version}</span>` +
|
||||
`${isNewest ? '<span class="update-card-badge">最新</span>' : ''}</div>` +
|
||||
`${titleHtml}${logHtml}</div>`;
|
||||
}).reverse().join('');
|
||||
|
||||
return `<div class="update-versions-list">${cards}</div>`;
|
||||
|
|
@ -3101,7 +3088,7 @@ async function checkForUpdates(silent = false) {
|
|||
|
||||
allNewerVersions = parsedVersions
|
||||
.filter(v => compareVersions(currentVersion, v.version) > 0)
|
||||
.sort((a, b) => compareVersions(a.version, b.version));
|
||||
.sort((a, b) => compareVersions(b.version, a.version));
|
||||
|
||||
updateAvailable = allNewerVersions.length > 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue