rpfm_lib/files/trade_routes/
mod.rs1use getset::*;
32use serde_derive::{Deserialize, Serialize};
33
34use crate::binary::{ReadBytes, WriteBytes};
35use crate::error::{Result, RLibError};
36use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
37use crate::utils::check_size_mismatch;
38
39pub const EXTENSION: &str = ".ptd";
41
42pub const SIGNATURE: &[u8; 8] = b"\x89PTD\r\n\x1a\n";
44
45const SUPPORTED_VERSION: u32 = 1;
47
48#[cfg(test)] mod trade_routes_test;
49
50#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
56#[getset(get = "pub", get_mut = "pub", set = "pub")]
57pub struct TradeRoutes {
58
59 version: u32,
61
62 regions: Vec<String>,
64
65 splines: Vec<TradeSpline>,
67
68 region_routes: Vec<TradeRoute>,
70
71 port_routes: Vec<TradeRoute>,
73
74 trailer: u32,
76}
77
78#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
80#[getset(get = "pub", get_mut = "pub", set = "pub")]
81pub struct TradeSpline {
82
83 flags: [bool; 4],
85
86 segments: Vec<TradeSplineSegment>,
88}
89
90#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
92#[getset(get = "pub", get_mut = "pub", set = "pub")]
93pub struct TradeSplineSegment {
94
95 start: (u16, u16),
97
98 start_control: (i16, i16),
100
101 end_control: (i16, i16),
103
104 end: (u16, u16),
106}
107
108#[derive(Default, PartialEq, Eq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
110#[getset(get = "pub", get_mut = "pub", set = "pub")]
111pub struct TradeRoute {
112
113 from: u32,
115
116 to: u32,
118
119 edges: Vec<TradeRouteEdge>,
121}
122
123#[derive(Default, PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)]
126pub struct TradeRouteEdge(u32);
127
128impl Decodeable for TradeRoutes {
133
134 fn decode<R: ReadBytes>(data: &mut R, _extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
135 let signature = data.read_slice(SIGNATURE.len(), false)?;
136 if signature != SIGNATURE {
137 return Err(RLibError::DecodingPTDUnsupportedSignature(signature));
138 }
139
140 let version = data.read_u32()?;
141 if version != SUPPORTED_VERSION {
142 return Err(RLibError::DecodingPTDUnsupportedVersion(version));
143 }
144
145 let region_count = data.read_u32()?;
146 let regions = (0..region_count).map(|_| data.read_sized_string_u8_u32()).collect::<Result<Vec<_>>>()?;
147
148 let spline_count = data.read_u32()?;
149 let splines = (0..spline_count).map(|_| TradeSpline::decode(data)).collect::<Result<Vec<_>>>()?;
150
151 let region_routes = TradeRoute::decode_list(data)?;
152 let port_routes = TradeRoute::decode_list(data)?;
153 let trailer = data.read_u32()?;
154
155 check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
156
157 Ok(Self {
158 version,
159 regions,
160 splines,
161 region_routes,
162 port_routes,
163 trailer,
164 })
165 }
166}
167
168impl Encodeable for TradeRoutes {
169
170 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, _extra_data: &Option<EncodeableExtraData>) -> Result<()> {
171 buffer.write_all(SIGNATURE)?;
172 buffer.write_u32(self.version)?;
173
174 buffer.write_u32(self.regions.len() as u32)?;
175 for region in &self.regions {
176 buffer.write_sized_string_u8_u32(region)?;
177 }
178
179 buffer.write_u32(self.splines.len() as u32)?;
180 for spline in &self.splines {
181 spline.encode(buffer)?;
182 }
183
184 TradeRoute::encode_list(&self.region_routes, buffer)?;
185 TradeRoute::encode_list(&self.port_routes, buffer)?;
186 buffer.write_u32(self.trailer)?;
187 Ok(())
188 }
189}
190
191impl TradeSpline {
192
193 fn decode<R: ReadBytes>(data: &mut R) -> Result<Self> {
194 let mut flags = [false; 4];
195 for flag in &mut flags {
196 *flag = data.read_bool()?;
197 }
198
199 let segment_count = data.read_u32()?;
200 let segments = (0..segment_count).map(|_| TradeSplineSegment::decode(data)).collect::<Result<Vec<_>>>()?;
201 Ok(Self { flags, segments })
202 }
203
204 fn encode<W: WriteBytes>(&self, buffer: &mut W) -> Result<()> {
205 for flag in self.flags {
206 buffer.write_bool(flag)?;
207 }
208
209 buffer.write_u32(self.segments.len() as u32)?;
210 for segment in &self.segments {
211 segment.encode(buffer)?;
212 }
213 Ok(())
214 }
215}
216
217impl TradeSplineSegment {
218
219 fn decode<R: ReadBytes>(data: &mut R) -> Result<Self> {
220 Ok(Self {
221 start: (data.read_u16()?, data.read_u16()?),
222 start_control: (data.read_i16()?, data.read_i16()?),
223 end_control: (data.read_i16()?, data.read_i16()?),
224 end: (data.read_u16()?, data.read_u16()?),
225 })
226 }
227
228 fn encode<W: WriteBytes>(&self, buffer: &mut W) -> Result<()> {
229 buffer.write_u16(self.start.0)?;
230 buffer.write_u16(self.start.1)?;
231 buffer.write_i16(self.start_control.0)?;
232 buffer.write_i16(self.start_control.1)?;
233 buffer.write_i16(self.end_control.0)?;
234 buffer.write_i16(self.end_control.1)?;
235 buffer.write_u16(self.end.0)?;
236 buffer.write_u16(self.end.1)
237 }
238}
239
240impl TradeRoute {
241
242 pub fn new(from: u32, to: u32, edges: Vec<TradeRouteEdge>) -> Self {
244 Self { from, to, edges }
245 }
246
247 fn decode_list<R: ReadBytes>(data: &mut R) -> Result<Vec<Self>> {
249 let count = data.read_u32()?;
250 (0..count).map(|_| {
251 let from = data.read_u32()?;
252 let to = data.read_u32()?;
253 let edge_count = data.read_u32()?;
254 let edges = (0..edge_count).map(|_| data.read_u32().map(TradeRouteEdge)).collect::<Result<Vec<_>>>()?;
255 Ok(Self { from, to, edges })
256 }).collect()
257 }
258
259 fn encode_list<W: WriteBytes>(routes: &[Self], buffer: &mut W) -> Result<()> {
261 buffer.write_u32(routes.len() as u32)?;
262 for route in routes {
263 buffer.write_u32(route.from)?;
264 buffer.write_u32(route.to)?;
265 buffer.write_u32(route.edges.len() as u32)?;
266 for edge in &route.edges {
267 buffer.write_u32(edge.0)?;
268 }
269 }
270 Ok(())
271 }
272}
273
274impl TradeRouteEdge {
275
276 pub fn new(value: u32) -> Self {
278 Self(value)
279 }
280
281 pub fn value(&self) -> u32 {
283 self.0
284 }
285
286 pub fn spline(&self) -> usize {
288 (self.0 / 2) as usize
289 }
290
291 pub fn is_reversed(&self) -> bool {
293 self.0 % 2 == 1
294 }
295}