wormhole_common/instances/
instance.rs

1use 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}