polytrack_codes/v4/
mod.rs1#[cfg(test)]
2mod tests;
3
4use crate::tools::{self, prelude::*};
5use crate::{Block, Part, Track};
6
7pub const CP_IDS: [u8; 4] = [52, 65, 75, 77];
8
9#[derive(Debug, PartialEq, Eq, Clone)]
10pub struct V4Track {
11 pub parts: Vec<V4Part>,
12}
13#[derive(Debug, PartialEq, Eq, Clone)]
14pub struct V4Part {
15 pub id: u8,
16 pub amount: u32,
17 pub blocks: Vec<V4Block>,
18}
19#[derive(Debug, PartialEq, Eq, Clone)]
20pub struct V4Block {
21 pub x: i32,
22 pub y: i32,
23 pub z: i32,
24
25 pub rotation: u8,
26 pub cp_order: Option<u16>,
27}
28
29impl Track for V4Track {
30 type Part = V4Part;
31
32 type Metadata = ();
33 fn meta(&self) -> Self::Metadata {}
34 fn parts(&self) -> Vec<Self::Part> {
35 self.parts.clone()
36 }
37
38 fn decode_meta(_: &[u8], _: &mut usize) -> Option<Self::Metadata> {
39 Some(())
40 }
41 fn encode_meta(&self, _: &mut Vec<u8>) {}
42 fn from_data(_: Self::Metadata, parts: Vec<Self::Part>) -> Self {
43 Self { parts }
44 }
45
46 type TrackInfo = ();
47 fn decode_track_code(track_code: &str) -> Option<(String, Self::TrackInfo, Vec<u8>)> {
48 let track_code = track_code.get(2..)?;
49 let metadata = tools::decode(track_code.get(..2)?)?;
50 let name_len = *metadata.first()? as usize;
51 let track_name_raw = tools::decode(track_code.get(2..2 + name_len)?)?;
52 let name = String::from_utf8(track_name_raw).ok()?;
53 let track_data = tools::decompress(&tools::decode(track_code.get(2 + name_len..)?)?)?;
54
55 Some((name, (), track_data))
56 }
57 fn encode_track_code(name: String, _: Self::TrackInfo, track_data: &[u8]) -> Option<String> {
58 let track_data = tools::encode(&tools::compress_final(track_data)?)?;
59
60 let name_raw = name.as_bytes().to_vec();
61 let name = tools::encode(&name_raw)?;
62 let metadata = tools::encode(&[name.len() as u8])?;
63
64 let track_code = String::from("v3") + &metadata + &name + &track_data;
66 Some(track_code)
67 }
68}
69impl Part for V4Part {
70 type Block = V4Block;
71
72 fn id(&self) -> u8 {
73 self.id
74 }
75 fn amount(&self) -> u32 {
76 self.amount
77 }
78 fn blocks(&self) -> Vec<Self::Block> {
79 self.blocks.clone()
80 }
81 fn from_data(id: u8, amount: u32, blocks: Vec<Self::Block>) -> Self {
82 Self { id, amount, blocks }
83 }
84
85 fn decode_header(data: &[u8], offset: &mut usize) -> Option<(u8, u32)> {
86 Some((read_u16(data, offset)? as u8, read_u32(data, offset)?))
87 }
88 fn encode_header(&self, data: &mut Vec<u8>) {
89 write_u16(data, self.id.into());
90 write_u32(data, self.amount);
91 }
92}
93impl Block for V4Block {
94 type Track = V4Track;
95
96 type Extra = Option<u16>;
97 fn extra_data(&self) -> Self::Extra {
98 self.cp_order
99 }
100
101 type Coord = i32;
102 fn pos(&self) -> (Self::Coord, Self::Coord, Self::Coord) {
103 (self.x, self.y, self.z)
104 }
105 fn rot(&self) -> u8 {
106 self.rotation
107 }
108
109 fn decode(
110 data: &[u8],
111 offset: &mut usize,
112 id: u8,
113 _: <Self::Track as Track>::Metadata,
114 ) -> Option<Self> {
115 let x = read_i24(data, offset)? - i32::pow(2, 23);
116 let y = read_i24(data, offset)?;
117 let z = read_i24(data, offset)? - i32::pow(2, 23);
118
119 let rotation = read_u8(data, offset)? & 3;
120
121 let cp_order = if CP_IDS.contains(&id) {
122 Some(read_u16(data, offset)?)
123 } else {
124 None
125 };
126
127 Some(Self {
128 x,
129 y,
130 z,
131 rotation,
132 cp_order,
133 })
134 }
135 fn encode(&self, data: &mut Vec<u8>, _: <Self::Track as Track>::Metadata) {
136 write_u24(data, (self.x + i32::pow(2, 23)).cast_unsigned());
137 write_u24(data, self.y.cast_unsigned());
138 write_u24(data, (self.z + i32::pow(2, 23)).cast_unsigned());
139 data.push(self.rotation);
140 if let Some(cp_order) = self.cp_order {
141 write_u16(data, cp_order.into());
142 }
143 }
144}