frontend: nice flow for decompiling/compiling

This commit is contained in:
Tyler Wilding 2023-02-19 14:41:51 -05:00
parent 5634257381
commit f118d856c3
No known key found for this signature in database
GPG key ID: 77CB07796494137E
8 changed files with 136 additions and 20 deletions

View file

@ -51,17 +51,27 @@ pub async fn run_decompiler(
match &config_lock.installation_dir {
None => Ok(()),
Some(path) => {
let install_path = Path::new(path);
let data_folder = install_path.join("active/jak1/data");
let mut source_path = path_to_iso;
if source_path.is_empty() {
// TODO - we could probably be more explicit here using a param
source_path = data_folder
.join("iso_data/jak1")
.to_string_lossy()
.to_string();
}
// TODO - be smarter
// TODO - make folder if it doesnt exist
// TODO - copy over the data folder
// TODO - log it to a file
let install_path = Path::new(path);
let binary_dir = install_path.join("versions/official/v0.1.32/");
let data_folder = install_path.join("active/jak1/data");
let executable_location = binary_dir.join("extractor.exe");
let output = Command::new(&executable_location)
.args([
path_to_iso,
source_path,
"--decompile".to_string(),
"--proj-path".to_string(),
data_folder.to_string_lossy().into_owned(),
@ -84,17 +94,26 @@ pub async fn run_compiler(
match &config_lock.installation_dir {
None => Ok(()),
Some(path) => {
let install_path = Path::new(path);
let data_folder = install_path.join("active/jak1/data");
let mut source_path = path_to_iso;
if source_path.is_empty() {
// TODO - we could probably be more explicit here using a param
source_path = data_folder
.join("iso_data/jak1")
.to_string_lossy()
.to_string();
}
// TODO - be smarter
// TODO - make folder if it doesnt exist
// TODO - copy over the data folder
// TODO - log it to a file
let install_path = Path::new(path);
let binary_dir = install_path.join("versions/official/v0.1.32/");
let data_folder = install_path.join("active/jak1/data");
let executable_location = binary_dir.join("extractor.exe");
let output = Command::new(&executable_location)
.args([
path_to_iso,
source_path,
"--compile".to_string(),
"--proj-path".to_string(),
data_folder.to_string_lossy().into_owned(),

View file

@ -86,7 +86,9 @@
<DropdownDivider />
<DropdownItem
on:click={async () => {
await openDir(settingsDir);
dispatch('job', {
type: "decompile"
})
}}
>Decompile
<!-- NOTE - this is a bug in flowbite-svelte, it's not replacing the default class but just appending -->
@ -96,7 +98,9 @@
>
<DropdownItem
on:click={async () => {
await openDir(settingsDir);
dispatch('job', {
type: "compile"
})
}}
>Compile
<!-- NOTE - this is a bug in flowbite-svelte, it's not replacing the default class but just appending -->

View file

@ -0,0 +1,79 @@
<script lang="ts">
// components
import Progress from "../setup/Progress.svelte";
// constants
import LogViewer from "../setup/LogViewer.svelte";
import { createEventDispatcher, onMount } from "svelte";
import { Button } from "flowbite-svelte";
import { progressTracker } from "$lib/stores/ProgressStore";
import type { Job } from "$lib/jobs/jobs";
import { getInternalName, type SupportedGame } from "$lib/constants";
import { runCompiler, runDecompiler } from "$lib/rpc/extractor";
export let activeGame: SupportedGame;
export let jobType: Job;
const dispatch = createEventDispatcher();
let running = false;
// This is basically a stripped down `GameSetup` component that doesn't care about user initiation
// requirement checking, etc
//
// It's used to provide almost the same interface as the normal installation, with logs, etc
// but for arbitrary jobs. Such as decompiling, or compiling.
onMount(async () => {
if (jobType === "decompile") {
progressTracker.init([
{
status: "queued",
label: "Decompile",
},
{
status: "queued",
label: "Done",
},
]);
progressTracker.start();
await runDecompiler("", getInternalName(activeGame));
progressTracker.proceed();
progressTracker.proceed();
} else if (jobType === "compile") {
progressTracker.init([
{
status: "queued",
label: "Compile",
},
{
status: "queued",
label: "Done",
},
]);
progressTracker.start();
await runCompiler("", getInternalName(activeGame));
progressTracker.proceed();
progressTracker.proceed();
}
});
function dispatchCompleteJob() {
dispatch("jobFinished");
}
</script>
<div class="flex flex-col justify-content">
<Progress />
{#if $progressTracker.logs}
<LogViewer />
{/if}
</div>
{#if $progressTracker.overallStatus === "success"}
<div class="flex flex-col justify-end items-end mt-auto">
<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={async () => dispatchCompleteJob()}>Continue</Button
>
</div>
</div>
{/if}

View file

@ -74,8 +74,6 @@
}
</script>
<!-- TODO - allow passing a folder path -->
{#if !requirementsMet}
<Requirements />
{:else if installing}

View file

@ -58,8 +58,8 @@
<div class="w-full py-6">
<div class="flex">
{#each progress.steps as step, i}
<!-- NOTE - this breaks down if there is only 1 step, or probably if you have a huge number of steps -->
<div class="w-1/{progress.steps.length}">
<!-- NOTE - this will break if you add too many steps! -->
<div class="grow">
<div class="relative mb-2">
<!-- BAR (skipped for first element) -->
{#if i !== 0}

1
src/lib/jobs/jobs.ts Normal file
View file

@ -0,0 +1 @@
export type Job = "decompile" | "compile";

View file

@ -1,6 +1,11 @@
import { writable } from "svelte/store";
export type ProgressStatus = "success" | "queued" | "pending" | "failed";
export type ProgressStatus =
| "inactive"
| "success"
| "queued"
| "pending"
| "failed";
export interface ProgressStep {
status: ProgressStatus;
@ -16,7 +21,7 @@ interface ProgressTracker {
const storeValue: ProgressTracker = {
currentStep: 0,
overallStatus: "queued",
overallStatus: "inactive",
steps: [],
logs: [],
};
@ -29,7 +34,7 @@ function createProgressTracker() {
init: (steps: ProgressStep[]) =>
update((val) => {
val.currentStep = 0;
val.overallStatus = "queued";
val.overallStatus = "inactive";
val.steps = steps;
val.logs = [];
return val;

View file

@ -7,15 +7,15 @@
import { isDataDirectoryUpToDate } from "$lib/utils/data-files";
import { Spinner } from "flowbite-svelte";
import { isGameInstalled } from "$lib/rpc/config";
import { progressTracker } from "$lib/stores/ProgressStore";
import GameJob from "../components/games/job/GameJob.svelte";
const params = useParams();
let activeGame = SupportedGame.Jak1;
let componentLoaded = false;
let gameInstalled = false;
let dataDirUpToDate = false;
let updatingDataDir = false;
let gameJobToRun = undefined;
onMount(async () => {
// Figure out what game we are displaying
@ -43,6 +43,14 @@
gameInstalled = await isGameInstalled(getInternalName(activeGame));
// TODO - check data dir?
}
async function runGameJob(event) {
gameJobToRun = event.detail.type;
}
async function gameJobFinished() {
gameJobToRun = undefined;
}
</script>
<div class="ml-20">
@ -54,9 +62,11 @@
<Spinner color="yellow" size={"12"} />
</div>
{:else if !gameInstalled}
<GameSetup {activeGame} on:change={updateGameState} />
<GameSetup activeGame={activeGame} on:change={updateGameState} />
{:else if gameJobToRun !== undefined}
<GameJob activeGame={activeGame} jobType={gameJobToRun} on:jobFinished={gameJobFinished}/>
{:else}
<GameControls {activeGame} on:change={updateGameState} />
<GameControls {activeGame} on:change={updateGameState} on:job={runGameJob} />
{/if}
</div>
</div>