osrscache/definition/osrs/
obj_def.rs

1use std::{collections::HashMap, io, io::BufReader};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6use super::Definition;
7use crate::{extension::ReadExt, util};
8
9/// Contains all the information about a certain object fetched from the cache through
10/// the [ObjectLoader](../../loader/osrs/struct.ObjectLoader.html).
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[derive(Clone, Eq, PartialEq, Debug, Default)]
13pub struct ObjectDefinition {
14    pub id: u16,
15    pub name: String,
16    pub config_id: Option<u16>,
17    pub map_area_id: Option<u16>,
18    pub map_scene_id: u16,
19    pub animation_id: u16,
20    pub solid: bool,
21    pub shadow: bool,
22    pub obstruct_ground: bool,
23    pub supports_items: Option<u8>,
24    pub actions: [String; 5],
25    pub interact_type: u8,
26    pub rotated: bool,
27    pub ambient_sound_id: u16,
28    pub blocks_projectile: bool,
29    pub wall_or_door: Option<u8>,
30    pub contoured_ground: Option<u8>,
31    pub config_change_dest: Vec<u16>,
32    pub params: HashMap<u32, String>,
33    pub model_data: ObjectModelData,
34}
35
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
38pub struct ObjectModelData {
39    pub models: Vec<u16>,
40    pub types: Vec<u8>,
41    pub recolor_find: Vec<u16>,
42    pub recolor_replace: Vec<u16>,
43    pub retexture_find: Vec<u16>,
44    pub retexture_replace: Vec<u16>,
45    pub size_x: u8,
46    pub size_y: u8,
47    pub offset_x: u16,
48    pub offset_y: u16,
49    pub offset_z: u16,
50    pub model_size_x: u16,
51    pub model_size_y: u16,
52    pub model_size_z: u16,
53    pub varp_id: Option<u16>,
54    pub ambient: u8,
55    pub contrast: u8,
56    pub decord_displacement: u8,
57    pub merge_normals: bool,
58    pub blocking_mask: u8,
59}
60
61impl Definition for ObjectDefinition {
62    fn new(id: u16, buffer: &[u8]) -> crate::Result<Self> {
63        let mut reader = BufReader::new(buffer);
64        let mut obj_def = decode_buffer(id, &mut reader)?;
65        post(&mut obj_def);
66
67        Ok(obj_def)
68    }
69}
70
71fn decode_buffer(id: u16, reader: &mut BufReader<&[u8]>) -> io::Result<ObjectDefinition> {
72    let mut obj_def = ObjectDefinition {
73        id,
74        interact_type: 2,
75        blocks_projectile: true,
76        solid: true,
77        model_data: ObjectModelData {
78            decord_displacement: 16,
79            size_x: 1,
80            size_y: 1,
81            model_size_x: 128,
82            model_size_y: 128,
83            model_size_z: 128,
84            ..ObjectModelData::default()
85        },
86        ..ObjectDefinition::default()
87    };
88
89    loop {
90        let opcode = reader.read_u8()?;
91
92        match opcode {
93            0 => break,
94            1 => {
95                let len = reader.read_u8()?;
96                for _ in 0..len {
97                    obj_def.model_data.models.push(reader.read_u16()?);
98                    obj_def.model_data.types.push(reader.read_u8()?);
99                }
100            }
101            2 => {
102                obj_def.name = reader.read_string()?;
103            }
104            5 => {
105                let len = reader.read_u8()?;
106                obj_def.model_data.types.clear();
107                for _ in 0..len {
108                    obj_def.model_data.models.push(reader.read_u16()?);
109                }
110            }
111            14 => {
112                obj_def.model_data.size_x = reader.read_u8()?;
113            }
114            15 => {
115                obj_def.model_data.size_y = reader.read_u8()?;
116            }
117            17 => {
118                obj_def.interact_type = 0;
119                obj_def.blocks_projectile = false;
120            }
121            18 => {
122                obj_def.blocks_projectile = false;
123            }
124            19 => {
125                obj_def.wall_or_door = Some(reader.read_u8()?);
126            }
127            21 => {
128                obj_def.contoured_ground = Some(0);
129            }
130            22 => {
131                obj_def.model_data.merge_normals = true;
132            }
133            24 => {
134                obj_def.animation_id = reader.read_u16()?;
135            }
136            27 => {
137                obj_def.interact_type = 1;
138            }
139            28 => {
140                obj_def.model_data.decord_displacement = reader.read_u8()?;
141            }
142            29 => {
143                obj_def.model_data.ambient = reader.read_u8()?;
144            }
145            30..=34 => {
146                obj_def.actions[opcode as usize - 30] = reader.read_string()?;
147            }
148            39 => {
149                obj_def.model_data.contrast = reader.read_u8()?;
150            }
151            40 => {
152                let len = reader.read_u8()?;
153                for _ in 0..len {
154                    obj_def.model_data.recolor_find.push(reader.read_u16()?);
155                    obj_def.model_data.recolor_replace.push(reader.read_u16()?);
156                }
157            }
158            41 => {
159                let len = reader.read_u8()?;
160                for _ in 0..len {
161                    obj_def.model_data.retexture_find.push(reader.read_u16()?);
162                    obj_def
163                        .model_data
164                        .retexture_replace
165                        .push(reader.read_u16()?);
166                }
167            }
168            62 => {
169                obj_def.rotated = true;
170            }
171            64 => {
172                obj_def.shadow = true;
173            }
174            65 => {
175                obj_def.model_data.model_size_x = reader.read_u16()?;
176            }
177            66 => {
178                obj_def.model_data.model_size_z = reader.read_u16()?;
179            }
180            67 => {
181                obj_def.model_data.model_size_y = reader.read_u16()?;
182            }
183            68 => {
184                obj_def.map_scene_id = reader.read_u16()?;
185            }
186            69 => {
187                obj_def.model_data.blocking_mask = reader.read_u8()?;
188            }
189            70 => {
190                obj_def.model_data.offset_x = reader.read_u16()?;
191            }
192            71 => {
193                obj_def.model_data.offset_z = reader.read_u16()?;
194            }
195            72 => {
196                obj_def.model_data.offset_y = reader.read_u16()?;
197            }
198            73 => {
199                obj_def.obstruct_ground = true;
200            }
201            74 => {
202                obj_def.solid = false;
203            }
204            75 => {
205                obj_def.supports_items = Some(reader.read_u8()?);
206            }
207            77 => {
208                let varp_id = reader.read_u16()?;
209                obj_def.model_data.varp_id = if varp_id == std::u16::MAX {
210                    None
211                } else {
212                    Some(varp_id)
213                };
214                let config_id = reader.read_u16()?;
215                obj_def.config_id = if config_id == std::u16::MAX {
216                    None
217                } else {
218                    Some(config_id)
219                };
220                let len = reader.read_u8()?;
221                obj_def.config_change_dest = Vec::new();
222                for _ in 0..=len {
223                    obj_def.config_change_dest.push(reader.read_u16()?);
224                }
225            }
226            78 => {
227                obj_def.ambient_sound_id = reader.read_u16()?;
228                reader.read_u8()?;
229            }
230            79 => {
231                reader.read_u16()?;
232                reader.read_u16()?;
233                reader.read_u8()?;
234                let len = reader.read_u8()?;
235                for _ in 0..len {
236                    reader.read_u16()?;
237                }
238            }
239            81 => {
240                obj_def.contoured_ground = Some(reader.read_u8()?);
241            }
242            82 => {
243                obj_def.map_area_id = Some(reader.read_u16()?);
244            }
245            92 => {
246                let varp_id = reader.read_u16()?;
247                obj_def.model_data.varp_id = if varp_id == std::u16::MAX {
248                    None
249                } else {
250                    Some(varp_id)
251                };
252
253                let config_id = reader.read_u16()?;
254                obj_def.config_id = if config_id == std::u16::MAX {
255                    None
256                } else {
257                    Some(config_id)
258                };
259                // should append var at end
260                let _var = reader.read_u16()?;
261
262                let len = reader.read_u8()?;
263                obj_def.config_change_dest = Vec::new();
264                for _ in 0..=len {
265                    obj_def.config_change_dest.push(reader.read_u16()?);
266                }
267            }
268            249 => {
269                obj_def.params = util::read_parameters(reader)?;
270            }
271            23 => { /* skip */ }
272            _ => unreachable!(),
273        }
274    }
275
276    Ok(obj_def)
277}
278
279fn post(obj_def: &mut ObjectDefinition) {
280    if obj_def.wall_or_door.is_none() {
281        obj_def.wall_or_door = Some(0);
282        if !obj_def.model_data.models.is_empty()
283            && (obj_def.model_data.types.is_empty() || obj_def.model_data.types[0] == 10)
284        {
285            obj_def.wall_or_door = Some(1);
286        }
287
288        for var in 0..5 {
289            if !obj_def.actions[var].is_empty() {
290                obj_def.wall_or_door = Some(1);
291            }
292        }
293    }
294
295    if obj_def.supports_items.is_none() {
296        obj_def.supports_items = Some(if obj_def.interact_type != 0 { 1 } else { 0 });
297    }
298}