polytrack_codes/v3/
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 V3Track {
11 pub parts: Vec<V3Part>,
12}
13#[derive(Debug, PartialEq, Eq, Clone)]
14pub struct V3Part {
15 pub id: u8,
16 pub amount: u32,
17 pub blocks: Vec<V3Block>,
18}
19#[derive(Debug, PartialEq, Eq, Clone)]
20pub struct V3Block {
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 V3Track {
30 type Part = V3Part;
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_step1 = *metadata.first()? as usize;
51 let name_len = (name_len_step1 * 4).div_ceil(3);
52 let track_name_raw = tools::decode(track_code.get(2..2 + name_len)?)?;
53 let name = String::from_utf8(track_name_raw).ok()?;
54 let track_data = tools::decompress(&tools::decode(track_code.get(2 + name_len..)?)?)?;
55
56 Some((name, (), track_data))
57 }
58 fn encode_track_code(name: String, _: Self::TrackInfo, track_data: &[u8]) -> Option<String> {
59 let track_data = tools::encode(&tools::compress_final(track_data)?)?;
60
61 let name_raw = name.as_bytes().to_vec();
62 let name = tools::encode(&name_raw)?;
63 let metadata = tools::encode(&[(name.len() * 3 / 4) as u8])?;
64
65 let track_code = String::from("v2") + &metadata + &name + &track_data;
67 Some(track_code)
68 }
69}
70impl Part for V3Part {
71 type Block = V3Block;
72
73 fn id(&self) -> u8 {
74 self.id
75 }
76 fn amount(&self) -> u32 {
77 self.amount
78 }
79 fn blocks(&self) -> Vec<Self::Block> {
80 self.blocks.clone()
81 }
82 fn from_data(id: u8, amount: u32, blocks: Vec<Self::Block>) -> Self {
83 Self { id, amount, blocks }
84 }
85
86 fn decode_header(data: &[u8], offset: &mut usize) -> Option<(u8, u32)> {
87 Some((read_u16(data, offset)? as u8, read_u32(data, offset)?))
88 }
89 fn encode_header(&self, data: &mut Vec<u8>) {
90 write_u16(data, self.id.into());
91 write_u32(data, self.amount);
92 }
93}
94impl Block for V3Block {
95 type Track = V3Track;
96
97 type Extra = Option<u16>;
98 fn extra_data(&self) -> Self::Extra {
99 self.cp_order
100 }
101
102 type Coord = i32;
103 fn pos(&self) -> (Self::Coord, Self::Coord, Self::Coord) {
104 (self.x, self.y, self.z)
105 }
106 fn rot(&self) -> u8 {
107 self.rotation
108 }
109
110 fn decode(
111 data: &[u8],
112 offset: &mut usize,
113 id: u8,
114 _: <Self::Track as Track>::Metadata,
115 ) -> Option<Self> {
116 let x = read_i24(data, offset)? - i32::pow(2, 23);
117 let y = read_i24(data, offset)?;
118 let z = read_i24(data, offset)? - i32::pow(2, 23);
119
120 let rotation = read_u8(data, offset)? & 3;
121
122 let cp_order = if CP_IDS.contains(&id) {
123 Some(read_u16(data, offset)?)
124 } else {
125 None
126 };
127
128 Some(Self {
129 x,
130 y,
131 z,
132 rotation,
133 cp_order,
134 })
135 }
136 fn encode(&self, data: &mut Vec<u8>, _: <Self::Track as Track>::Metadata) {
137 write_u24(data, (self.x + i32::pow(2, 23)).cast_unsigned());
138 write_u24(data, self.y.cast_unsigned());
139 write_u24(data, (self.z + i32::pow(2, 23)).cast_unsigned());
140 data.push(self.rotation);
141 if let Some(cp_order) = self.cp_order {
142 write_u16(data, cp_order.into());
143 }
144 }
145}