1pub mod models;
2mod utils;
3
4use std::collections::HashMap;
5use std::fs;
6use std::path::Path;
7
8#[cfg(feature = "log")]
9use log::{trace, warn};
10use models::enchantment::SkyblockEnchantment;
11use models::item::SkyblockItem;
12use models::pet::SkyblockPet;
13pub use models::{UpgradeCost, UpgradeType, enchantment, item, pet, recipe};
14#[cfg(feature = "python")]
15use pyo3::exceptions::PyValueError;
16#[cfg(feature = "python")]
17use pyo3::prelude::*;
18#[cfg(feature = "python")]
19use pyo3::types::PyModule;
20use rustc_hash::FxHashMap;
21use serde::Deserialize;
22pub use utils::{delete_repo, download_repo};
23
24#[cfg(feature = "python")]
25#[pymodule]
26fn skyblock_repo(m: &Bound<'_, PyModule>) -> PyResult<()> {
27 m.add_class::<SkyblockRepo>()?;
28 m.add_function(pyo3::wrap_pyfunction!(download_repo, m)?)?;
29 m.add_function(pyo3::wrap_pyfunction!(delete_repo, m)?)?;
30
31 Ok(())
32}
33
34#[derive(Deserialize)]
35struct RepoStructure {
36 #[allow(dead_code)]
37 version: u8,
38 paths: HashMap<String, String>,
39}
40
41#[cfg_attr(feature = "python", pyclass)]
43pub struct SkyblockRepo {
44 pub enchantments: FxHashMap<String, SkyblockEnchantment>,
45 pub items: FxHashMap<String, SkyblockItem>,
46 pub pets: FxHashMap<String, SkyblockPet>,
47}
48
49#[cfg(feature = "python")]
50#[pymethods]
51impl SkyblockRepo {
52 #[must_use]
62 #[new]
63 pub fn new() -> PyResult<Self> {
64 let structure: RepoStructure =
65 serde_json::from_str(&fs::read_to_string("SkyblockRepo/manifest.json")?)
66 .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
67
68 let mut repo = Self {
69 enchantments: FxHashMap::default(),
70 items: FxHashMap::default(),
71 pets: FxHashMap::default(),
72 };
73
74 for path_name in structure.paths.values() {
75 let path = &format!("SkyblockRepo/{}", path_name);
76 let path = Path::new(path);
77 let data_entries = fs::read_dir(&path)?;
78
79 for json in data_entries {
80 let json = json?.path();
81 let content = fs::read_to_string(&json)?;
82
83 match path_name.as_str() {
84 | "enchantments" => {
85 let parsed: SkyblockEnchantment = serde_json::from_str(&content)
86 .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
87 repo.enchantments.insert(parsed.internal_id.clone(), parsed);
88 },
89 | "items" => {
90 let parsed: SkyblockItem = serde_json::from_str(&content)
91 .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
92 repo.items.insert(parsed.internal_id.clone(), parsed);
93 },
94 | "pets" => {
95 let parsed: SkyblockPet = serde_json::from_str(&content)
96 .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
97 repo.pets.insert(parsed.internal_id.clone(), parsed);
98 },
99 | _ => continue,
100 }
101 }
102 }
103
104 Ok(repo)
105 }
106
107 #[must_use]
109 #[inline]
110 pub fn get_enchantment_by_id(
111 &self,
112 id: &str,
113 ) -> Option<SkyblockEnchantment> {
114 self.enchantments.get(id).cloned()
115 }
116
117 #[must_use]
119 #[inline]
120 pub fn get_item_by_id(
121 &self,
122 id: &str,
123 ) -> Option<SkyblockItem> {
124 self.items.get(id).cloned()
125 }
126
127 #[must_use]
129 #[inline]
130 pub fn get_pet_by_id(
131 &self,
132 id: &str,
133 ) -> Option<SkyblockPet> {
134 self.pets.get(id).cloned()
135 }
136}
137
138#[cfg(not(feature = "python"))]
139impl SkyblockRepo {
140 pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
141 let structure: RepoStructure =
142 serde_json::from_str(&fs::read_to_string("SkyblockRepo/manifest.json")?)?;
143
144 let mut repo = Self {
145 enchantments: FxHashMap::default(),
146 items: FxHashMap::default(),
147 pets: FxHashMap::default(),
148 };
149
150 for path_name in structure.paths.values() {
151 let path = &format!("SkyblockRepo/{}", path_name);
152 let path = Path::new(path);
153 let data_entries = fs::read_dir(&path)?;
154
155 for json in data_entries {
156 let json = json?.path();
157 #[cfg(feature = "log")]
158 trace!("parsing {:?}", json);
159 let content = fs::read_to_string(&json)?;
160
161 match path_name.as_str() {
162 | "enchantments" => {
163 let parsed: SkyblockEnchantment = serde_json::from_str(&content)?;
164 repo.enchantments.insert(parsed.internal_id.clone(), parsed);
165 },
166 | "items" => {
167 let parsed: SkyblockItem = serde_json::from_str(&content)?;
168 repo.items.insert(parsed.internal_id.clone(), parsed);
169 },
170 | "pets" => {
171 let parsed: SkyblockPet = serde_json::from_str(&content)?;
172 repo.pets.insert(parsed.internal_id.clone(), parsed);
173 },
174 #[cfg_attr(not(feature = "log"), allow(unused_variables))]
175 | other => {
176 #[cfg(feature = "log")]
177 warn!("Unknown dir found while parsing SkyblockData: {}", other);
178 continue;
179 },
180 }
181 }
182 }
183
184 Ok(repo)
185 }
186
187 #[must_use]
189 #[inline]
190 pub fn get_enchantment_by_id(
191 &self,
192 id: &str,
193 ) -> Option<SkyblockEnchantment> {
194 self.enchantments.get(id).cloned()
195 }
196
197 #[must_use]
199 #[inline]
200 pub fn get_item_by_id(
201 &self,
202 id: &str,
203 ) -> Option<SkyblockItem> {
204 self.items.get(id).cloned()
205 }
206
207 #[must_use]
209 #[inline]
210 pub fn get_pet_by_id(
211 &self,
212 id: &str,
213 ) -> Option<SkyblockPet> {
214 self.pets.get(id).cloned()
215 }
216}