1use std::collections::{
2 hash_map::{self, Entry},
3 HashMap,
4};
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::{
10 definition::osrs::{
11 Definition, FetchDefinition, InventoryDefinition, ItemDefinition, LocationDefinition,
12 MapDefinition, NpcDefinition, ObjectDefinition, VarbitDefinition,
13 },
14 Cache,
15};
16
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19#[derive(Clone, Eq, PartialEq, Debug, Default)]
20pub struct ItemLoader(HashMap<u16, ItemDefinition>);
21
22impl_osrs_loader!(ItemLoader, ItemDefinition, index_id: 2, archive_id: 10);
23
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26#[derive(Clone, Eq, PartialEq, Debug, Default)]
27pub struct NpcLoader(HashMap<u16, NpcDefinition>);
28
29impl_osrs_loader!(NpcLoader, NpcDefinition, index_id: 2, archive_id: 9);
30
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[derive(Clone, Eq, PartialEq, Debug, Default)]
34pub struct ObjectLoader(HashMap<u16, ObjectDefinition>);
35
36impl_osrs_loader!(ObjectLoader, ObjectDefinition, index_id: 2, archive_id: 6);
37
38#[derive(Clone, Eq, PartialEq, Debug, Default)]
40#[cfg_attr(feature = "serde-derive", derive(Serialize, Deserialize))]
41pub struct InventoryLoader(HashMap<u16, InventoryDefinition>);
42
43impl_osrs_loader!(InventoryLoader, InventoryDefinition, index_id: 2, archive_id: 5);
44
45#[derive(Clone, Eq, PartialEq, Debug, Default)]
47#[cfg_attr(feature = "serde-derive", derive(Serialize, Deserialize))]
48pub struct VarbitLoader(HashMap<u16, VarbitDefinition>);
49
50impl_osrs_loader!(VarbitLoader, VarbitDefinition, index_id: 2, archive_id: 14);
51
52#[derive(Debug)]
54pub struct MapLoader<'cache> {
55 cache: &'cache Cache,
56 maps: HashMap<u16, MapDefinition>,
57}
58
59impl<'cache> MapLoader<'cache> {
60 pub fn new(cache: &'cache Cache) -> Self {
66 Self {
67 cache,
68 maps: HashMap::new(),
69 }
70 }
71
72 pub fn load(&mut self, id: u16) -> crate::Result<&MapDefinition> {
73 if let Entry::Vacant(entry) = self.maps.entry(id) {
74 let x = id >> 8;
75 let y = id & 0xFF;
76
77 let map_archive = self.cache.archive_by_name(5, format!("m{}_{}", x, y))?;
78 let buffer = self.cache.read_archive(map_archive)?.decode()?;
79
80 entry.insert(MapDefinition::new(id, &buffer)?);
81 }
82
83 Ok(&self.maps[&id])
84 }
85}
86
87#[derive(Debug)]
89pub struct LocationLoader<'cache> {
90 cache: &'cache Cache,
91 locations: HashMap<u16, LocationDefinition>,
92}
93
94impl<'cache> LocationLoader<'cache> {
95 pub fn new(cache: &'cache Cache) -> Self {
101 Self {
102 cache,
103 locations: HashMap::new(),
104 }
105 }
106
107 pub fn load(&mut self, id: u16, keys: &[u32; 4]) -> crate::Result<&LocationDefinition> {
112 if let Entry::Vacant(entry) = self.locations.entry(id) {
113 let x = id >> 8;
114 let y = id & 0xFF;
115
116 let loc_archive = self.cache.archive_by_name(5, format!("l{}_{}", x, y))?;
117 let buffer = self
118 .cache
119 .read_archive(loc_archive)?
120 .with_xtea_keys(*keys)
121 .decode()?;
122
123 entry.insert(LocationDefinition::new(id, &buffer)?);
124 }
125
126 Ok(&self.locations[&id])
127 }
128}
129
130#[cfg(test)]
131mod items {
132 use super::ItemLoader;
133 use crate::test_util;
134
135 fn item_loader() -> crate::Result<ItemLoader> {
136 ItemLoader::new(&test_util::osrs_cache()?)
137 }
138
139 #[test]
140 fn blue_partyhat() -> crate::Result<()> {
141 let item_loader = item_loader()?;
142 let item = item_loader.load(1042).unwrap();
143
144 assert_eq!(item.name, "Blue partyhat");
145 assert!(!item.stackable);
146 assert!(!item.members_only);
147
148 Ok(())
149 }
150
151 #[test]
152 fn magic_logs() -> crate::Result<()> {
153 let item_loader = item_loader()?;
154 let item = item_loader.load(1513).unwrap();
155
156 assert_eq!(item.name, "Magic logs");
157 assert!(!item.stackable);
158 assert!(item.members_only);
159
160 Ok(())
161 }
162
163 #[test]
164 fn noted() -> crate::Result<()> {
165 let item_loader = item_loader()?;
166 let item = item_loader.load(1512).unwrap();
167
168 assert!(item.stackable);
169 assert!(!item.members_only);
170
171 Ok(())
172 }
173
174 #[test]
175 fn non_existent() -> crate::Result<()> {
176 let item_loader = item_loader()?;
177
178 assert!(item_loader.load(65_535).is_none());
179
180 Ok(())
181 }
182}
183
184#[cfg(test)]
185mod npcs {
186 use super::NpcLoader;
187 use crate::test_util;
188
189 fn npc_loader() -> crate::Result<NpcLoader> {
190 NpcLoader::new(&test_util::osrs_cache()?)
191 }
192
193 #[test]
194 fn woodsman_tutor() -> crate::Result<()> {
195 let npc_loader = npc_loader()?;
196 let npc = npc_loader.load(3226).unwrap();
197
198 assert_eq!(npc.name, "Woodsman tutor");
199 assert!(npc.interactable);
200
201 Ok(())
202 }
203
204 #[test]
205 fn last_valid_npc() -> crate::Result<()> {
206 let npc_loader = npc_loader()?;
207 let npc = npc_loader.load(8691).unwrap();
208
209 assert_eq!(npc.name, "Ancient Fungi");
210 assert!(npc.interactable);
211
212 Ok(())
213 }
214
215 #[test]
216 fn non_existent() -> crate::Result<()> {
217 let npc_loader = npc_loader()?;
218
219 assert!(npc_loader.load(65_535).is_none());
220
221 Ok(())
222 }
223}
224
225#[cfg(test)]
226mod objects {
227 use super::ObjectLoader;
228 use crate::test_util;
229
230 fn obj_loader() -> crate::Result<ObjectLoader> {
231 ObjectLoader::new(&test_util::osrs_cache()?)
232 }
233
234 #[test]
235 fn law_rift() -> crate::Result<()> {
236 let obj_loader = obj_loader()?;
237 let obj = obj_loader.load(25034).unwrap();
238
239 assert_eq!(obj.name, "Law rift");
240 assert_eq!(obj.animation_id, 2178);
241 assert!(obj.solid);
242 assert!(!obj.obstruct_ground);
243
244 Ok(())
245 }
246
247 #[test]
248 fn furnace() -> crate::Result<()> {
249 let obj_loader = obj_loader()?;
250 let obj = obj_loader.load(2030).unwrap();
251
252 assert_eq!(obj.name, "Furnace");
253 assert!(obj.solid);
254 assert!(!obj.obstruct_ground);
255
256 Ok(())
257 }
258
259 #[test]
260 fn bank_table() -> crate::Result<()> {
261 let obj_loader = obj_loader()?;
262 let obj = obj_loader.load(590).unwrap();
263
264 assert_eq!(obj.name, "Bank table");
265 assert_eq!(obj.supports_items, Some(1));
266 assert!(obj.solid);
267 assert!(!obj.obstruct_ground);
268
269 Ok(())
270 }
271
272 #[test]
273 fn dungeon_door() -> crate::Result<()> {
274 let obj_loader = obj_loader()?;
275 let obj = obj_loader.load(1725).unwrap();
276
277 assert_eq!(obj.name, "Dungeon door");
278 assert_eq!(obj.wall_or_door, Some(1));
279 assert_eq!(obj.supports_items, Some(0));
280 assert!(obj.solid);
281 assert!(!obj.obstruct_ground);
282
283 Ok(())
284 }
285}
286
287#[cfg(test)]
288mod locations {
289 use super::LocationLoader;
290 use crate::test_util;
291
292 #[test]
293 fn lumbridge() -> crate::Result<()> {
294 let cache = test_util::osrs_cache()?;
295
296 let keys: [u32; 4] = [1766500218, 1050654932, 397022681, 1618041309];
297
298 let mut location_loader = LocationLoader::new(&cache);
299 let location_def = location_loader.load(12850, &keys)?;
300
301 assert_eq!(location_def.region_x, 50);
302 assert_eq!(location_def.region_y, 50);
303 assert_eq!(location_def.region_base_coords(), (3200, 3200));
304 assert_eq!(location_def.data.len(), 4730);
305
306 Ok(())
307 }
308}
309
310#[cfg(test)]
311mod maps {
312 use super::MapLoader;
313 use crate::test_util;
314
315 #[test]
316 fn lumbridge() -> crate::Result<()> {
317 let cache = test_util::osrs_cache()?;
318
319 let mut map_loader = MapLoader::new(&cache);
320 let map_def = map_loader.load(12850).unwrap();
321
322 assert_eq!(map_def.region_x, 50);
323 assert_eq!(map_def.region_y, 50);
324 assert_eq!(map_def.region_base_coords(), (3200, 3200));
325
326 Ok(())
327 }
328}
329
330#[cfg(test)]
331mod inventory {
332 use super::InventoryLoader;
333 use crate::test_util;
334
335 #[test]
336 fn load_player_backpack() -> crate::Result<()> {
337 let cache = test_util::osrs_cache()?;
338 let inventory_loader = InventoryLoader::new(&cache)?;
339
340 let inventory = inventory_loader.load(93).unwrap();
341
342 assert_eq!(28, inventory.capacity.unwrap());
343
344 Ok(())
345 }
346}
347
348#[cfg(test)]
349mod varbits {
350 use super::VarbitLoader;
351 use crate::test_util;
352
353 #[test]
354 fn load_sample_varbit() -> crate::Result<()> {
355 let cache = test_util::osrs_cache()?;
356 let varbit_loader = VarbitLoader::new(&cache)?;
357
358 let chatbox_varbit = varbit_loader.load(8119).unwrap();
359
360 assert_eq!(1737, chatbox_varbit.varp_id);
361 assert_eq!(31, chatbox_varbit.least_significant_bit);
362 assert_eq!(31, chatbox_varbit.most_significant_bit);
363
364 Ok(())
365 }
366}