mirror of
https://github.com/open-goal/launcher.git
synced 2024-10-20 19:07:36 -04:00
frontend: wire up controls for interacting with the game
This commit is contained in:
parent
5513d99608
commit
e2b284515f
|
@ -6,7 +6,6 @@
|
|||
import Settings from "./routes/Settings.svelte";
|
||||
import Sidebar from "./components/sidebar/Sidebar.svelte";
|
||||
import Background from "./components/background/Background.svelte";
|
||||
import { isInDebugMode } from "$lib/setup/setup";
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
import { isInstalling } from "./lib/stores/AppStore";
|
||||
import { log } from "$lib/utils/log";
|
||||
|
@ -15,6 +14,7 @@
|
|||
import Textures from "./routes/Textures.svelte";
|
||||
import Update from "./routes/Update.svelte";
|
||||
import GameInProgress from "./components/games/GameInProgress.svelte";
|
||||
import { isInDebugMode } from "$lib/utils/common";
|
||||
|
||||
let revokeSpecificActions = false;
|
||||
|
||||
|
@ -75,7 +75,12 @@
|
|||
<Route path="/" component={Game} primary={false} let:params />
|
||||
<Route path="/:game_name" component={Game} primary={false} let:params />
|
||||
<Route path="/jak2" component={GameInProgress} primary={false} let:params />
|
||||
<Route path="/settings/:tab" component={Settings} primary={false} let:params />
|
||||
<Route
|
||||
path="/settings/:tab"
|
||||
component={Settings}
|
||||
primary={false}
|
||||
let:params
|
||||
/>
|
||||
<Route path="/faq" component={Faq} primary={false} />
|
||||
<Route path="/textures" component={Textures} primary={false} />
|
||||
<Route path="/update" component={Update} primary={false} />
|
||||
|
|
|
@ -1,99 +1,46 @@
|
|||
<script type="ts">
|
||||
import { launcherConfig } from "$lib/config";
|
||||
import { getGameTitle, getInternalName, SupportedGame } from "$lib/constants";
|
||||
import { launchGameInDebug } from "$lib/launch";
|
||||
import { openDir, openREPL } from "$lib/rpc/commands";
|
||||
import { uninstallGame } from "$lib/setup/setup";
|
||||
import { openDir } from "$lib/rpc/commands";
|
||||
import Icon from "@iconify/svelte";
|
||||
import { appDir, configDir, join } from "@tauri-apps/api/path";
|
||||
import { configDir, join } from "@tauri-apps/api/path";
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import {
|
||||
isCompiling,
|
||||
isDecompiling,
|
||||
ProcessLogs,
|
||||
} from "$lib/stores/AppStore";
|
||||
import { link } from "svelte-navigator";
|
||||
|
||||
import { isCompiling, isDecompiling } from "$lib/stores/AppStore";
|
||||
import { confirm } from "@tauri-apps/api/dialog";
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Chevron,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownDivider,
|
||||
Spinner,
|
||||
Helper,
|
||||
} from "flowbite-svelte";
|
||||
import { launchGame } from "$lib/rpc/game";
|
||||
import { launchGame, uninstallGame } from "$lib/rpc/game";
|
||||
|
||||
export let activeGame: SupportedGame;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
let componentLoaded = false;
|
||||
let configPath = undefined;
|
||||
let screenshotsPath = undefined;
|
||||
let settingsDir = undefined;
|
||||
let savesDir = undefined;
|
||||
|
||||
onMount(async () => {
|
||||
configPath = await join(
|
||||
settingsDir = await join(
|
||||
await configDir(),
|
||||
"OpenGOAL",
|
||||
getInternalName(activeGame)
|
||||
getInternalName(activeGame),
|
||||
"settings"
|
||||
);
|
||||
|
||||
screenshotsPath = await join(
|
||||
savesDir = await join(
|
||||
await configDir(),
|
||||
"OpenGOAL-Launcher/data/screenshots"
|
||||
"OpenGOAL",
|
||||
getInternalName(activeGame),
|
||||
"saves"
|
||||
);
|
||||
componentLoaded = true;
|
||||
});
|
||||
|
||||
function onClickPlay() {
|
||||
launchGame("jak1");
|
||||
}
|
||||
|
||||
async function onClickOpenREPL() {
|
||||
await openREPL();
|
||||
}
|
||||
|
||||
function onClickBootDebug() {
|
||||
launchGameInDebug();
|
||||
}
|
||||
|
||||
async function onClickUninstall() {
|
||||
const confirmed = await confirm("Are you sure you want to uninstall?");
|
||||
if (confirmed) {
|
||||
await launcherConfig.setInstallStatus(activeGame, false);
|
||||
await uninstallGame(activeGame);
|
||||
dispatch("change");
|
||||
}
|
||||
}
|
||||
|
||||
async function onClickDecompile() {
|
||||
ProcessLogs.update(() => "");
|
||||
const isoPath = await join(
|
||||
await appDir(),
|
||||
"data",
|
||||
"iso_data",
|
||||
getInternalName(activeGame)
|
||||
);
|
||||
// await decompileGameData(isoPath);
|
||||
}
|
||||
|
||||
async function onClickCompile() {
|
||||
ProcessLogs.update(() => "");
|
||||
const isoPath = await join(
|
||||
await appDir(),
|
||||
"data",
|
||||
"iso_data",
|
||||
getInternalName(activeGame)
|
||||
);
|
||||
// await compileGame(isoPath);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- TODO - texture replacements left out for now, get everything else working end-to-end first -->
|
||||
<!-- TOOO - time played -->
|
||||
|
||||
<div class="flex flex-col justify-end items-end mt-auto">
|
||||
<!-- TOOO - time played -->
|
||||
<h1
|
||||
class="tracking-tighter text-2xl font-bold pb-3 text-orange-500 text-outline pointer-events-none"
|
||||
>
|
||||
|
@ -102,89 +49,83 @@
|
|||
<div class="flex flex-row gap-2">
|
||||
<Button
|
||||
btnClass="border-solid border-2 border-slate-900 rounded bg-slate-900 hover:bg-slate-800 text-sm text-white font-semibold px-5 py-2"
|
||||
on:click={onClickPlay}
|
||||
on:click={async () => {
|
||||
launchGame(getInternalName(activeGame), false);
|
||||
}}
|
||||
disabled={$isDecompiling || $isCompiling}>Play</Button
|
||||
>
|
||||
<Button
|
||||
<!-- TODO - texture replacements left out for now, get everything else working end-to-end first -->
|
||||
<!-- <Button
|
||||
btnClass="text-center font-semibold focus:ring-0 focus:outline-none inline-flex items-center justify-center px-5 py-2 text-sm text-white border-solid border-2 border-slate-900 rounded bg-slate-900 hover:bg-slate-800"
|
||||
><Chevron placement="top">Features</Chevron></Button
|
||||
>
|
||||
<Dropdown placement="top">
|
||||
<DropdownItem>Dashboard</DropdownItem>
|
||||
<DropdownDivider />
|
||||
<DropdownItem>Settings</DropdownItem>
|
||||
<DropdownItem>Earnings</DropdownItem>
|
||||
<DropdownItem slot="footer">Separated link</DropdownItem>
|
||||
</Dropdown>
|
||||
<Dropdown placement="top-end">
|
||||
<DropdownItem>Texture Replacements</DropdownItem>
|
||||
</Dropdown> -->
|
||||
<Button
|
||||
btnClass="text-center font-semibold focus:ring-0 focus:outline-none inline-flex items-center justify-center px-2 py-2 text-sm text-white border-solid border-2 border-slate-900 rounded bg-slate-900 hover:bg-slate-800"
|
||||
>
|
||||
<Icon icon="material-symbols:settings" width={24} height={24} />
|
||||
</Button
|
||||
>
|
||||
<Icon icon="material-symbols:settings" width={24} height={24} />
|
||||
</Button>
|
||||
<Dropdown placement="top-end" frameClass="mr-1">
|
||||
<DropdownItem>Dashboard</DropdownItem>
|
||||
<DropdownItem
|
||||
on:click={async () => {
|
||||
launchGame(getInternalName(activeGame), true);
|
||||
}}>Play in Debug Mode</DropdownItem
|
||||
>
|
||||
<DropdownDivider />
|
||||
<DropdownItem>Settings</DropdownItem>
|
||||
<DropdownItem>Earnings</DropdownItem>
|
||||
<DropdownItem slot="footer">Separated link</DropdownItem>
|
||||
<!-- TODO - screenshot folder? how do we even configure where those go? -->
|
||||
<DropdownItem
|
||||
on:click={async () => {
|
||||
await openDir(settingsDir);
|
||||
}}>Open Settings Folder</DropdownItem
|
||||
>
|
||||
<DropdownItem
|
||||
on:click={async () => {
|
||||
await openDir(savesDir);
|
||||
}}>Open Saves Folder</DropdownItem
|
||||
>
|
||||
<DropdownDivider />
|
||||
<DropdownItem
|
||||
on:click={async () => {
|
||||
await openDir(settingsDir);
|
||||
}}
|
||||
>Decompile
|
||||
<!-- NOTE - this is a bug in flowbite-svelte, it's not replacing the default class but just appending -->
|
||||
<Helper helperClass="!text-neutral-400 !text-xs"
|
||||
>Extracts game assets (ie. to apply texture replacements)</Helper
|
||||
></DropdownItem
|
||||
>
|
||||
<DropdownItem
|
||||
on:click={async () => {
|
||||
await openDir(settingsDir);
|
||||
}}
|
||||
>Compile
|
||||
<!-- NOTE - this is a bug in flowbite-svelte, it's not replacing the default class but just appending -->
|
||||
<Helper helperClass="!text-neutral-400 !text-xs"
|
||||
>Rebuild the game. (ie. after modifying OpenGOAL source code)</Helper
|
||||
></DropdownItem
|
||||
>
|
||||
<DropdownDivider />
|
||||
<!-- TODO - verify installation -->
|
||||
<!-- <DropdownItem>Verify Install</DropdownItem> -->
|
||||
<DropdownItem
|
||||
on:click={async () => {
|
||||
// Get confirmation
|
||||
// TODO - probably move these confirms into the actual launcher itself
|
||||
const confirmed = await confirm(
|
||||
"Are you sure you want to uninstall?",
|
||||
{ title: "OpenGOAL Launcher", type: "warning" }
|
||||
);
|
||||
if (confirmed) {
|
||||
await uninstallGame(getInternalName(activeGame));
|
||||
dispatch("change");
|
||||
}
|
||||
}}
|
||||
>Uninstall<Helper helperClass="!text-neutral-400 !text-xs"
|
||||
>This will not delete any saves or settings</Helper
|
||||
></DropdownItem
|
||||
>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- {#if componentLoaded}
|
||||
<ButtonGroup>
|
||||
{#if $isDecompiling || $isCompiling}
|
||||
<Spinner class="min-h-full mx-2" />
|
||||
{/if}
|
||||
<Button
|
||||
class="w-56 !rounded-none !bg-[#222222] border-none !text-white hover:!text-blue-500 !text-2xl"
|
||||
on:click={onClickPlay}
|
||||
disabled={$isDecompiling || $isCompiling}>Play</Button
|
||||
>
|
||||
|
||||
<Button disabled={$isDecompiling || $isCompiling}
|
||||
><Chevron placement="top">Extras</Chevron></Button
|
||||
>
|
||||
<Dropdown class="!rounded-none" placement="top">
|
||||
{#if !($isDecompiling || $isCompiling)}
|
||||
<DropdownItem href="#" on:click={onClickBootDebug}
|
||||
>Boot In Debug</DropdownItem
|
||||
>
|
||||
{/if}
|
||||
<DropdownItem href="#" on:click={onClickOpenREPL}>Open REPL</DropdownItem>
|
||||
<DropdownDivider />
|
||||
<!-- NOTE: Wrapped these two dropdown items in a tags for the use:link, otherwise the dropdownitem doesnt support it -->
|
||||
<!-- <a use:link href="/textures"><DropdownItem>Texture Packs</DropdownItem></a
|
||||
>
|
||||
<!-- <a use:link href="/mods">
|
||||
<DropdownItem>Mods</DropdownItem>
|
||||
</a> -->
|
||||
<!-- </Dropdown>
|
||||
|
||||
<Button class="!rounded-none" disabled={$isDecompiling || $isCompiling}
|
||||
><Chevron placement="top"><i class="fa fa-cog" /></Chevron></Button
|
||||
>
|
||||
<Dropdown class="!rounded-none" placement="top">
|
||||
<DropdownItem href="#" on:click={() => openDir(configPath)}
|
||||
>Open Settings & Saves</DropdownItem
|
||||
>
|
||||
<DropdownItem href="#" on:click={() => openDir(screenshotsPath)}
|
||||
>Open Screenshots Directory</DropdownItem
|
||||
>
|
||||
{#if !($isDecompiling || $isCompiling)}
|
||||
<DropdownDivider />
|
||||
<DropdownItem href="#" on:click={async () => await onClickDecompile()}
|
||||
>Decompile</DropdownItem
|
||||
>
|
||||
<DropdownItem href="#" on:click={async () => await onClickCompile()}
|
||||
>Compile</DropdownItem
|
||||
>
|
||||
<DropdownDivider />
|
||||
<DropdownItem href="#" color="red" on:click={() => onClickUninstall()}
|
||||
>Uninstall</DropdownItem
|
||||
>
|
||||
{/if}
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
{/if} -->
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<div class="ml-20">
|
||||
<!-- TODO - the static height here is kinda a hack, it's because the
|
||||
header and the rest of the layout aren't within a shared container -->
|
||||
<div
|
||||
class="flex flex-col h-[544px] justify-center items-center p-5 text-center"
|
||||
>
|
||||
<h1 class="text-2xl font-black mb-5">Jak 2 is Currently in Development</h1>
|
||||
<p class="mb-10">
|
||||
In the meantime, check out our latest progress reports showcasing what
|
||||
we've accomplished so far
|
||||
</p>
|
||||
<a
|
||||
class="font-bold text-orange-400 hover:text-orange-600"
|
||||
href="https://opengoal.dev/blog/tags/progress-report"
|
||||
target="_blank"
|
||||
rel="noreferrer">Progress Reports</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-20">
|
||||
<!-- TODO - the static height here is kinda a hack, it's because the
|
||||
header and the rest of the layout aren't within a shared container -->
|
||||
<div
|
||||
class="flex flex-col h-[544px] justify-center items-center p-5 text-center"
|
||||
>
|
||||
<h1 class="text-2xl font-black mb-5">Jak 2 is Currently in Development</h1>
|
||||
<p class="mb-10">
|
||||
In the meantime, check out our latest progress reports showcasing what
|
||||
we've accomplished so far
|
||||
</p>
|
||||
<a
|
||||
class="font-bold text-orange-400 hover:text-orange-600"
|
||||
href="https://opengoal.dev/blog/tags/progress-report"
|
||||
target="_blank"
|
||||
rel="noreferrer">Progress Reports</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -59,11 +59,8 @@ body {
|
|||
}
|
||||
|
||||
.text-outline {
|
||||
text-shadow:
|
||||
-1px -1px 0 #000,
|
||||
1px -1px 0 #000,
|
||||
-1px 1px 0 #000,
|
||||
1px 1px 0 #000;
|
||||
text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000,
|
||||
1px 1px 0 #000;
|
||||
}
|
||||
|
||||
.log-accordian > div > div.p-5 {
|
||||
|
|
|
@ -1,255 +0,0 @@
|
|||
import { createDir, readTextFile, writeFile } from "@tauri-apps/api/fs";
|
||||
import { appDir, join } from "@tauri-apps/api/path";
|
||||
import { SupportedGame } from "./constants";
|
||||
import { fileExists } from "./utils/file";
|
||||
import { log } from "./utils/log";
|
||||
|
||||
interface Serializable<T> {
|
||||
deserialize(input: Object): T;
|
||||
}
|
||||
|
||||
class GameConfig implements Serializable<GameConfig> {
|
||||
isInstalled: boolean = false;
|
||||
version: string = null;
|
||||
|
||||
deserialize(json: JSON): GameConfig {
|
||||
this.isInstalled = json["isInstalled"];
|
||||
this.version = json["version"];
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class GameRequirements implements Serializable<GameRequirements> {
|
||||
avx: boolean | null = null;
|
||||
openGL: boolean | null = null;
|
||||
|
||||
deserialize(json: JSON): GameRequirements {
|
||||
this.avx = json["avx"];
|
||||
this.openGL = json["openGL"];
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class LauncherConfig implements Serializable<LauncherConfig> {
|
||||
version: string | null = "1.0";
|
||||
requirements: GameRequirements = new GameRequirements();
|
||||
games = {
|
||||
[SupportedGame.Jak1]: new GameConfig(),
|
||||
[SupportedGame.Jak2]: new GameConfig(),
|
||||
[SupportedGame.Jak3]: new GameConfig(),
|
||||
[SupportedGame.JakX]: new GameConfig(),
|
||||
};
|
||||
lastActiveGame: SupportedGame | null;
|
||||
|
||||
private _loaded: boolean = false;
|
||||
|
||||
deserialize(json: JSON): LauncherConfig {
|
||||
this.version = json["version"];
|
||||
this.requirements = new GameRequirements().deserialize(
|
||||
json["requirements"]
|
||||
);
|
||||
this.games[SupportedGame.Jak1] = new GameConfig().deserialize(
|
||||
json["games"][SupportedGame.Jak1]
|
||||
);
|
||||
this.games[SupportedGame.Jak2] = new GameConfig().deserialize(
|
||||
json["games"][SupportedGame.Jak2]
|
||||
);
|
||||
this.games[SupportedGame.Jak3] = new GameConfig().deserialize(
|
||||
json["games"][SupportedGame.Jak3]
|
||||
);
|
||||
this.games[SupportedGame.JakX] = new GameConfig().deserialize(
|
||||
json["games"][SupportedGame.JakX]
|
||||
);
|
||||
this.lastActiveGame = json["lastActiveGame"];
|
||||
return this;
|
||||
}
|
||||
|
||||
private async loadConfigFromFile() {
|
||||
if (this._loaded) {
|
||||
return;
|
||||
}
|
||||
const configPath = await join(await appDir(), "settings.json");
|
||||
const configExists = await fileExists(configPath);
|
||||
if (!configExists) {
|
||||
console.log(
|
||||
`[Launcher]: Settings file not found at '${configPath}, initializing with defaults!`
|
||||
);
|
||||
await createDir(await appDir(), { recursive: true });
|
||||
await writeFile({
|
||||
contents: JSON.stringify(this, null, 2),
|
||||
path: configPath,
|
||||
});
|
||||
console.log("[Launcher]: Settings file initialized");
|
||||
} else {
|
||||
const data = await readTextFile(configPath);
|
||||
this.deserialize(JSON.parse(data));
|
||||
}
|
||||
this._loaded = true;
|
||||
}
|
||||
|
||||
private async saveConfigToFile() {
|
||||
if (!this._loaded) {
|
||||
log.info("config not loaded when trying to save, initializing it first!");
|
||||
await this.loadConfigFromFile();
|
||||
return;
|
||||
}
|
||||
const path = await join(await appDir(), "settings.json");
|
||||
await writeFile({
|
||||
contents: JSON.stringify(this, null, 2),
|
||||
path: path,
|
||||
});
|
||||
log.info("settings file initialized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the version to enable safe config operations
|
||||
*
|
||||
* Assumes the config has been loaded before calling to reduce boilerplate
|
||||
*
|
||||
* @param {*} version "<major>.<minor>"
|
||||
* @returns True if majors match, and expected minor greater than or equal to stored. False otherwise, or if no version can be found
|
||||
*/
|
||||
private validVersion(requiredVersion: string): boolean {
|
||||
const [requiredMajor, requiredMinor] = requiredVersion.split(".");
|
||||
if (this.version === null) {
|
||||
return false;
|
||||
}
|
||||
const [storedMajor, storedMinor] = this.version.split(".");
|
||||
if (requiredMajor != storedMajor) {
|
||||
return false;
|
||||
}
|
||||
if (parseInt(requiredMinor) < parseInt(storedMinor)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// GETTERS
|
||||
|
||||
/**
|
||||
* If a game is installed or not
|
||||
* @param {string} supportedGame
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async getInstallStatus(supportedGame: SupportedGame): Promise<boolean> {
|
||||
await this.loadConfigFromFile();
|
||||
if (!this.validVersion("1.0")) {
|
||||
return false;
|
||||
}
|
||||
const gameConfigs = this.games;
|
||||
if (gameConfigs === null || !(supportedGame in gameConfigs)) {
|
||||
return false;
|
||||
}
|
||||
return gameConfigs[supportedGame].isInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last game that was considered active in the launcher
|
||||
* @returns {Promise<SupportedGame | null>}
|
||||
*/
|
||||
async getLastActiveGame(): Promise<SupportedGame | null> {
|
||||
await this.loadConfigFromFile();
|
||||
if (!this.validVersion("1.0")) {
|
||||
return null;
|
||||
}
|
||||
return this.lastActiveGame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user config file to see if avx and openGL requirements are met.
|
||||
*/
|
||||
async areRequirementsMet(): Promise<boolean> {
|
||||
await this.loadConfigFromFile();
|
||||
if (!this.validVersion("1.0")) {
|
||||
return false;
|
||||
}
|
||||
return this.requirements.avx && this.requirements.openGL;
|
||||
}
|
||||
|
||||
async isAVXRequirementMet(): Promise<boolean> {
|
||||
await this.loadConfigFromFile();
|
||||
if (!this.validVersion("1.0")) {
|
||||
log.error("requirement false - AVX unsupported");
|
||||
return false;
|
||||
}
|
||||
return this.requirements.avx;
|
||||
}
|
||||
|
||||
async isOpenGLRequirementMet(): Promise<boolean> {
|
||||
await this.loadConfigFromFile();
|
||||
if (!this.validVersion("1.0")) {
|
||||
log.error("requirement false - OpenGL 4.3 unsupported");
|
||||
return false;
|
||||
}
|
||||
return this.requirements.openGL;
|
||||
}
|
||||
|
||||
async getGameInstallVersion(game: SupportedGame): Promise<String> {
|
||||
await this.loadConfigFromFile();
|
||||
if (!this.validVersion("1.0")) {
|
||||
return null;
|
||||
}
|
||||
return this.games[game].version;
|
||||
}
|
||||
|
||||
private async getLatestProjectBinaryVersion(): Promise<string | null> {
|
||||
// TODO - make a LauncherMetadata class similar to this
|
||||
const appDirPath = await appDir();
|
||||
const userMetaPath = await join(appDirPath, "data", "metadata.json");
|
||||
// TODO - ensure it exists!
|
||||
const data = await readTextFile(userMetaPath);
|
||||
const { version } = JSON.parse(data);
|
||||
return version;
|
||||
}
|
||||
|
||||
async shouldUpdateGameInstall(game: SupportedGame): Promise<Boolean> {
|
||||
const installVersion = await this.getGameInstallVersion(game);
|
||||
if (installVersion === null || installVersion === undefined) {
|
||||
return false;
|
||||
}
|
||||
const toolsVersion = await this.getLatestProjectBinaryVersion();
|
||||
|
||||
if (installVersion === toolsVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log.warn("Tools version is different than install verison", {
|
||||
tools: toolsVersion,
|
||||
installed: installVersion,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// SETTERS
|
||||
|
||||
/**
|
||||
* @param {string} supportedGame
|
||||
* @param {boolean} installed
|
||||
* @returns
|
||||
*/
|
||||
async setInstallStatus(
|
||||
supportedGame: SupportedGame,
|
||||
installed: boolean
|
||||
): Promise<void> {
|
||||
this.games[supportedGame].isInstalled = installed;
|
||||
await this.saveConfigToFile();
|
||||
}
|
||||
|
||||
async setRequirementsMet(
|
||||
avx: boolean = null,
|
||||
openGL: boolean = null
|
||||
): Promise<void> {
|
||||
this.requirements.avx = avx;
|
||||
this.requirements.openGL = openGL;
|
||||
await this.saveConfigToFile();
|
||||
}
|
||||
|
||||
async setGameInstallVersion(game: SupportedGame) {
|
||||
const version = await this.getLatestProjectBinaryVersion();
|
||||
this.games[game].version = version;
|
||||
await this.saveConfigToFile();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize with defaults
|
||||
export let launcherConfig: LauncherConfig = new LauncherConfig();
|
|
@ -1,51 +1,51 @@
|
|||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export async function getInstallationDirectory(): Promise<string | null> {
|
||||
try {
|
||||
return await invoke("get_install_directory", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function setInstallationDirectory(
|
||||
newInstallDir: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
await invoke("set_install_directory", { newDir: newInstallDir });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isAVXRequirementMet(): Promise<boolean> {
|
||||
try {
|
||||
return await invoke("is_avx_requirement_met", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isOpenGLRequirementMet(): Promise<boolean> {
|
||||
try {
|
||||
return await invoke("is_opengl_requirement_met", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function finalizeInstallation(gameName: string): Promise<void> {
|
||||
try {
|
||||
return await invoke("finalize_installation", { gameName: gameName });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isGameInstalled(gameName: string): Promise<boolean> {
|
||||
try {
|
||||
return await invoke("is_game_installed", { gameName: gameName });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export async function getInstallationDirectory(): Promise<string | null> {
|
||||
try {
|
||||
return await invoke("get_install_directory", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function setInstallationDirectory(
|
||||
newInstallDir: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
await invoke("set_install_directory", { newDir: newInstallDir });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isAVXRequirementMet(): Promise<boolean> {
|
||||
try {
|
||||
return await invoke("is_avx_requirement_met", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isOpenGLRequirementMet(): Promise<boolean> {
|
||||
try {
|
||||
return await invoke("is_opengl_requirement_met", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function finalizeInstallation(gameName: string): Promise<void> {
|
||||
try {
|
||||
return await invoke("finalize_installation", { gameName: gameName });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isGameInstalled(gameName: string): Promise<boolean> {
|
||||
try {
|
||||
return await invoke("is_game_installed", { gameName: gameName });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export async function extractAndValidateISO(
|
||||
pathToIso: string,
|
||||
gameName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("extract_and_validate_iso", {
|
||||
pathToIso: pathToIso,
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function runDecompiler(
|
||||
pathToIso: string,
|
||||
gameName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("run_decompiler", {
|
||||
pathToIso: pathToIso,
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function runCompiler(
|
||||
pathToIso: string,
|
||||
gameName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("run_compiler", {
|
||||
pathToIso: pathToIso,
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export async function extractAndValidateISO(
|
||||
pathToIso: string,
|
||||
gameName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("extract_and_validate_iso", {
|
||||
pathToIso: pathToIso,
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function runDecompiler(
|
||||
pathToIso: string,
|
||||
gameName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("run_decompiler", {
|
||||
pathToIso: pathToIso,
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function runCompiler(
|
||||
pathToIso: string,
|
||||
gameName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("run_compiler", {
|
||||
pathToIso: pathToIso,
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export async function launchGame(gameName: string): Promise<void> {
|
||||
try {
|
||||
return await invoke("launch_game", {
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export async function launchGame(
|
||||
gameName: string,
|
||||
inDebugMode: boolean
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await invoke("launch_game", {
|
||||
gameName: gameName,
|
||||
inDebug: inDebugMode,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function uninstallGame(gameName: string): Promise<void> {
|
||||
try {
|
||||
return await invoke("uninstall_game", {
|
||||
gameName: gameName,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export enum VersionFolders {
|
||||
OFFICIAL = "official",
|
||||
UNOFFICIAL = "unofficial",
|
||||
DEVEL = "devel",
|
||||
}
|
||||
|
||||
export async function listDownloadedVersions(
|
||||
folder: VersionFolders
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
return await invoke("list_downloaded_versions", { versionFolder: folder });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function downloadOfficialVersion(
|
||||
version: String,
|
||||
url: String
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
return await invoke("download_official_version", { version: version, url });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function openVersionFolder(folder: VersionFolders) {
|
||||
try {
|
||||
return await invoke("go_to_version_folder", { versionFolder: folder });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveActiveVersionChange(
|
||||
folder: VersionFolders,
|
||||
newVersion: String
|
||||
) {
|
||||
try {
|
||||
return await invoke("save_active_version_change", {
|
||||
versionFolder: folder,
|
||||
newActiveVersion: newVersion,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getActiveVersion() {
|
||||
try {
|
||||
return await invoke("get_active_version", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getActiveVersionFolder() {
|
||||
try {
|
||||
return await invoke("get_active_version_folder", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
|
||||
export enum VersionFolders {
|
||||
OFFICIAL = "official",
|
||||
UNOFFICIAL = "unofficial",
|
||||
DEVEL = "devel",
|
||||
}
|
||||
|
||||
export async function listDownloadedVersions(
|
||||
folder: VersionFolders
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
return await invoke("list_downloaded_versions", { versionFolder: folder });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function downloadOfficialVersion(
|
||||
version: String,
|
||||
url: String
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
return await invoke("download_official_version", { version: version, url });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function openVersionFolder(folder: VersionFolders) {
|
||||
try {
|
||||
return await invoke("go_to_version_folder", { versionFolder: folder });
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveActiveVersionChange(
|
||||
folder: VersionFolders,
|
||||
newVersion: String
|
||||
) {
|
||||
try {
|
||||
return await invoke("save_active_version_change", {
|
||||
versionFolder: folder,
|
||||
newActiveVersion: newVersion,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getActiveVersion() {
|
||||
try {
|
||||
return await invoke("get_active_version", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getActiveVersionFolder() {
|
||||
try {
|
||||
return await invoke("get_active_version_folder", {});
|
||||
} catch (e) {
|
||||
console.log("TODO AH!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,34 +2,14 @@ import { Command } from "@tauri-apps/api/shell";
|
|||
import { appDir, join } from "@tauri-apps/api/path";
|
||||
import { os } from "@tauri-apps/api";
|
||||
import { getHighestSimd } from "$lib/rpc/commands";
|
||||
import {
|
||||
gameNeedsReinstall,
|
||||
InstallStatus,
|
||||
isCompiling,
|
||||
isDecompiling,
|
||||
isInstalling,
|
||||
} from "../stores/AppStore";
|
||||
import {
|
||||
getInternalName,
|
||||
SETUP_ERROR,
|
||||
SETUP_SUCCESS,
|
||||
SupportedGame,
|
||||
} from "$lib/constants";
|
||||
import { filePrompt } from "$lib/utils/file";
|
||||
import { launcherConfig } from "$lib/config";
|
||||
import { isInstalling } from "../stores/AppStore";
|
||||
import { getInternalName, SupportedGame } from "$lib/constants";
|
||||
import { resolveErrorCode } from "./setup_errors";
|
||||
import { installLog, log } from "$lib/utils/log";
|
||||
import { ProcessLogs } from "$lib/stores/AppStore";
|
||||
import { removeDir } from "@tauri-apps/api/fs";
|
||||
|
||||
let sidecarOptions = {};
|
||||
|
||||
export interface InstallationStatus {}
|
||||
|
||||
export function isInDebugMode() {
|
||||
return process.env.NODE_ENV === "development";
|
||||
}
|
||||
|
||||
export async function isAVXSupported() {
|
||||
const highestSIMD = await getHighestSimd();
|
||||
if (highestSIMD === undefined) {
|
||||
|
@ -72,9 +52,10 @@ export async function checkRequirements(): Promise<void> {
|
|||
const isAVX = await isAVXSupported();
|
||||
const isOpenGL = await isOpenGLVersionSupported("4.3");
|
||||
console.log(`avx - ${isAVX} opengl - ${isOpenGL}`);
|
||||
await launcherConfig.setRequirementsMet(isAVX, isOpenGL);
|
||||
// TODO - fix
|
||||
// await launcherConfig.setRequirementsMet(isAVX, isOpenGL);
|
||||
} catch (err) {
|
||||
await launcherConfig.setRequirementsMet(false, false);
|
||||
// await launcherConfig.setRequirementsMet(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,39 +67,3 @@ async function handleErrorCode(code: number, stepName: string) {
|
|||
}
|
||||
throw new Error(explaination);
|
||||
}
|
||||
|
||||
export async function decompileFromFile(activeGame: SupportedGame) {
|
||||
const isoPath = await join(
|
||||
await appDir(),
|
||||
"data",
|
||||
"iso_data",
|
||||
getInternalName(activeGame)
|
||||
);
|
||||
await decompileGameData(isoPath);
|
||||
}
|
||||
|
||||
export async function compileFromFile(activeGame: SupportedGame) {
|
||||
const isoPath = await join(
|
||||
await appDir(),
|
||||
"data",
|
||||
"iso_data",
|
||||
getInternalName(activeGame)
|
||||
);
|
||||
await compileGame(isoPath);
|
||||
}
|
||||
|
||||
export async function uninstallGame(game: SupportedGame) {
|
||||
const dataDir = await join(await appDir(), "data");
|
||||
try {
|
||||
const t0 = await join(dataDir, "decompiler_out", getInternalName(game));
|
||||
const t1 = await join(dataDir, "iso_data", getInternalName(game));
|
||||
const t2 = await join(dataDir, "out", getInternalName(game));
|
||||
const targets = [t0, t1, t2];
|
||||
for (const target of targets) {
|
||||
console.log("Deleting folder: ", target);
|
||||
await removeDir(target, { recursive: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
|
3
src/lib/utils/common.ts
Normal file
3
src/lib/utils/common.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export function isInDebugMode() {
|
||||
return process.env.NODE_ENV === "development";
|
||||
}
|
Loading…
Reference in a new issue