sb3_decoder/structs/project.rs
1//! A project that contains all the decoded data from a Scratch 3.0 project file (.sb3).
2
3use std::collections::HashMap;
4
5use zip::ZipArchive;
6
7use crate::{
8 decoder::RawProject,
9 error::DecodeError,
10 structs::{Broadcast, Sprite, Stage, Target, Variable},
11};
12
13/// The [`Project`] struct represents a Scratch 3.0 project.
14///
15/// It contains all the decoded data from a `.sb3` file, including sprites and the stage.
16#[derive(Debug, Clone)]
17pub struct Project {
18 /// Contains all the sprites in the project.
19 pub sprites: Vec<Sprite>,
20
21 /// Contains the stage of the project.
22 pub stage: Stage,
23}
24
25impl Project {
26 /// Returns a new project from a [`RawProject`] and the zip archive.
27 ///
28 /// # Errors
29 /// Returns [`DecodeError::Zip`] if there is an error reading the ZIP archive.
30 /// Returns [`DecodeError::NotFound`] if something expected is not found in the archive or in
31 /// the JSON data.
32 pub fn new(
33 raw: RawProject,
34 zip: &mut ZipArchive<std::io::Cursor<Vec<u8>>>,
35 ) -> Result<Self, DecodeError> {
36 let mut sprites = Vec::new();
37 let mut stage = None;
38
39 for raw_target in raw.targets {
40 match Target::new(raw_target, zip)? {
41 Target::Sprite(sprite) => sprites.push(sprite),
42 Target::Stage(s) => stage = Some(s),
43 }
44 }
45
46 Ok(Self {
47 sprites,
48 stage: stage.ok_or(DecodeError::NotFound("Stage".to_string()))?,
49 })
50 }
51
52 /// Returns a reference to the global variables from the stage.
53 ///
54 /// # Example
55 ///
56 /// ```no_run
57 /// # use sb3_decoder::prelude::*;
58 /// # let mut decoder = DecoderBuilder::new()
59 /// # .use_file("path/to/project.sb3")
60 /// # .build()
61 /// # .unwrap();
62 /// let project = decoder.decode().unwrap();
63 /// let global_vars = project.global_variables();
64 /// ```
65 pub fn global_variables(&self) -> &HashMap<String, Variable> {
66 &self.stage.variables
67 }
68
69 /// Returns a mutable reference to the global variables from the stage.
70 ///
71 /// # Example
72 ///
73 /// ```no_run
74 /// # use sb3_decoder::prelude::*;
75 /// # let mut decoder = DecoderBuilder::new()
76 /// # .use_file("path/to/project.sb3")
77 /// # .build()
78 /// # .unwrap();
79 /// let mut project = decoder.decode().unwrap();
80 /// let mut global_vars = project.global_variables_mut();
81 /// ```
82 pub fn global_variables_mut(&mut self) -> &mut HashMap<String, Variable> {
83 &mut self.stage.variables
84 }
85
86 /// Returns all the broadcast messages in the project.
87 pub fn broadcasts(&self) -> Vec<Broadcast> {
88 self.stage.broadcasts.clone()
89 }
90
91 /// Returns a reference to a sprite by its name, if it exists.
92 ///
93 /// # Example
94 ///
95 /// ```no_run
96 /// # use sb3_decoder::prelude::*;
97 /// # let mut decoder = DecoderBuilder::new()
98 /// # .use_file("path/to/project.sb3")
99 /// # .build()
100 /// # .unwrap();
101 /// let project = decoder.decode().unwrap();
102 /// let sprite = project.get("Cat");
103 /// if let Some(sprite) = sprite {
104 /// // Do something with the sprite
105 /// }
106 /// ```
107 pub fn get(&self, name: &str) -> Option<&Sprite> {
108 self.sprites.iter().find(|sprite| sprite.name == name)
109 }
110
111 /// Returns a mutable reference to a sprite by its name, if it exists.
112 ///
113 /// # Example
114 ///
115 /// ```no_run
116 /// # use sb3_decoder::prelude::*;
117 /// # let mut decoder = DecoderBuilder::new()
118 /// # .use_file("path/to/project.sb3")
119 /// # .build()
120 /// # .unwrap();
121 /// let mut project = decoder.decode().unwrap();
122 /// let sprite = project.get_mut("Cat");
123 /// if let Some(sprite) = sprite {
124 /// // Do something with the sprite
125 /// }
126 /// ```
127 pub fn get_mut(&mut self, name: &str) -> Option<&mut Sprite> {
128 self.sprites.iter_mut().find(|sprite| sprite.name == name)
129 }
130}