Skip to content

Commit d7f1280

Browse files
committed
feat: launch option selector
1 parent 58c6f3e commit d7f1280

File tree

4 files changed

+125
-9
lines changed

4 files changed

+125
-9
lines changed

main/pages/library/[id]/index.vue

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,45 @@
395395
</template>
396396
</ModalTemplate>
397397

398+
<ModalTemplate :model-value="launchOptionsOpen">
399+
<template #default>
400+
<div class="sm:flex sm:items-start">
401+
<div class="mt-3 text-center sm:mt-0 sm:text-left">
402+
<h3 class="text-base font-semibold text-zinc-100">
403+
Launch {{ game.mName }}
404+
</h3>
405+
<div class="mt-2">
406+
<p class="text-sm text-zinc-400">
407+
The instance admin has configured multiple ways to start this
408+
game. Select an option to start.
409+
</p>
410+
</div>
411+
</div>
412+
</div>
413+
414+
<ol class="space-y-2">
415+
<li v-for="(launchData, launchIdx) in launchOptions!">
416+
<button class="transition w-full rounded-sm bg-zinc-800 inline-flex items-center text-sm py-2 px-3 gap-x-2 text-zinc-100 hover:text-zinc-300 hover:bg-zinc-700" @click="() => launchIndex(launchIdx)">
417+
<PlayIcon class="size-4" />
418+
<span>
419+
{{ launchData.name }}
420+
</span>
421+
</button>
422+
</li>
423+
</ol>
424+
</template>
425+
<template #buttons>
426+
<button
427+
type="button"
428+
class="mt-3 inline-flex w-full justify-center rounded-md bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-700 hover:bg-zinc-900 sm:mt-0 sm:w-auto"
429+
@click="launchOptions = undefined"
430+
ref="cancelButtonRef"
431+
>
432+
Cancel
433+
</button>
434+
</template>
435+
</ModalTemplate>
436+
398437
<!--
399438
Dear future DecDuck,
400439
This v-if is necessary for Vue rendering reasons
@@ -492,6 +531,7 @@ import {
492531
XMarkIcon,
493532
ArrowsPointingOutIcon,
494533
PhotoIcon,
534+
PlayIcon,
495535
} from "@heroicons/vue/20/solid";
496536
import { BuildingStorefrontIcon } from "@heroicons/vue/24/outline";
497537
import { XCircleIcon } from "@heroicons/vue/24/solid";
@@ -584,9 +624,34 @@ async function resumeDownload() {
584624
}
585625
}
586626
627+
const launchOptions = ref<Array<{ name: string }> | undefined>(undefined);
628+
const launchOptionsOpen = computed(() => launchOptions.value !== undefined);
629+
587630
async function launch() {
588631
try {
589-
await invoke("launch_game", { id: game.value.id });
632+
const fetchedLaunchOptions = await invoke<Array<{ name: string }>>(
633+
"get_launch_options",
634+
{ id: game.value.id }
635+
);
636+
launchOptions.value = fetchedLaunchOptions;
637+
} catch (e) {
638+
createModal(
639+
ModalType.Notification,
640+
{
641+
title: `Couldn't run "${game.value.mName}"`,
642+
description: `Drop failed to launch "${game.value.mName}": ${e}`,
643+
buttonText: "Close",
644+
},
645+
(e, c) => c()
646+
);
647+
console.error(e);
648+
}
649+
}
650+
651+
async function launchIndex(index: number) {
652+
launchOptions.value = undefined;
653+
try {
654+
await invoke("launch_game", { id: game.value.id, index });
590655
} catch (e) {
591656
createModal(
592657
ModalType.Notification,

src-tauri/process/src/process_manager.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::{
22
collections::HashMap,
33
fs::{OpenOptions, create_dir_all},
44
io,
5+
ops::Index,
56
path::PathBuf,
67
process::{Command, ExitStatus},
78
str::FromStr,
@@ -18,6 +19,7 @@ use dynfmt::Format;
1819
use dynfmt::SimpleCurlyFormat;
1920
use games::{library::push_game_update, state::GameStatusManager};
2021
use log::{debug, info, warn};
22+
use serde::Serialize;
2123
use shared_child::SharedChild;
2224
use tauri::{AppHandle, Emitter as _};
2325

@@ -45,6 +47,11 @@ pub struct ProcessManager<'a> {
4547
app_handle: AppHandle,
4648
}
4749

50+
#[derive(Serialize)]
51+
pub struct LaunchOption {
52+
name: String,
53+
}
54+
4855
impl ProcessManager<'_> {
4956
pub fn new(app_handle: AppHandle) -> Self {
5057
let log_output_dir = DATA_ROOT_DIR.join("logs");
@@ -207,8 +214,42 @@ impl ProcessManager<'_> {
207214
process_handler.is_ok()
208215
}
209216

217+
pub fn get_launch_options(game_id: String) -> Result<Vec<LaunchOption>, ProcessError> {
218+
let db_lock = borrow_db_checked();
219+
220+
let meta = db_lock
221+
.applications
222+
.installed_game_version
223+
.get(&game_id)
224+
.cloned()
225+
.ok_or(ProcessError::NotInstalled)?;
226+
227+
let game_version = db_lock
228+
.applications
229+
.game_versions
230+
.get(&game_id)
231+
.ok_or(ProcessError::InvalidID)?
232+
.get(&meta.version)
233+
.ok_or(ProcessError::InvalidVersion)?;
234+
235+
let launch_options = game_version
236+
.launches
237+
.iter()
238+
.filter(|v| v.platform == meta.target_platform)
239+
.map(|v| LaunchOption {
240+
name: v.name.clone(),
241+
})
242+
.collect::<Vec<LaunchOption>>();
243+
244+
Ok(launch_options)
245+
}
246+
210247
/// Must be called through spawn as it is currently blocking
211-
pub fn launch_process(&mut self, game_id: String) -> Result<(), ProcessError> {
248+
pub fn launch_process(
249+
&mut self,
250+
game_id: String,
251+
launch_process_index: usize,
252+
) -> Result<(), ProcessError> {
212253
if self.processes.contains_key(&game_id) {
213254
return Err(ProcessError::AlreadyRunning);
214255
}
@@ -292,12 +333,13 @@ impl ProcessManager<'_> {
292333
version_name: _,
293334
install_dir: _,
294335
} => {
295-
let launch_config = game_version
336+
let (_, launch_config) = game_version
296337
.launches
297338
.iter()
298-
.find(|v| v.platform == target_platform)
339+
.filter(|v| v.platform == target_platform)
340+
.enumerate()
341+
.find(|(i, _)| *i == launch_process_index)
299342
.ok_or(ProcessError::NotInstalled)?;
300-
301343
(
302344
launch_config.command.clone(),
303345
launch_config.args.clone(),

src-tauri/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ pub fn run() {
271271
kill_game,
272272
toggle_autostart,
273273
get_autostart_enabled,
274-
open_process_logs
274+
open_process_logs,
275+
get_launch_options
275276
])
276277
.plugin(tauri_plugin_shell::init())
277278
.plugin(tauri_plugin_dialog::init())

src-tauri/src/process.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
use std::sync::nonpoison::Mutex;
22

3-
use process::{PROCESS_MANAGER, error::ProcessError};
4-
use tauri::AppHandle;
3+
use process::{PROCESS_MANAGER, error::ProcessError, process_manager::{LaunchOption, ProcessManager}};
4+
use tauri::{AppHandle, Error};
55
use tauri_plugin_opener::OpenerExt;
66

77
use crate::AppState;
88

9+
#[tauri::command]
10+
pub fn get_launch_options(id: String) -> Result<Vec<LaunchOption>, ProcessError> {
11+
let launch_options = ProcessManager::get_launch_options(id)?;
12+
13+
Ok(launch_options)
14+
}
15+
916
#[tauri::command]
1017
pub fn launch_game(
1118
id: String,
19+
index: usize,
1220
state: tauri::State<'_, Mutex<AppState>>,
1321
) -> Result<(), ProcessError> {
1422
let state_lock = state.lock();
@@ -19,7 +27,7 @@ pub fn launch_game(
1927
// download_type: DownloadType::Game,
2028
//};
2129

22-
match process_manager_lock.launch_process(id) {
30+
match process_manager_lock.launch_process(id, index) {
2331
Ok(()) => {}
2432
Err(e) => return Err(e),
2533
}

0 commit comments

Comments
 (0)