ayaka_model/
view_model.rs1use crate::*;
2use anyhow::Result;
3use serde::Serialize;
4use stream_future::stream;
5use trylog::macros::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
9#[serde(tag = "t", content = "data")]
10pub enum OpenGameStatus {
11 LoadSettings,
13 LoadGlobalRecords,
15 LoadRecords,
17 Loaded,
19}
20
21pub struct GameViewModel<S: SettingsManager, M: RawModule + Send + Sync + 'static> {
24 context: Option<Context<M>>,
25 current_record: ActionRecord,
26 current_raw_context: Option<RawContext>,
27 settings_manager: S,
28 settings: Option<Settings>,
29 records: Vec<ActionRecord>,
30 global_record: Option<GlobalRecord>,
31}
32
33impl<S: SettingsManager, M: RawModule + Send + Sync + 'static> GameViewModel<S, M> {
34 pub fn new(settings_manager: S) -> Self {
36 Self {
37 settings_manager,
38 context: None,
39 current_record: ActionRecord::default(),
40 current_raw_context: None,
41 settings: None,
42 records: vec![],
43 global_record: None,
44 }
45 }
46
47 #[stream(OpenGameStatus, lifetime = 'a)]
49 pub async fn open_game<'a>(&'a mut self, context: Context<M>) -> Result<()> {
50 yield OpenGameStatus::LoadSettings;
51 let settings = unwrap_or_default_log!(
52 self.settings_manager.load_settings(),
53 "Load settings failed"
54 );
55 self.settings = Some(settings);
56
57 yield OpenGameStatus::LoadGlobalRecords;
58 let global_record = unwrap_or_default_log!(
59 self.settings_manager
60 .load_global_record(&context.game().config.title),
61 "Load global records failed"
62 );
63 self.global_record = Some(global_record);
64
65 yield OpenGameStatus::LoadRecords;
66 self.records = unwrap_or_default_log!(
67 self.settings_manager
68 .load_records(&context.game().config.title),
69 "Load records failed"
70 );
71 self.context = Some(context);
72
73 yield OpenGameStatus::Loaded;
74
75 Ok(())
76 }
77
78 pub fn context(&self) -> &Context<M> {
80 self.context
81 .as_ref()
82 .expect("should be called after open_game")
83 }
84
85 pub fn context_mut(&mut self) -> &mut Context<M> {
87 self.context
88 .as_mut()
89 .expect("should be called after open_game")
90 }
91
92 pub fn record(&self) -> &ActionRecord {
94 &self.current_record
95 }
96
97 pub fn settings(&self) -> &Settings {
99 self.settings
100 .as_ref()
101 .expect("should be called after open_game")
102 }
103
104 pub fn set_settings(&mut self, settings: Settings) {
106 self.settings = Some(settings);
107 }
108
109 pub fn records(&self) -> &[ActionRecord] {
111 &self.records
112 }
113
114 pub fn global_record(&self) -> &GlobalRecord {
116 self.global_record
117 .as_ref()
118 .expect("should be called after open_game")
119 }
120
121 pub fn global_record_mut(&mut self) -> &mut GlobalRecord {
123 self.global_record
124 .as_mut()
125 .expect("should be called after open_game")
126 }
127
128 pub fn avaliable_locale(&self) -> impl Iterator<Item = &Locale> {
130 self.context().game().paras.keys()
131 }
132
133 pub fn init_new(&mut self) {
139 let ctx = self.context().game().start_context();
140 self.current_record = ActionRecord::default();
141 self.current_raw_context = None;
143 self.context_mut().set_context(ctx);
144 }
145
146 pub fn init_context(&mut self, record: ActionRecord) {
148 let mut ctx = record.last_ctx_with_game(self.context().game());
149 self.current_record = record;
150 self.current_raw_context = self.current_record.history.last().cloned();
152 log::debug!("Context: {:?}", self.current_raw_context);
153 ctx.cur_act += 1;
155 self.context_mut().set_context(ctx);
156 }
157
158 pub fn init_context_by_index(&mut self, index: usize) {
160 self.init_context(self.records()[index].clone())
161 }
162
163 fn push_history(&mut self, ctx: &RawContext) {
164 let cur_text = self
165 .context()
166 .game()
167 .find_para(
168 &self.context().game().config.base_lang,
169 &ctx.cur_base_para,
170 &ctx.cur_para,
171 )
172 .and_then(|p| p.texts.get(ctx.cur_act));
173 let is_text = cur_text
174 .map(|line| matches!(line, Line::Text(_)))
175 .unwrap_or_default();
176 if is_text {
177 self.current_record.history.push(ctx.clone());
178 }
179 }
180
181 pub fn next_run(&mut self) -> bool {
183 let ctx = self.context_mut().next_run();
184 if let Some(ctx) = &ctx {
185 self.push_history(ctx);
186 self.global_record_mut().update(ctx);
187 log::debug!("{ctx:?}");
188 }
189 self.current_raw_context = ctx;
190 self.current_raw_context.is_some()
191 }
192
193 pub fn next_back_run(&mut self) -> bool {
195 if self.current_record.history.len() <= 1 {
196 log::debug!("No action in the history.");
197 false
198 } else {
199 self.current_record.history.pop();
203 self.current_raw_context = self.current_record.history.last().cloned();
205 debug_assert!(self.current_raw_context.is_some());
206 let mut ctx = self
210 .current_raw_context
211 .clone()
212 .expect("current raw context cannot be None");
213 ctx.cur_act += 1;
214 self.context_mut().set_context(ctx);
215 true
216 }
217 }
218
219 pub fn current_run(&self) -> Option<&RawContext> {
221 self.current_raw_context.as_ref()
222 }
223
224 pub fn current_title(&self) -> Option<&String> {
226 self.context()
227 .current_paragraph_title(&self.settings().lang)
228 }
229
230 pub fn current_action(&self) -> Option<Action> {
232 self.current_run().map(|raw_ctx| {
233 unwrap_or_default_log!(
234 self.context().get_action(&self.settings().lang, raw_ctx),
235 "Cannot get action"
236 )
237 })
238 }
239
240 pub fn current_actions(&self) -> Option<(Action, Option<Action>)> {
242 self.current_run().map(|raw_ctx| self.get_actions(raw_ctx))
243 }
244
245 fn get_actions(&self, raw_ctx: &RawContext) -> (Action, Option<Action>) {
246 let action = unwrap_or_default_log!(
247 self.context().get_action(&self.settings().lang, raw_ctx),
248 "Cannot get action"
249 );
250 let base_action = self.settings().sub_lang.as_ref().map(|sub_lang| {
251 unwrap_or_default_log!(
252 self.context().get_action(sub_lang, raw_ctx),
253 "Cannot get sub action"
254 )
255 });
256 (action, base_action)
257 }
258
259 pub fn switch(&mut self, i: usize) {
261 log::debug!("Switch {i}");
262 self.context_mut().switch(i);
263 }
264
265 pub fn save_current_to(&mut self, index: usize) {
267 let record = self.current_record.clone();
268 if index >= self.records.len() {
269 self.records.push(record);
270 } else {
271 self.records[index] = record;
272 }
273 }
274
275 pub fn save_settings(&self) -> Result<()> {
277 let game = &self.context().game().config.title;
278 self.settings_manager.save_settings(self.settings())?;
279 self.settings_manager
280 .save_global_record(game, self.global_record())?;
281 self.settings_manager.save_records(game, self.records())?;
282 Ok(())
283 }
284
285 pub fn current_visited(&self) -> bool {
287 self.current_run()
288 .map(|ctx| self.global_record().visited(ctx))
289 .unwrap_or_default()
290 }
291
292 pub fn records_text(&self) -> impl Iterator<Item = ActionText> + '_ {
294 self.records().iter().map(|record| {
295 let raw_ctx = record
296 .last_ctx()
297 .expect("there should be at least one RawContext in the ActionRecord");
298 let action = unwrap_or_default_log!(
299 self.context().get_action(&self.settings().lang, raw_ctx),
300 "Cannot get action"
301 );
302 if let Action::Text(action) = action {
303 action
304 } else {
305 panic!("action in the record should be text action")
306 }
307 })
308 }
309
310 pub fn current_history(
312 &self,
313 ) -> impl DoubleEndedIterator<Item = (Action, Option<Action>)> + '_ {
314 self.record()
315 .history
316 .iter()
317 .map(|raw_ctx| self.get_actions(raw_ctx))
318 }
319}