homm5_scaner/entity/
hero.rs

1use crate::{
2    entity::{Scan, Output, configure_path, CollectFiles},
3    pak::FileStructure
4};
5use quick_xml::{Reader, events::Event};
6use std::collections::HashMap;
7use homm5_types::{common::FileRef, hero::AdvMapHeroShared};
8
9impl Output for AdvMapHeroShared {
10    type ID = String;
11    fn to_lua(&self, _id: Option<String>) -> String {
12        let is_scenario_lua = if self.ScenarioHero == true {"1"} else {"nil"};
13        format!(
14            "\t[\"{}\"] = {{
15        is_scenario = {},
16        hero_class = {},
17        spec = {},
18        spec_name = \"{}\",
19        spec_desc = \"{}\",
20        spec_icon = \"{}\",
21        icon = \"{}\",
22        town = {},
23        name = \"{}\",
24        bio = \"{}\"
25    }},\n", 
26            self.InternalName, 
27            is_scenario_lua, 
28            self.Class, 
29            self.Specialization, 
30            self.SpecializationNameFileRef.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()), 
31            self.SpecializationDescFileRef.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()), 
32            self.SpecializationIcon.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()), 
33            self.FaceTexture.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()),
34            self.TownType,
35            self.Editable.NameFileRef.as_ref().unwrap().href.as_ref().unwrap_or(&String::new()),
36            self.Editable.BiographyFileRef.as_ref().unwrap().href.as_ref().unwrap_or(&String::new())
37        )
38    }
39
40    fn to_json(&self) -> String {
41        serde_json::to_string_pretty(self).unwrap()
42    }
43}
44
45pub struct HeroFileCollector {}
46
47impl CollectFiles for HeroFileCollector {
48    fn collect(&self, files: &HashMap<String, FileStructure>, collected_files: &mut Vec<(String, FileStructure)>) {
49        files.iter()
50            .filter(|f| {
51                f.1.content.contains("AdvMapHeroShared") && f.1.content.contains("ScenarioHero")
52            })
53            .for_each(|f| {
54                collected_files.push((f.0.clone(), f.1.clone()))
55            });
56    }
57}
58
59pub struct HeroScaner {}
60
61impl Scan<String> for HeroScaner {
62    fn scan(&mut self, file_key: &String, entity: &String, files: &HashMap<String, FileStructure>) -> Option<Box<dyn Output<ID = String>>> {
63        let mut buf = Vec::new();
64        let mut reader = Reader::from_str(entity);
65        reader.trim_text(true);
66        reader.expand_empty_elements(true);
67        loop {
68            match reader.read_event_into(&mut buf) {
69                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
70                Ok(Event::Eof) => break None,
71                Ok(Event::Start(e)) => {
72                    match e.name().as_ref() {
73                        b"AdvMapHeroShared" => {
74                            let end = e.to_end().into_owned();
75                            let possible_text = reader.read_text(end.name());
76                            match possible_text {
77                                Ok(text) => {
78                                    let text = text.to_string();
79                                    let de_res: Result<AdvMapHeroShared, quick_xml::DeError> = quick_xml::de::from_str(&format!("<AdvMapHeroShared>{}</AdvMapHeroShared>", text));
80                                    match de_res {
81                                        Ok(mut hero) => {
82                                            let spec_name = configure_path(hero.SpecializationNameFileRef.as_ref().unwrap().href.as_ref(), file_key, files);
83                                            let spec_desc = configure_path(hero.SpecializationDescFileRef.as_ref().unwrap().href.as_ref(), file_key, files);
84                                            let spec_icon = configure_path(
85                                                Some(&hero.SpecializationIcon.as_ref().unwrap().href.as_ref()
86                                                    .unwrap_or(&String::new()).replace("#xpointer(/Texture)", "")), 
87                                                    file_key, 
88                                                    files
89                                            );
90                                            let icon = configure_path(
91                                                Some(&hero.FaceTexture.as_ref().unwrap().href.as_ref()
92                                                .unwrap_or(&String::new()).replace("#xpointer(/Texture)", "")), 
93                                                file_key, 
94                                                files
95                                            );
96                                            let name = configure_path(hero.Editable.NameFileRef.as_ref().unwrap().href.as_ref(), file_key, files);
97                                            let bio = configure_path(hero.Editable.BiographyFileRef.as_ref().unwrap().href.as_ref(), file_key, files);
98                                            hero.SpecializationNameFileRef = Some(FileRef { href: Some(spec_name) });
99                                            hero.SpecializationDescFileRef = Some(FileRef { href: Some(spec_desc) });
100                                            hero.SpecializationIcon = Some(FileRef { href: Some(spec_icon) });
101                                            hero.FaceTexture = Some(FileRef { href: Some(icon) });
102                                            hero.Editable.NameFileRef = Some(FileRef { href: Some(name) });
103                                            hero.Editable.BiographyFileRef = Some(FileRef { href: Some(bio) });
104                                            break Some(Box::new(hero));
105                                        }
106                                        Err(e) => {
107                                            println!("error while deserializing {:?}", e.to_string());
108                                        }
109                                    }
110                                },
111                                Err(e) => println!("error reading file content: {}, {}", file_key, e.to_string())
112                            }
113                        }
114                        _=> {}
115                    }
116                }
117                _ => ()
118            }
119            buf.clear();
120        }
121    }
122
123    fn get_id(&self) -> Option<String> {
124        None
125    }
126
127}