homm5_scaner/entity/
spell.rs

1use super::{configure_path, CollectFiles, FileObjects, FileStructure, Output, Scan};
2use quick_xml::{Reader, events::Event};
3use std::collections::HashMap;
4use homm5_types::{common::FileRef, spell::SpellShared};
5
6impl Output for SpellShared {
7    type ID = u16;
8    fn to_lua(&self, id: Option<Self::ID>) -> String {
9        let is_aimed = if self.IsAimed == true {"1"} else {"nil"};
10        let is_area = if self.IsAreaAttack == true {"1"} else {"nil"};
11        format!(
12            "\t[{}] = {{
13        name = \"{}\",
14        desc = \"{}\",
15        icon = \"{}\",
16        school = {},
17        level = {},
18        is_aimed = {},
19        is_area = {}
20    }},\n", 
21            id.unwrap(),
22            self.NameFileRef.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()), 
23            self.LongDescriptionFileRef.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()),
24            self.Texture.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()),
25            self.MagicSchool,
26            self.Level,
27            is_aimed,
28            is_area
29        )
30    }
31
32    fn to_json(&self) -> String {
33        serde_json::to_string_pretty(self).unwrap()
34    }
35}
36
37pub struct SpellFileCollector { 
38}
39
40impl CollectFiles for SpellFileCollector {
41    fn collect(&self, files: &HashMap<String, FileStructure>, collected_files: &mut Vec<(String, FileStructure)>) {
42        let spells_xdb = files.iter()
43        .find(|f| f.0 == "GameMechanics/RefTables/UndividedSpells.xdb".to_lowercase().as_str())
44        .unwrap();
45    let mut buf = Vec::new();
46    let mut reader = Reader::from_str(spells_xdb.1.content.as_str());
47    reader.trim_text(true);
48    reader.expand_empty_elements(true);
49    loop {
50        match reader.read_event_into(&mut buf) {
51            Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
52            Ok(Event::Eof) => break,
53            Ok(Event::Start(e)) => {
54                match e.name().as_ref() {
55                    b"objects" => {
56                        let end = e.to_end().into_owned();
57                        let text = reader.read_text(end.name()).unwrap().to_string();
58                        let text = format!("<objects>{}</objects>", text);
59                        let spells_de: Result<FileObjects, quick_xml::DeError> = quick_xml::de::from_str(&text);
60                        match spells_de {
61                            Ok(spells) => {
62                                for spell in spells.objects {
63                                    match spell.Obj {
64                                        Some(obj) => {
65                                            match obj.href.as_ref() {
66                                                Some(href) => {
67                                                    let spell_key = href
68                                                        .replace("#xpointer(/Spell)", "")
69                                                        .trim_start_matches("/")
70                                                        .to_lowercase();
71                                                    let spell_entity = files.get(&spell_key);
72                                                    match spell_entity {
73                                                        Some(entity) => {
74                                                            collected_files.push((spell_key.clone(), entity.clone()));
75                                                        },
76                                                        None => println!("Key {} is not in files", &spell_key)
77                                                    }
78                                                },
79                                                None => {}
80                                            }
81                                        }
82                                        None => {}
83                                    }
84                                }
85                            },
86                            Err(e) => println!("Error deserializing spells.xdb, {}", e.to_string())
87                        }
88                    }
89                    _=> {}
90                }
91            }
92            _ => ()
93        }
94        buf.clear();
95    }
96    }
97}
98
99pub struct SpellScaner {
100    pub id: u16
101}
102
103impl Scan<u16> for SpellScaner {
104    fn scan(&mut self, file_key: &String, entity: &String, files: &HashMap<String, FileStructure>) -> Option<Box<dyn Output<ID = u16>>> {
105        let mut buf = Vec::new();
106        let mut reader = Reader::from_str(entity);
107        reader.trim_text(true);
108        reader.expand_empty_elements(true);
109        loop {
110            match reader.read_event_into(&mut buf) {
111                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
112                Ok(Event::Eof) => break None,
113                Ok(Event::Start(e)) => {
114                    match e.name().as_ref() {
115                        b"Spell" => {
116                            let end = e.to_end().into_owned();
117                            let possible_text = reader.read_text(end.name());
118                            match possible_text {
119                                Ok(text) => {
120                                    let text = text.to_string();
121                                    let de_res: Result<SpellShared, quick_xml::DeError> = quick_xml::de::from_str(
122                                        &format!("<Spell>{}</Spell>", text)
123                                    );
124                                    match de_res {
125                                        Ok(mut spell) => {
126                                            let name = configure_path(spell.NameFileRef.as_ref().unwrap().href.as_ref(), file_key, files);
127                                            let desc = configure_path(spell.LongDescriptionFileRef.as_ref().unwrap().href.as_ref(), file_key, files);
128                                            let icon_key = spell.Texture.as_ref().unwrap().href.as_ref().unwrap_or(&String::new())
129                                                .replace("#xpointer(/Texture)", "")
130                                                .to_lowercase();
131                                            let icon = configure_path(Some(&icon_key), file_key, files);
132                                            spell.NameFileRef = Some(FileRef { href: Some(name) });
133                                            spell.LongDescriptionFileRef = Some(FileRef { href: Some(desc) });
134                                            spell.Texture = Some(FileRef { href: Some(icon) });
135                                            self.id+=1;
136                                            break Some(Box::new(spell));
137                                        }
138                                        Err(e) => {
139                                            println!("error while deserializing file key {}, {:?}", file_key, e.to_string());
140                                        }
141                                    }
142                                },
143                                Err(_e) => println!("error reading file content: {}", file_key)
144                            }
145                        }
146                        _=> {}
147                    }
148                }
149                _ => ()
150            }
151            buf.clear();
152        }
153    }
154
155    fn get_id(&self) -> Option<u16> {
156        Some(self.id)
157    }
158}