arrowvortex_clipboard/lib.rs
1#![warn(missing_docs)]
2
3/*!
4Small library for encoding and decoding [ArrowVortex](https://arrowvortex.ddrnl.com/) clipboard
5data. Ported from [av-clipboard-lib](https://github.com/DeltaEpsilon7787/av-clipboard-lib), a Python
6libary by DeltaEpsilon.
7
8Main credit goes to DeltaEpsilon for reverse-engineering ArrowVortex' clipboard functions and
9implementing the first ArrowVortex clipboard library.
10
11```rust
12// EtternaOnline noteskin template pattern (https://etternaonline.com/noteskins)
13let data = r#"ArrowVortex:notes:!"8i-K)chjJHuM^!#P_Z![IjrJi#:bJ2UO3!BC3L"%E"#;
14
15// Decode string into Vec<Note>
16let notes = match arrowvortex_clipboard::decode(data.as_bytes())? {
17 arrowvortex_clipboard::DecodeResult::RowBasedNotes(notes) => notes,
18 _ => panic!("Unexpected data type"),
19};
20println!("{:?}", notes);
21
22// Encode &[Note] into string
23let buffer = arrowvortex_clipboard::encode_row_based_notes(¬es)?;
24println!("{}", buffer);
25
26// Verify that string stayed identical after roundtrip
27assert_eq!(data, buffer);
28# Ok::<(), Box<dyn std::error::Error>>(())
29```
30*/
31
32mod decode;
33pub use decode::*;
34
35mod encode;
36pub use encode::*;
37
38/// Note-type specific data
39#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub enum NoteKind<P> {
41 /// Normal tap
42 Tap,
43 /// Hold note, spanning from this note's row up to end_row
44 Hold {
45 /// Where this hold note ends
46 end_pos: P,
47 },
48 /// Mine note
49 Mine,
50 /// Roll note, spanning from this note's row up to end_row
51 Roll {
52 /// Where this roll note ends
53 end_pos: P,
54 },
55 /// Lift note
56 Lift,
57 /// Fake note
58 Fake,
59}
60
61impl<P> Default for NoteKind<P> {
62 fn default() -> Self {
63 Self::Tap
64 }
65}
66
67/// Singular note
68#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
69pub struct Note<P> {
70 /// Position of this note
71 pub pos: P,
72 /// Column of this note. Left-most column is 0
73 pub column: u8,
74 /// Type and type-specific data for this note
75 pub kind: NoteKind<P>,
76}
77
78/// Tempo event type specific data
79#[derive(Debug, Clone, PartialEq)]
80pub enum TempoEventKind {
81 /// Changes BPM (beats per minute)
82 Bpm {
83 /// BPM value
84 bpm: f64,
85 },
86 /// Stops for a number of seconds
87 Stop {
88 /// Duration in seconds
89 time: f64,
90 },
91 /// Delays for a number of seconds
92 Delay {
93 /// Duration in seconds
94 time: f64,
95 },
96 /// Warps over a number of rows
97 Warp {
98 /// Length in rows
99 num_skipped_rows: u32,
100 },
101 /// Changes time signature
102 TimeSignature {
103 /// Numerator of the time signature fraction
104 numerator: u32,
105 /// Denominator of the time signature fraction
106 denominator: u32,
107 },
108 /// Changes number of ticks per beat
109 Ticks {
110 /// Number of ticks per beat
111 num_ticks: u32,
112 },
113 /// Changes combo multiplier settings
114 Combo {
115 /// Combo multiplier
116 combo_multiplier: u32,
117 /// Miss multiplier
118 miss_multiplier: u32,
119 },
120 /// Unknown
121 Speed {
122 /// Unknown
123 ratio: f64,
124 /// Unknown
125 delay: f64,
126 /// Unknown
127 delay_is_time: bool,
128 },
129 /// Changes scroll speed
130 Scroll {
131 /// Scroll speed multiplier
132 ratio: f64,
133 },
134 /// Converts all notes in the following rows into fakes
135 FakeSegment {
136 /// Length in rows
137 num_fake_rows: u32,
138 },
139 /// Label with arbitrary content
140 Label {
141 /// Message content
142 message: Vec<u8>,
143 },
144}
145
146/// Singular tempo event
147#[derive(Debug, Clone, PartialEq)]
148pub struct TempoEvent {
149 /// Row position of this tempo event
150 pub row: u32,
151 /// Type and type-specific for this tempo event
152 pub kind: TempoEventKind,
153}