help: allow launching the game with a one-off gk executable (#570)
Some checks failed
🧪 Tests / Frontend (push) Has been cancelled
🔨 Build / App (macos-12) (push) Has been cancelled
🔨 Build / App (ubuntu-20.04) (push) Has been cancelled
🔨 Build / App (windows-latest) (push) Has been cancelled
📝 Linter / Frontend (push) Has been cancelled
📝 Linter / Backend Formatting (push) Has been cancelled
📝 Linter / Backend Linter (push) Has been cancelled

Fixes #267 

This is something I've had to manually get users to do multiple times to
see if a fix has worked in the C++ code. This should make that much
easier.

Still requires some cleanup / OS specific handling.
This commit is contained in:
Tyler Wilding 2024-09-22 18:39:15 -04:00 committed by GitHub
parent 465092d965
commit e73a779bab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 80 additions and 8 deletions

View file

@ -1,8 +1,11 @@
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
use std::{ use std::{
collections::HashMap, collections::HashMap,
io::ErrorKind, io::ErrorKind,
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Stdio, process::Stdio,
str::FromStr,
time::Instant, time::Instant,
}; };
use tokio::{io::AsyncWriteExt, process::Command}; use tokio::{io::AsyncWriteExt, process::Command};
@ -591,7 +594,7 @@ pub async fn open_repl(
let mut command; let mut command;
#[cfg(windows)] #[cfg(windows)]
{ {
command = Command::new("cmd"); command = std::process::Command::new("cmd");
command command
.args([ .args([
"/K", "/K",
@ -605,14 +608,14 @@ pub async fn open_repl(
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
command = Command::new("xdg-terminal-exec"); command = std::process::Command::new("xdg-terminal-exec");
command command
.args(["./goalc", "--proj-path", &data_folder.to_string_lossy()]) .args(["./goalc", "--proj-path", &data_folder.to_string_lossy()])
.current_dir(exec_info.executable_dir); .current_dir(exec_info.executable_dir);
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
command = Command::new("osascript"); command = std::process::Command::new("osascript");
command command
.args([ .args([
"-e", "-e",
@ -794,18 +797,44 @@ pub async fn launch_game(
app_handle: tauri::AppHandle, app_handle: tauri::AppHandle,
game_name: String, game_name: String,
in_debug: bool, in_debug: bool,
executable_location: Option<String>,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let config_lock = config.lock().await; let config_lock = config.lock().await;
let config_info = common_prelude(&config_lock)?; let config_info = common_prelude(&config_lock)?;
let exec_info = get_exec_location(&config_info, "gk")?; let mut exec_info = get_exec_location(&config_info, "gk")?;
if let Some(custom_exec_location) = executable_location {
match PathBuf::from_str(custom_exec_location.as_str()) {
Ok(exec_path) => {
let path_copy = exec_path.clone();
if path_copy.parent().is_none() {
return Err(CommandError::BinaryExecution(format!(
"Failed to resolve custom binary parent directory"
)));
}
exec_info = ExecutableLocation {
executable_dir: exec_path.clone().parent().unwrap().to_path_buf(),
executable_path: exec_path.clone(),
};
}
Err(err) => {
return Err(CommandError::BinaryExecution(format!(
"Failed to resolve custom binary location {}",
err
)));
}
}
}
let args = generate_launch_game_string(&config_info, game_name.clone(), in_debug, false)?; let args = generate_launch_game_string(&config_info, game_name.clone(), in_debug, false)?;
log::info!( log::info!(
"Launching game version {:?} -> {:?} with args: {:?}", "Launching game version {:?} -> {:?} with args: {:?}. Working Directory: {:?}, Path: {:?}",
&config_info.active_version, &config_info.active_version,
&config_info.tooling_version, &config_info.tooling_version,
args args,
exec_info.executable_dir,
exec_info.executable_path,
); );
let log_file = create_std_log_file(&app_handle, format!("game-{game_name}.log"), false)?; let log_file = create_std_log_file(&app_handle, format!("game-{game_name}.log"), false)?;

View file

@ -16,7 +16,12 @@
} from "flowbite-svelte"; } from "flowbite-svelte";
import { resetGameSettings, uninstallGame } from "$lib/rpc/game"; import { resetGameSettings, uninstallGame } from "$lib/rpc/game";
import { platform } from "@tauri-apps/api/os"; import { platform } from "@tauri-apps/api/os";
import { getLaunchGameString, launchGame, openREPL } from "$lib/rpc/binaries"; import {
getLaunchGameString,
launchGame,
launchGameWithCustomExecutable,
openREPL,
} from "$lib/rpc/binaries";
import { import {
doesActiveToolingVersionMeetMinimum, doesActiveToolingVersionMeetMinimum,
getInstallationDirectory, getInstallationDirectory,
@ -165,6 +170,11 @@
launchGame(getInternalName(activeGame), true); launchGame(getInternalName(activeGame), true);
}}>{$_("gameControls_button_playInDebug")}</DropdownItem }}>{$_("gameControls_button_playInDebug")}</DropdownItem
> >
<DropdownItem
on:click={async () => {
launchGameWithCustomExecutable(getInternalName(activeGame));
}}>Launch with Custom Executable</DropdownItem
>
<DropdownItem <DropdownItem
on:click={async () => { on:click={async () => {
openREPL(getInternalName(activeGame)); openREPL(getInternalName(activeGame));

View file

@ -1,3 +1,4 @@
import { filePrompt, filePromptNoFilters } from "$lib/utils/file-dialogs";
import { invoke_rpc } from "./rpc"; import { invoke_rpc } from "./rpc";
interface InstallationOutput { interface InstallationOutput {
@ -66,12 +67,27 @@ export async function launchGame(
): Promise<void> { ): Promise<void> {
return await invoke_rpc( return await invoke_rpc(
"launch_game", "launch_game",
{ gameName, inDebug }, { gameName, inDebug, executableLocation: null },
() => {}, () => {},
"_mirror_", "_mirror_",
); );
} }
export async function launchGameWithCustomExecutable(
gameName: string,
): Promise<void> {
// Get custom executable location
const customExecutable = await filePromptNoFilters("Select custom 'gk'");
if (customExecutable !== null) {
return await invoke_rpc(
"launch_game",
{ gameName, inDebug: false, executableLocation: customExecutable },
() => {},
"_mirror_",
);
}
}
export async function openREPL(gameName: string): Promise<void> { export async function openREPL(gameName: string): Promise<void> {
return await invoke_rpc( return await invoke_rpc(
"open_repl", "open_repl",

View file

@ -1,5 +1,22 @@
import { open, save } from "@tauri-apps/api/dialog"; import { open, save } from "@tauri-apps/api/dialog";
export async function filePromptNoFilters(
title: string,
): Promise<string | null> {
const path = await open({
title: title,
multiple: false,
directory: false,
filters: undefined,
});
if (Array.isArray(path) || path === null) {
return null;
}
return path;
}
export async function filePrompt( export async function filePrompt(
extensions: string[], extensions: string[],
name: string, name: string,