osrscache/definition/osrs/
obj_def.rs1use 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#[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 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 => { }
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}