feat: 환경에서 비 Windows 플랫폼의 SPT 설치 경로 확인 및 Git/LFS 설치 시뮬레이션 기능 추가
This commit is contained in:
parent
c78159d442
commit
ce6d43f597
187
src/main/main.ts
187
src/main/main.ts
|
|
@ -254,21 +254,21 @@ const checkGameRunning = async (): Promise<{ running: boolean; serverRunning: bo
|
||||||
let clientRunning = false;
|
let clientRunning = false;
|
||||||
|
|
||||||
for (const procName of GAME_PROCESS_NAMES) {
|
for (const procName of GAME_PROCESS_NAMES) {
|
||||||
if (output.includes(procName.toLowerCase())) {
|
if (output.includes(procName.toLowerCase())) {
|
||||||
runningProcesses.push(procName);
|
runningProcesses.push(procName);
|
||||||
if (SERVER_PROCESS_NAMES.includes(procName)) {
|
if (SERVER_PROCESS_NAMES.includes(procName)) {
|
||||||
serverRunning = true;
|
serverRunning = true;
|
||||||
} else if (CLIENT_PROCESS_NAMES.includes(procName)) {
|
} else if (CLIENT_PROCESS_NAMES.includes(procName)) {
|
||||||
clientRunning = true;
|
clientRunning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
running: runningProcesses.length > 0,
|
running: runningProcesses.length > 0,
|
||||||
serverRunning,
|
serverRunning,
|
||||||
clientRunning,
|
clientRunning,
|
||||||
processes: runningProcesses
|
processes: runningProcesses
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -670,7 +670,8 @@ const findSptInstallPath = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveSptInstall = async (): Promise<SptInstallInfo> => {
|
const resolveSptInstall = async (): Promise<SptInstallInfo> => {
|
||||||
if (process.platform !== "win32") {
|
const isDevUi = process.env.VITE_DEV_UI === "1";
|
||||||
|
if (process.platform !== "win32" && !isDevUi) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
checkedAt: Date.now(),
|
checkedAt: Date.now(),
|
||||||
|
|
@ -1007,11 +1008,79 @@ const runModSync = async (
|
||||||
const installGitTools = async (
|
const installGitTools = async (
|
||||||
onProgress?: (step: InstallStep) => void,
|
onProgress?: (step: InstallStep) => void,
|
||||||
): Promise<InstallGitToolsResult> => {
|
): Promise<InstallGitToolsResult> => {
|
||||||
|
const isDevUi = process.env.VITE_DEV_UI === "1";
|
||||||
|
|
||||||
if (process.platform !== "win32") {
|
if (process.platform !== "win32") {
|
||||||
|
if (!isDevUi) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
error: "Windows에서만 자동 설치가 가능합니다.",
|
||||||
|
steps: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mac/Linux Dev UI Simulation
|
||||||
|
const steps: InstallStep[] = [];
|
||||||
|
const totalSteps = 3;
|
||||||
|
const emitProgress = (
|
||||||
|
name: string,
|
||||||
|
current: number,
|
||||||
|
status: InstallStep["status"],
|
||||||
|
) => {
|
||||||
|
const percent = Math.round((current / totalSteps) * 100);
|
||||||
|
onProgress?.({
|
||||||
|
name,
|
||||||
|
ok: status !== "error",
|
||||||
|
status,
|
||||||
|
progress: { current, total: totalSteps, percent },
|
||||||
|
result: { ok: true, command: "simulated", args: [] }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
emitProgress("winget 확인", 1, "running");
|
||||||
|
await new Promise(r => setTimeout(r, 500));
|
||||||
|
const wingetStep: InstallStep = {
|
||||||
|
name: "winget 확인",
|
||||||
|
ok: true,
|
||||||
|
status: "done",
|
||||||
|
progress: { current: 1, total: totalSteps, percent: 33 },
|
||||||
|
result: { ok: true, command: "simulated", args: [] }
|
||||||
|
};
|
||||||
|
steps.push(wingetStep);
|
||||||
|
onProgress?.(wingetStep);
|
||||||
|
|
||||||
|
emitProgress("Git 설치", 2, "running");
|
||||||
|
await new Promise(r => setTimeout(r, 800));
|
||||||
|
const gitInstallStep: InstallStep = {
|
||||||
|
name: "Git 설치",
|
||||||
|
ok: true,
|
||||||
|
status: "done",
|
||||||
|
progress: { current: 2, total: totalSteps, percent: 67 },
|
||||||
|
result: { ok: true, command: "simulated", args: [] }
|
||||||
|
};
|
||||||
|
steps.push(gitInstallStep);
|
||||||
|
onProgress?.(gitInstallStep);
|
||||||
|
|
||||||
|
emitProgress("Git LFS 설치", 3, "running");
|
||||||
|
await new Promise(r => setTimeout(r, 800));
|
||||||
|
const lfsInstallStep: InstallStep = {
|
||||||
|
name: "Git LFS 설치",
|
||||||
|
ok: true,
|
||||||
|
status: "done",
|
||||||
|
progress: { current: 3, total: totalSteps, percent: 100 },
|
||||||
|
result: { ok: true, command: "simulated", args: [] }
|
||||||
|
};
|
||||||
|
steps.push(lfsInstallStep);
|
||||||
|
onProgress?.(lfsInstallStep);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: true,
|
||||||
error: "Windows에서만 자동 설치가 가능합니다.",
|
steps,
|
||||||
steps: [],
|
check: {
|
||||||
|
git: { ok: true, command: "git", version: "simulated" },
|
||||||
|
lfs: { ok: true, command: "git", lfs: "simulated" } as any,
|
||||||
|
checkedAt: Date.now()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1436,13 +1505,13 @@ app.whenReady().then(() => {
|
||||||
// Double check running processes
|
// Double check running processes
|
||||||
const running = await checkGameRunning();
|
const running = await checkGameRunning();
|
||||||
if (running.clientRunning) {
|
if (running.clientRunning) {
|
||||||
return { ok: false, error: "already_running", details: running.processes };
|
return { ok: false, error: "already_running", details: running.processes };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double check mod version (optional but safer)
|
// Double check mod version (optional but safer)
|
||||||
const modStatus = await getModVersionStatus();
|
const modStatus = await getModVersionStatus();
|
||||||
if (!modStatus.ok) {
|
if (!modStatus.ok) {
|
||||||
return { ok: false, error: "mod_verification_failed" };
|
return { ok: false, error: "mod_verification_failed" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch Server if not running (Local only)
|
// Launch Server if not running (Local only)
|
||||||
|
|
@ -1450,45 +1519,45 @@ app.whenReady().then(() => {
|
||||||
const isLocal = serverUrl.hostname === "127.0.0.1" || serverUrl.hostname === "localhost";
|
const isLocal = serverUrl.hostname === "127.0.0.1" || serverUrl.hostname === "localhost";
|
||||||
|
|
||||||
if (isLocal && !running.serverRunning) {
|
if (isLocal && !running.serverRunning) {
|
||||||
let serverExePath: string | undefined;
|
let serverExePath: string | undefined;
|
||||||
for (const exe of SERVER_PROCESS_NAMES) {
|
for (const exe of SERVER_PROCESS_NAMES) {
|
||||||
// Check direct path or SPT subdirectory
|
// Check direct path or SPT subdirectory
|
||||||
const direct = path.join(installInfo.path, exe);
|
const direct = path.join(installInfo.path, exe);
|
||||||
if (await pathExists(direct)) {
|
if (await pathExists(direct)) {
|
||||||
serverExePath = direct;
|
serverExePath = direct;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
const nested = path.join(installInfo.path, "SPT", exe);
|
|
||||||
if (await pathExists(nested)) {
|
|
||||||
serverExePath = nested;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const nested = path.join(installInfo.path, "SPT", exe);
|
||||||
if (serverExePath) {
|
if (await pathExists(nested)) {
|
||||||
console.log(`[spt-launcher] Starting Server: ${serverExePath}`);
|
serverExePath = nested;
|
||||||
const serverBat = stripExe(serverExePath) + ".bat"; // Sometimes users use bat, but exe should work if arguments aren't complex
|
break;
|
||||||
|
|
||||||
// Prefer EXE for now.
|
|
||||||
const child = require("child_process").spawn(serverExePath, [], {
|
|
||||||
cwd: path.dirname(serverExePath),
|
|
||||||
detached: true,
|
|
||||||
stdio: "ignore"
|
|
||||||
});
|
|
||||||
child.unref();
|
|
||||||
|
|
||||||
// Wait for server health
|
|
||||||
let attempts = 0;
|
|
||||||
const maxAttempts = 30; // 30 seconds approx
|
|
||||||
while(attempts < maxAttempts) {
|
|
||||||
const health = await checkServerHealth();
|
|
||||||
if (health.ok) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
await new Promise(r => setTimeout(r, 1000));
|
|
||||||
attempts++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverExePath) {
|
||||||
|
console.log(`[spt-launcher] Starting Server: ${serverExePath}`);
|
||||||
|
const serverBat = stripExe(serverExePath) + ".bat"; // Sometimes users use bat, but exe should work if arguments aren't complex
|
||||||
|
|
||||||
|
// Prefer EXE for now.
|
||||||
|
const child = require("child_process").spawn(serverExePath, [], {
|
||||||
|
cwd: path.dirname(serverExePath),
|
||||||
|
detached: true,
|
||||||
|
stdio: "ignore"
|
||||||
|
});
|
||||||
|
child.unref();
|
||||||
|
|
||||||
|
// Wait for server health
|
||||||
|
let attempts = 0;
|
||||||
|
const maxAttempts = 30; // 30 seconds approx
|
||||||
|
while (attempts < maxAttempts) {
|
||||||
|
const health = await checkServerHealth();
|
||||||
|
if (health.ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch Client
|
// Launch Client
|
||||||
|
|
@ -1511,7 +1580,7 @@ app.whenReady().then(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!executablePath) {
|
if (!executablePath) {
|
||||||
return { ok: false, error: "executable_not_found" };
|
return { ok: false, error: "executable_not_found" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Session ID for args
|
// Get Session ID for args
|
||||||
|
|
@ -1533,7 +1602,7 @@ app.whenReady().then(() => {
|
||||||
const sanitizedEnv = { ...process.env };
|
const sanitizedEnv = { ...process.env };
|
||||||
for (const key of Object.keys(sanitizedEnv)) {
|
for (const key of Object.keys(sanitizedEnv)) {
|
||||||
if (key.startsWith("ELECTRON_") || key.startsWith("NODE_") || key === "VITE_DEV_SERVER_URL") {
|
if (key.startsWith("ELECTRON_") || key.startsWith("NODE_") || key === "VITE_DEV_SERVER_URL") {
|
||||||
delete sanitizedEnv[key];
|
delete sanitizedEnv[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1554,9 +1623,9 @@ app.whenReady().then(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function stripExe(filename: string) {
|
function stripExe(filename: string) {
|
||||||
return filename.replace(/\.exe$/i, "");
|
return filename.replace(/\.exe$/i, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle("spt:checkGameRunning", async () => {
|
ipcMain.handle("spt:checkGameRunning", async () => {
|
||||||
return await checkGameRunning();
|
return await checkGameRunning();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue