Skip to main content

bladeink/story/
state.rs

1use crate::{
2    path::Path, story::Story, story_error::StoryError, story_state::StoryState,
3    value_type::ValueType,
4};
5
6/// # State
7/// Methods to read and write story state.
8impl Story {
9    #[inline]
10    pub(crate) fn get_state(&self) -> &StoryState {
11        &self.state
12    }
13
14    #[inline]
15    pub(crate) fn get_state_mut(&mut self) -> &mut StoryState {
16        &mut self.state
17    }
18
19    pub(crate) fn reset_globals(&mut self) -> Result<(), StoryError> {
20        if self
21            .main_content_container
22            .named_content
23            .contains_key("global decl")
24        {
25            let original_pointer = self.get_state().get_current_pointer().clone();
26
27            self.choose_path(
28                &Path::new_with_components_string(Some("global decl")),
29                false,
30            )?;
31
32            // Continue, but without validating external bindings,
33            // since we may be doing this reset at initialisation time.
34            self.continue_internal(0.0)?;
35
36            self.get_state().set_current_pointer(original_pointer);
37        }
38
39        self.get_state_mut()
40            .variables_state
41            .snapshot_default_globals();
42
43        Ok(())
44    }
45
46    /// Set the value of a named global ink variable.
47    /// The types available are the standard ink types.
48    pub fn set_variable(
49        &mut self,
50        variable_name: &str,
51        value_type: &ValueType,
52    ) -> Result<(), StoryError> {
53        let notify_observers = self
54            .get_state_mut()
55            .variables_state
56            .set(variable_name, value_type.clone())?;
57
58        if notify_observers {
59            self.notify_variable_changed(variable_name, value_type);
60        }
61
62        Ok(())
63    }
64
65    /// Get the value of a named global ink variable.
66    /// The types available are the standard ink types.
67    pub fn get_variable(&self, variable_name: &str) -> Option<ValueType> {
68        self.get_state().variables_state.get(variable_name)
69    }
70
71    pub(crate) fn restore_state_snapshot(&mut self) {
72        // Patched state had temporarily hijacked our
73        // VariablesState and set its own callstack on it,
74        // so we need to restore that.
75        // If we're in the middle of saving, we may also
76        // need to give the VariablesState the old patch.
77        self.state_snapshot_at_last_new_line
78            .as_mut()
79            .unwrap()
80            .restore_after_patch(); // unwrap: state_snapshot_at_last_new_line checked Some in previous fn
81
82        self.state = self.state_snapshot_at_last_new_line.take().unwrap();
83
84        // If save completed while the above snapshot was
85        // active, we need to apply any changes made since
86        // the save was started but before the snapshot was made.
87        if !self.async_saving {
88            self.get_state_mut().apply_any_patch();
89        }
90    }
91
92    pub(crate) fn state_snapshot(&mut self) {
93        // tmp_state contains the new state and current state is stored in snapshot
94        let mut tmp_state = self.state.copy_and_start_patching(false);
95        std::mem::swap(&mut tmp_state, &mut self.state);
96        self.state_snapshot_at_last_new_line = Some(tmp_state);
97    }
98
99    pub(crate) fn discard_snapshot(&mut self) {
100        // Normally we want to integrate the patch
101        // into the main global/counts dictionaries.
102        // However, if we're in the middle of async
103        // saving, we simply stay in a "patching" state,
104        // albeit with the newer cloned patch.
105
106        if !self.async_saving {
107            self.get_state_mut().apply_any_patch();
108        }
109
110        // No longer need the snapshot.
111        self.state_snapshot_at_last_new_line = None;
112    }
113
114    /// Exports the current state to JSON format, in order to save the game.
115    pub fn save_state(&self) -> Result<String, StoryError> {
116        self.get_state().to_json()
117    }
118
119    /// Loads a previously saved state in JSON format.
120    pub fn load_state(&mut self, json_state: &str) -> Result<(), StoryError> {
121        self.get_state_mut().load_json(json_state)
122    }
123
124    /// Reset the Story back to its initial state as it was when it was first constructed.
125    pub fn reset_state(&mut self) -> Result<(), StoryError> {
126        self.if_async_we_cant("ResetState")?;
127
128        self.state = StoryState::new(
129            self.main_content_container.clone(),
130            self.list_definitions.clone(),
131        );
132
133        self.reset_globals()?;
134
135        Ok(())
136    }
137}