Skip to main content

maple_render_core/
repository.rs

1use std::{
2    collections::HashMap,
3    io::{Cursor, Read, Seek},
4};
5#[cfg(not(target_arch = "wasm32"))]
6use std::{fs::File, io::BufReader, path::Path};
7
8use image::RgbaImage;
9use zip::ZipArchive;
10
11use crate::{
12    error::{Error, Result},
13    mapping::Mapping,
14    template::Template,
15};
16
17trait ReadSeek: Read + Seek {}
18impl<T: Read + Seek> ReadSeek for T {}
19
20pub struct Repository {
21    zip: ZipArchive<Box<dyn ReadSeek>>,
22    pub template: Template,
23    mappings: HashMap<i32, Mapping>,
24    peak_cache_count: usize,
25}
26
27impl Repository {
28    #[cfg(not(target_arch = "wasm32"))]
29    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
30        let path = path.as_ref();
31
32        if !path.exists() {
33            return Err(Error::FileNotFound(path.to_path_buf()));
34        }
35
36        let file = File::open(path)?;
37        let reader: Box<dyn ReadSeek> = Box::new(BufReader::new(file));
38        Self::load_from_reader(reader)
39    }
40
41    pub fn load_from_bytes(bytes: Vec<u8>) -> Result<Self> {
42        let reader: Box<dyn ReadSeek> = Box::new(Cursor::new(bytes));
43        Self::load_from_reader(reader)
44    }
45
46    fn load_from_reader(reader: Box<dyn ReadSeek>) -> Result<Self> {
47        let mut zip = ZipArchive::new(reader)?;
48
49        let template_json = Self::load_text_from_zip(&mut zip, "template.json")?;
50        let template: Template = serde_json::from_str(&template_json)?;
51
52        Ok(Repository { zip, template, mappings: HashMap::new(), peak_cache_count: 0 })
53    }
54
55    fn load_text_from_zip<R: Read + Seek>(zip: &mut ZipArchive<R>, name: &str) -> Result<String> {
56        let mut file = zip.by_name(name).map_err(|_| Error::MissingFile(name.to_string()))?;
57        let mut contents = String::new();
58        file.read_to_string(&mut contents)?;
59        Ok(contents)
60    }
61
62    fn load_image(&mut self, name: &str) -> Result<RgbaImage> {
63        let mut file = self.zip.by_name(name).map_err(|_| Error::MissingFile(name.to_string()))?;
64        let mut data = Vec::new();
65        file.read_to_end(&mut data)?;
66        let img = image::load_from_memory(&data)?;
67        Ok(img.to_rgba8())
68    }
69
70    fn load_frame(&mut self, frame: i32) -> Result<Mapping> {
71        let light_name = format!("frame{}_light.png", frame);
72        let dark_name = format!("frame{}_dark.png", frame);
73        let map_name = format!("frame{}_map.png", frame);
74        let sel_name = format!("frame{}_sel.png", frame);
75        let transparent_name = format!("frame{}_transparent.png", frame);
76
77        let light = self.load_image(&light_name)?;
78        let dark = self.load_image(&dark_name)?;
79        let map1 = self.load_image(&map_name)?;
80        let map2 = self.load_image(&sel_name)?;
81
82        let neutral = match self.load_image(&transparent_name) {
83            Ok(img) => img,
84            Err(_) => light.clone(),
85        };
86
87        Ok(Mapping {
88            light,
89            dark,
90            map1,
91            map2,
92            neutral,
93            scale: 1,
94            light_name,
95            dark_name,
96            map1_name: map_name,
97            map2_name: sel_name,
98            neutral_name: transparent_name,
99            smooth_cache: std::sync::OnceLock::new(),
100        })
101    }
102
103    pub fn get_mapping(&mut self, index: i32) -> Result<&Mapping> {
104        let actual_index = if !self.template.is_animation() { 0 } else { index };
105
106        if !self.mappings.contains_key(&actual_index) {
107            let mapping = self.load_frame(actual_index)?;
108            self.mappings.insert(actual_index, mapping);
109
110            if self.mappings.len() > self.peak_cache_count {
111                self.peak_cache_count = self.mappings.len();
112            }
113        }
114
115        Ok(self.mappings.get(&actual_index).unwrap())
116    }
117
118    pub fn remove_mapping(&mut self, index: i32) {
119        self.mappings.remove(&index);
120    }
121
122    pub fn take_mapping(&mut self, index: i32) -> Result<Mapping> {
123        let actual_index = if !self.template.is_animation() { 0 } else { index };
124
125        if !self.mappings.contains_key(&actual_index) {
126            let mapping = self.load_frame(actual_index)?;
127            return Ok(mapping);
128        }
129
130        Ok(self.mappings.remove(&actual_index).unwrap())
131    }
132
133    pub fn is_animation(&self) -> bool {
134        self.template.is_animation()
135    }
136
137    pub fn length(&self) -> u32 {
138        self.template.frames
139    }
140
141    pub fn get_palette(&self) -> Vec<i32> {
142        self.template.palette.clone()
143    }
144
145    pub fn get_period(&self) -> f64 {
146        self.template.period()
147    }
148
149    pub fn get_hold(&self) -> f64 {
150        self.template.hold
151    }
152
153    pub fn peak(&self) -> usize {
154        self.peak_cache_count
155    }
156}