aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorHsiangNianian <i@jyunko.cn>2026-01-16 20:20:05 +0800
committerHsiangNianian <i@jyunko.cn>2026-01-16 20:20:05 +0800
commit3c13c14dea03c6b91716fb0f1578deb12fcf9756 (patch)
tree840174337f765bfcac6c173ddd629c6e3bf6f6b1
parent1119f6c3cf421da2f2db92873efae8135c76b678 (diff)
downloadDropOut-3c13c14dea03c6b91716fb0f1578deb12fcf9756.tar.gz
DropOut-3c13c14dea03c6b91716fb0f1578deb12fcf9756.zip
feat: implement instance management functionality
Added a new InstancesState class to manage game instances, including loading, creating, deleting, updating, and duplicating instances. Integrated instance selection into the game launch process, ensuring an active instance is selected before starting a game. Updated the types to include instance-related data structures.
-rw-r--r--ui/src/stores/game.svelte.ts14
-rw-r--r--ui/src/stores/instances.svelte.ts109
-rw-r--r--ui/src/types/index.ts17
3 files changed, 137 insertions, 3 deletions
diff --git a/ui/src/stores/game.svelte.ts b/ui/src/stores/game.svelte.ts
index ca5dc2b..3efcf71 100644
--- a/ui/src/stores/game.svelte.ts
+++ b/ui/src/stores/game.svelte.ts
@@ -2,6 +2,7 @@ import { invoke } from "@tauri-apps/api/core";
import type { Version } from "../types";
import { uiState } from "./ui.svelte";
import { authState } from "./auth.svelte";
+import { instancesState } from "./instances.svelte";
export class GameState {
versions = $state<Version[]>([]);
@@ -34,10 +35,19 @@ export class GameState {
return;
}
+ if (!instancesState.activeInstanceId) {
+ alert("Please select an instance first!");
+ uiState.setView("instances");
+ return;
+ }
+
uiState.setStatus("Preparing to launch " + this.selectedVersion + "...");
- console.log("Invoking start_game for version:", this.selectedVersion);
+ console.log("Invoking start_game for version:", this.selectedVersion, "instance:", instancesState.activeInstanceId);
try {
- const msg = await invoke<string>("start_game", { versionId: this.selectedVersion });
+ const msg = await invoke<string>("start_game", {
+ instanceId: instancesState.activeInstanceId,
+ versionId: this.selectedVersion,
+ });
console.log("Response:", msg);
uiState.setStatus(msg);
} catch (e) {
diff --git a/ui/src/stores/instances.svelte.ts b/ui/src/stores/instances.svelte.ts
new file mode 100644
index 0000000..f4ac4e9
--- /dev/null
+++ b/ui/src/stores/instances.svelte.ts
@@ -0,0 +1,109 @@
+import { invoke } from "@tauri-apps/api/core";
+import type { Instance } from "../types";
+import { uiState } from "./ui.svelte";
+
+export class InstancesState {
+ instances = $state<Instance[]>([]);
+ activeInstanceId = $state<string | null>(null);
+ get activeInstance(): Instance | null {
+ if (!this.activeInstanceId) return null;
+ return this.instances.find((i) => i.id === this.activeInstanceId) || null;
+ }
+
+ async loadInstances() {
+ try {
+ this.instances = await invoke<Instance[]>("list_instances");
+ const active = await invoke<Instance | null>("get_active_instance");
+ if (active) {
+ this.activeInstanceId = active.id;
+ } else if (this.instances.length > 0) {
+ // If no active instance but instances exist, set the first one as active
+ await this.setActiveInstance(this.instances[0].id);
+ }
+ } catch (e) {
+ console.error("Failed to load instances:", e);
+ uiState.setStatus("Error loading instances: " + e);
+ }
+ }
+
+ async createInstance(name: string): Promise<Instance | null> {
+ try {
+ const instance = await invoke<Instance>("create_instance", { name });
+ await this.loadInstances();
+ uiState.setStatus(`Instance "${name}" created successfully`);
+ return instance;
+ } catch (e) {
+ console.error("Failed to create instance:", e);
+ uiState.setStatus("Error creating instance: " + e);
+ return null;
+ }
+ }
+
+ async deleteInstance(id: string) {
+ try {
+ await invoke("delete_instance", { instanceId: id });
+ await this.loadInstances();
+ // If deleted instance was active, set another as active
+ if (this.activeInstanceId === id) {
+ if (this.instances.length > 0) {
+ await this.setActiveInstance(this.instances[0].id);
+ } else {
+ this.activeInstanceId = null;
+ }
+ }
+ uiState.setStatus("Instance deleted successfully");
+ } catch (e) {
+ console.error("Failed to delete instance:", e);
+ uiState.setStatus("Error deleting instance: " + e);
+ }
+ }
+
+ async updateInstance(instance: Instance) {
+ try {
+ await invoke("update_instance", { instance });
+ await this.loadInstances();
+ uiState.setStatus("Instance updated successfully");
+ } catch (e) {
+ console.error("Failed to update instance:", e);
+ uiState.setStatus("Error updating instance: " + e);
+ }
+ }
+
+ async setActiveInstance(id: string) {
+ try {
+ await invoke("set_active_instance", { instanceId: id });
+ this.activeInstanceId = id;
+ uiState.setStatus("Active instance changed");
+ } catch (e) {
+ console.error("Failed to set active instance:", e);
+ uiState.setStatus("Error setting active instance: " + e);
+ }
+ }
+
+ async duplicateInstance(id: string, newName: string): Promise<Instance | null> {
+ try {
+ const instance = await invoke<Instance>("duplicate_instance", {
+ instanceId: id,
+ newName,
+ });
+ await this.loadInstances();
+ uiState.setStatus(`Instance duplicated as "${newName}"`);
+ return instance;
+ } catch (e) {
+ console.error("Failed to duplicate instance:", e);
+ uiState.setStatus("Error duplicating instance: " + e);
+ return null;
+ }
+ }
+
+ async getInstance(id: string): Promise<Instance | null> {
+ try {
+ return await invoke<Instance>("get_instance", { instanceId: id });
+ } catch (e) {
+ console.error("Failed to get instance:", e);
+ return null;
+ }
+ }
+}
+
+export const instancesState = new InstancesState();
diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts
index 9a4da2b..a5b336e 100644
--- a/ui/src/types/index.ts
+++ b/ui/src/types/index.ts
@@ -1,4 +1,4 @@
-export type ViewType = "home" | "versions" | "settings" | "guide";
+export type ViewType = "home" | "versions" | "settings" | "guide" | "instances";
export interface Version {
id: string;
@@ -187,3 +187,18 @@ export interface InstalledForgeVersion {
// ==================== Mod Loader Type ====================
export type ModLoaderType = "vanilla" | "fabric" | "forge";
+
+// ==================== Instance Types ====================
+
+export interface Instance {
+ id: string;
+ name: string;
+ game_dir: string;
+ version_id?: string;
+ created_at: number;
+ last_played?: number;
+ icon_path?: string;
+ notes?: string;
+ mod_loader?: string;
+ mod_loader_version?: string;
+}