mirror of
https://github.com/open-goal/launcher.git
synced 2024-10-20 04:57:38 -04:00
setup: check requirements in the frontend
This commit is contained in:
parent
efd7a5daad
commit
95eb86cfb2
|
@ -159,6 +159,7 @@ body {
|
|||
height: 100vh;
|
||||
width: 90vw;
|
||||
max-width: 90vw;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
|
@ -271,3 +272,21 @@ body {
|
|||
details > summary:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.progress-row a {
|
||||
text-decoration: none;
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
.progress-row a:hover {
|
||||
color: #ffbd42;
|
||||
}
|
||||
|
||||
.orange-text {
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
ul.no-decoration {
|
||||
list-style-type: none;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { Command } from "@tauri-apps/api/shell";
|
||||
import { resourceDir } from "@tauri-apps/api/path";
|
||||
import { os } from "@tauri-apps/api";
|
||||
import { getHighestSimd } from "/src/lib/commands";
|
||||
|
||||
export class InstallationStatus {
|
||||
static Pending = Symbol("pending");
|
||||
|
@ -8,6 +10,13 @@ export class InstallationStatus {
|
|||
static Success = Symbol("success");
|
||||
}
|
||||
|
||||
export class RequirementStatus {
|
||||
static Unknown = Symbol("unknown");
|
||||
static Met = Symbol("met");
|
||||
static Failed = Symbol("failed");
|
||||
static Checking = Symbol("checking");
|
||||
}
|
||||
|
||||
// TODO - is this set to `production` properly in release mode?
|
||||
function isInDebugMode() {
|
||||
return process.env.NODE_ENV === "development";
|
||||
|
@ -21,6 +30,35 @@ if (isInDebugMode()) {
|
|||
debugPath += "\\launcher\\bundle-test\\data";
|
||||
}
|
||||
|
||||
export async function isAVXSupported() {
|
||||
let highestSIMD = await getHighestSimd();
|
||||
if (highestSIMD === undefined) {
|
||||
return RequirementStatus.Unknown;
|
||||
}
|
||||
if (highestSIMD.toLowerCase().startsWith("avx")) {
|
||||
return RequirementStatus.Met
|
||||
}
|
||||
return RequirementStatus.Failed;
|
||||
}
|
||||
|
||||
export async function isOpenGLVersionSupported(version) {
|
||||
// TODO - glewinfo not pre-compiled to work on linux yet!
|
||||
if (await os.platform() === "linux" || await os.platform() === "darwin") {
|
||||
return RequirementStatus.Unknown;
|
||||
}
|
||||
// Otherwise, query for the version
|
||||
let command = Command.sidecar("bin/glewinfo", ["-version", version], { cwd: "bin" });
|
||||
try {
|
||||
let output = await command.execute();
|
||||
if (output.code === 0) {
|
||||
return RequirementStatus.Met;
|
||||
}
|
||||
return RequirementStatus.Failed;
|
||||
} catch {
|
||||
return RequirementStatus.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} filePath
|
||||
* @returns {Promise<ChildProcess>}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { Link, navigate } from "svelte-routing";
|
||||
import { filePrompt } from "/src/lib/utils/file";
|
||||
import {
|
||||
|
@ -6,9 +7,11 @@
|
|||
decompileGameData,
|
||||
extractISO,
|
||||
validateGameData,
|
||||
isAVXSupported,
|
||||
isOpenGLVersionSupported,
|
||||
} from "/src/lib/setup";
|
||||
import { SupportedGame, setInstallStatus } from "/src/lib/config";
|
||||
import { InstallationStatus } from "/src/lib/setup";
|
||||
import { InstallationStatus, RequirementStatus } from "/src/lib/setup";
|
||||
import {
|
||||
appendToInstallLog,
|
||||
appendToInstallErrorLog,
|
||||
|
@ -18,6 +21,19 @@
|
|||
let setupInProgress = false;
|
||||
let isoPath = undefined;
|
||||
|
||||
let requirementChecks = [
|
||||
{
|
||||
status: RequirementStatus.Checking,
|
||||
text: `CPU Supports <a href="https://en.wikipedia.org/wiki/Advanced_Vector_Extensions"><strong>AVX or AVX2</strong></a>`,
|
||||
check: async () => await isAVXSupported(),
|
||||
},
|
||||
{
|
||||
status: RequirementStatus.Checking,
|
||||
text: `GPU Supports OpenGL <span class="orange-text"><strong>4.3</strong></span>`,
|
||||
check: async () => await isOpenGLVersionSupported("4.3"),
|
||||
},
|
||||
];
|
||||
|
||||
let currStep = 0;
|
||||
let installSteps = [
|
||||
{
|
||||
|
@ -46,18 +62,42 @@
|
|||
},
|
||||
];
|
||||
|
||||
// TODO - move this to the enum
|
||||
function statusIndicator(status) {
|
||||
if (status === InstallationStatus.InProgress) {
|
||||
return `spinner`;
|
||||
} else if (status === InstallationStatus.Success) {
|
||||
if (
|
||||
status === InstallationStatus.InProgress ||
|
||||
status === RequirementStatus.Checking
|
||||
) {
|
||||
return `<div class="loader" />`;
|
||||
} else if (
|
||||
status === InstallationStatus.Success ||
|
||||
status === RequirementStatus.Met
|
||||
) {
|
||||
return "✅";
|
||||
} else if (status === InstallationStatus.Failed) {
|
||||
} else if (
|
||||
status === InstallationStatus.Failed ||
|
||||
status === RequirementStatus.Failed
|
||||
) {
|
||||
return "❌";
|
||||
} else if (status === RequirementStatus.Unknown) {
|
||||
return "⚠️";
|
||||
} else {
|
||||
return "⏳";
|
||||
}
|
||||
}
|
||||
|
||||
function areRequirementsMet(checks) {
|
||||
for (let i = 0; i < checks.length; i++) {
|
||||
if (
|
||||
checks[i].status !== RequirementStatus.Met &&
|
||||
checks[i].status !== RequirementStatus.Unknown
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function finishStep(output) {
|
||||
appendLogs(output);
|
||||
installSteps[currStep].status =
|
||||
|
@ -72,7 +112,10 @@
|
|||
|
||||
async function appendLogs(output) {
|
||||
const separator = `----${installSteps[currStep].text}----\n`;
|
||||
await appendToInstallLog(SupportedGame.Jak1, "\n" + separator + output.stdout);
|
||||
await appendToInstallLog(
|
||||
SupportedGame.Jak1,
|
||||
"\n" + separator + output.stdout
|
||||
);
|
||||
await appendToInstallErrorLog(
|
||||
SupportedGame.Jak1,
|
||||
"\n" + separator + output.stderr
|
||||
|
@ -111,6 +154,12 @@
|
|||
}
|
||||
|
||||
// Events
|
||||
onMount(async () => {
|
||||
for (let i = 0; i < requirementChecks.length; i++) {
|
||||
requirementChecks[i].status = await requirementChecks[i].check();
|
||||
}
|
||||
});
|
||||
|
||||
async function onClickBrowse() {
|
||||
isoPath = await filePrompt();
|
||||
installProcess();
|
||||
|
@ -119,54 +168,68 @@
|
|||
|
||||
<div class="content">
|
||||
<h1>Setup Process</h1>
|
||||
<p>Browse for your ISO - Obtained by dumping your own legitimate copy</p>
|
||||
<div>
|
||||
<button class="btn" on:click={onClickBrowse}>Browse for ISO</button>
|
||||
{#if isoPath}
|
||||
{isoPath}
|
||||
{/if}
|
||||
<span id="filePathLabel" />
|
||||
</div>
|
||||
{#if !setupInProgress}
|
||||
<div class="row">
|
||||
<Link to="/jak1">
|
||||
<button class="btn">Cancel</button>
|
||||
</Link>
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
<h2>Progress</h2>
|
||||
<ul>
|
||||
{#each installSteps as step}
|
||||
<li>
|
||||
<span class="progress-row">
|
||||
{#if step.status === InstallationStatus.InProgress}
|
||||
<div class="loader" />
|
||||
{:else}
|
||||
{statusIndicator(step.status)}
|
||||
{/if}
|
||||
{step.text}
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row">
|
||||
<details>
|
||||
<summary>Installation Logs</summary>
|
||||
<div class="logContainer">
|
||||
{#each installSteps as step}
|
||||
{#if step.logs !== ""}
|
||||
{step.logs}
|
||||
{/if}
|
||||
{#if step.errorLogs !== ""}
|
||||
<div class="errorLogs">
|
||||
{step.errorLogs}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
<h2>Minimum Requirements</h2>
|
||||
<ul class="no-decoration">
|
||||
{#each requirementChecks as check}
|
||||
<li>
|
||||
<span class="progress-row">
|
||||
{@html statusIndicator(check.status)}
|
||||
{@html check.text}
|
||||
</span>
|
||||
{#if check.status === RequirementStatus.Unknown}
|
||||
<ul class="no-decoration">
|
||||
<li>Unable to determine this requirement</li>
|
||||
</ul>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{#if areRequirementsMet(requirementChecks)}
|
||||
<p>Browse for your ISO - Obtained by dumping your own legitimate copy</p>
|
||||
<div>
|
||||
<button class="btn" on:click={onClickBrowse}>Browse for ISO</button>
|
||||
{#if isoPath}
|
||||
{isoPath}
|
||||
{/if}
|
||||
<span id="filePathLabel" />
|
||||
</div>
|
||||
{#if !setupInProgress}
|
||||
<div class="row">
|
||||
<Link to="/jak1">
|
||||
<button class="btn">Cancel</button>
|
||||
</Link>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
<h2>Progress</h2>
|
||||
<ul class="no-decoration">
|
||||
{#each installSteps as step}
|
||||
<li>
|
||||
<span class="progress-row">
|
||||
{@html statusIndicator(step.status)}
|
||||
{step.text}
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row">
|
||||
<details>
|
||||
<summary>Installation Logs</summary>
|
||||
<div class="logContainer">
|
||||
{#each installSteps as step}
|
||||
{#if step.logs !== ""}
|
||||
{step.logs}
|
||||
{/if}
|
||||
{#if step.errorLogs !== ""}
|
||||
<div class="errorLogs">
|
||||
{step.errorLogs}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue