Skip to main content

polytrack_codes/v4/
mod.rs

1#[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        // prepend the "v3"
65        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}