1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::fmt;
use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;

use crate::dh;

use super::address::Address;
use super::data::{
    Attr, Buff, Effect, FighterAbil, Item, ItemAttrs, ItemEffects, ItemFighterAbils, ItemGroup, ItemSkillMap, Metadata,
    MutaAttrMods, MutaItemConvs,
};
use super::error::{Error, FromPath, Result};
use super::fsd;

pub struct PhobosHandler {
    base_path: PathBuf,
}
impl PhobosHandler {
    pub fn new<T: Into<PathBuf>>(path: T) -> PhobosHandler {
        PhobosHandler { base_path: path.into() }
    }
    fn read_file(&self, addr: &Address) -> io::Result<Vec<u8>> {
        let full_path = addr.get_full_path(&self.base_path);
        let mut bytes = Vec::new();
        File::open(full_path)?.read_to_end(&mut bytes)?;
        Ok(bytes)
    }
    fn read_json(&self, addr: &Address) -> Result<serde_json::Value> {
        let bytes = self
            .read_file(addr)
            .map_err(|e| Error::from_path(e, addr.get_part_str()))?;
        let data = serde_json::from_slice(&bytes).map_err(|e| Error::from_path(e, addr.get_part_str()))?;
        Ok(data)
    }
    fn process_fsd<T, U>(&self, folder: &'static str, file: &'static str) -> dh::Result<dh::Container<U>>
    where
        T: serde::de::DeserializeOwned + fsd::FsdMerge<U>,
    {
        let addr = Address::new(folder, file);
        let json = self.read_json(&addr)?;
        fsd::handle::<T, U>(json)
    }
}
impl fmt::Debug for PhobosHandler {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "PhobosHandler(\"{}\")", self.base_path.to_str().unwrap_or("<error>"))
    }
}
impl dh::DataHandler for PhobosHandler {
    fn get_items(&self) -> dh::Result<dh::Container<dh::Item>> {
        self.process_fsd::<Item, dh::Item>("fsd_lite", "evetypes")
    }
    fn get_item_groups(&self) -> dh::Result<dh::Container<dh::ItemGroup>> {
        self.process_fsd::<ItemGroup, dh::ItemGroup>("fsd_lite", "evegroups")
    }
    fn get_attrs(&self) -> dh::Result<dh::Container<dh::Attr>> {
        self.process_fsd::<Attr, dh::Attr>("fsd_binary", "dogmaattributes")
    }
    fn get_item_attrs(&self) -> dh::Result<dh::Container<dh::ItemAttr>> {
        self.process_fsd::<ItemAttrs, dh::ItemAttr>("fsd_binary", "typedogma")
    }
    fn get_effects(&self) -> dh::Result<dh::Container<dh::Effect>> {
        self.process_fsd::<Effect, dh::Effect>("fsd_binary", "dogmaeffects")
    }
    fn get_item_effects(&self) -> dh::Result<dh::Container<dh::ItemEffect>> {
        self.process_fsd::<ItemEffects, dh::ItemEffect>("fsd_binary", "typedogma")
    }
    fn get_fighter_abils(&self) -> dh::Result<dh::Container<dh::FighterAbil>> {
        self.process_fsd::<FighterAbil, dh::FighterAbil>("fsd_lite", "fighterabilities")
    }
    fn get_item_fighter_abils(&self) -> dh::Result<dh::Container<dh::ItemFighterAbil>> {
        self.process_fsd::<ItemFighterAbils, dh::ItemFighterAbil>("fsd_lite", "fighterabilitiesbytype")
    }
    fn get_buffs(&self) -> dh::Result<dh::Container<dh::Buff>> {
        self.process_fsd::<Buff, dh::Buff>("fsd_lite", "dbuffcollections")
    }
    fn get_item_skill_reqs(&self) -> dh::Result<dh::Container<dh::ItemSkillReq>> {
        self.process_fsd::<ItemSkillMap, dh::ItemSkillReq>("fsd_binary", "requiredskillsfortypes")
    }
    fn get_muta_item_convs(&self) -> dh::Result<dh::Container<dh::MutaItemConv>> {
        self.process_fsd::<MutaItemConvs, dh::MutaItemConv>("fsd_binary", "dynamicitemattributes")
    }
    fn get_muta_attr_mods(&self) -> dh::Result<dh::Container<dh::MutaAttrMod>> {
        self.process_fsd::<MutaAttrMods, dh::MutaAttrMod>("fsd_binary", "dynamicitemattributes")
    }
    fn get_version(&self) -> dh::Result<String> {
        let addr = Address::new("phobos", "metadata");
        let unprocessed = self.read_json(&addr)?;
        let metadatas: Vec<Metadata> =
            serde_json::from_value(unprocessed).map_err(|e| Error::from_path(e, addr.get_part_str()))?;
        for metadata in metadatas {
            if metadata.field_name == "client_build" {
                return Ok(metadata.field_value.to_string());
            }
        }
        Err(Error::new("unable to find client build").into())
    }
}