wormhole_common/instances/
instance.rs1use super::{InstanceJson, InstanceMod, KSPGame, KSP1_STEAM_API_SIZE, KSP2_STEAM_API_SIZE};
2
3use crate::{
4 finder::{find_ksp1_install_dir, find_ksp2_install_dir},
5 util::{copy_dir_all, get_data_dir},
6};
7
8use serde::{Deserialize, Serialize};
9use std::{
10 fs::{remove_dir_all, File},
11 io::{Read, Write},
12 mem::replace,
13 path::PathBuf,
14};
15
16#[derive(Serialize, Deserialize, Debug, Clone)]
17pub struct Instance {
18 pub id: i32,
19 pub name: String,
20 pub game: KSPGame,
21 pub mods: Vec<InstanceMod>,
22 pub install_path: PathBuf,
23 pub description: Option<String>,
24 pub time_played: Option<String>,
25}
26
27impl Instance {
28 pub fn defaults() -> Vec<Self> {
29 let v = vec![
30 Instance {
31 id: 0,
32 name: "KSP2 Default Instance".to_string(),
33 game: KSPGame::KSP2,
34 install_path: find_ksp2_install_dir(),
35 mods: Vec::new(),
36 description: None,
37 time_played: None,
38 },
39 Instance {
40 id: 1,
41 name: "KSP1 Default Instance".to_string(),
42 game: KSPGame::KSP1,
43 install_path: find_ksp1_install_dir(),
44 mods: Vec::new(),
45 description: None,
46 time_played: None,
47 },
48 ];
49
50 return Instance::validate_instances(v);
51 }
52
53 pub fn validate_instances(instances: Vec<Instance>) -> Vec<Instance> {
54 let mut final_instances = Vec::new();
55
56 for instance in instances {
57 if instance.install_path.exists() {
58 let api_dll = match instance.game {
59 KSPGame::KSP1 => instance
60 .install_path
61 .join("KSP_x64_Data/Plugins/x86_64/steam_api64.dll"),
62 KSPGame::KSP2 => instance
63 .install_path
64 .join("KSP2_x64_Data/Plugins/x86_64/steam_api64.dll`"),
65 };
66
67 let size = api_dll.metadata().unwrap().len();
68
69 let needed_size = match instance.game {
70 KSPGame::KSP1 => KSP1_STEAM_API_SIZE,
71 KSPGame::KSP2 => KSP2_STEAM_API_SIZE,
72 };
73
74 if size == needed_size {
75 final_instances.push(instance);
76 }
77 }
78 }
79
80 return final_instances;
81 }
82
83 pub fn load() -> Vec<Self> {
84 let instances;
85 let instances_path = get_data_dir().join("instances.json");
86
87 if instances_path.exists() {
88 let mut file = File::open(instances_path).unwrap();
89 let mut content = String::new();
90
91 file.read_to_string(&mut content).unwrap();
92 instances = serde_json::from_str(&content).unwrap();
93 } else {
94 instances = Instance::defaults();
95
96 Instance::save_all(&instances);
97 }
98
99 return instances;
100 }
101
102 pub fn save_all(instances: &Vec<Self>) {
103 let instances_path = get_data_dir().join("instances.json");
104 let mut file = File::create(instances_path).unwrap();
105
106 file.write_all(serde_json::to_string(&instances).unwrap().as_bytes())
107 .unwrap();
108 }
109
110 pub fn save(&self) {
111 let mut instances = Instance::load();
112
113 for (index, instance) in instances.clone().iter().enumerate() {
114 if instance.id == self.id {
115 let _ = replace(&mut instances[index], self.clone());
116 }
117 }
118
119 Instance::save_all(&instances);
120 }
121
122 pub fn from_id(id: i32) -> Option<Instance> {
123 let instances = Instance::load();
124 let instance = instances.iter().find(|i| i.id == id).cloned();
125
126 return instance;
127 }
128
129 pub fn load_from_file(file_path: PathBuf) -> Option<Instance> {
130 let mut file = File::open(file_path).unwrap();
131 let mut content = String::new();
132
133 file.read_to_string(&mut content).unwrap();
134
135 let parsed = serde_json::from_str::<InstanceJson>(&content);
136
137 if let Ok(instance_json) = parsed {
138 return Instance::from_id(instance_json.id);
139 }
140
141 return None;
142 }
143
144 pub fn get_active_instance(game: KSPGame) -> Option<Instance> {
145 let instance_info_file = (match game {
146 KSPGame::KSP1 => find_ksp1_install_dir(),
147 KSPGame::KSP2 => find_ksp2_install_dir(),
148 })
149 .join("instance.json");
150
151 if instance_info_file.exists() {
152 let instance = Instance::load_from_file(instance_info_file);
153
154 return instance;
155 }
156
157 return None;
158 }
159
160 pub fn enable(&self) {
161 let active = Instance::get_active_instance(self.game.clone());
162
163 if let Some(instance) = active {
164 instance.disable();
165 }
166
167 for instance_mod in self.mods.clone() {
168 for path in instance_mod.paths {
169 let local_path = self.install_path.join(path.clone());
170
171 let saved_path = get_data_dir()
172 .join("instances")
173 .join(self.id.to_string())
174 .join(path);
175
176 copy_dir_all(saved_path, local_path).unwrap();
177 }
178 }
179 }
180
181 pub fn disable(&self) {
182 for instance_mod in self.mods.clone() {
183 for path in instance_mod.paths {
184 let local_path = self.install_path.join(path.clone());
185
186 let saved_path = get_data_dir()
187 .join("instances")
188 .join(self.id.to_string())
189 .join(path);
190
191 copy_dir_all(local_path.clone(), saved_path).unwrap();
192 remove_dir_all(local_path).unwrap();
193 }
194 }
195 }
196}