1#![allow(nonstandard_style)]
2
3use std::collections::HashMap;
4use serde::{Deserialize, Serialize};
5use serde_repr::{Serialize_repr, Deserialize_repr};
6use crate::error::{Error, Result};
7use crate::types::common::{Axis, BoxFilterOrdering, Direction, DistributionKind, Easing, LightColor, RotationBehaviour, RotationDirection, LimitKind, NoteColor, SliderMidAnchorMode, TransitionKind, Difficulty, read_string_from_file, BoxFilterKind};
8
9#[derive(Serialize, Deserialize, Debug, PartialEq)]
10pub struct Info {
11 pub _version: String,
12 pub _songName: String,
13 pub _songSubName: String,
14 pub _songAuthorName: String,
15 pub _levelAuthorName: String,
16 pub _beatsPerMinute: f64,
17 pub _shuffle: f64,
18 pub _shufflePeriod: f64,
19 pub _previewStartTime: f64,
20 pub _previewDuration: f64,
21 pub _songFilename: String,
22 pub _coverImageFilename: String,
23 pub _environmentName: String,
24 #[serde(skip_serializing_if = "Option::is_none", default)]
25 pub _allDirectionsEnvironmentName : Option<String>,
26 pub _songTimeOffset: f64,
27 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
28 pub _customData: HashMap<String, serde_json::Value>,
29 pub _difficultyBeatmapSets: Vec<DifficultyBeatmapSet>
30}
31
32impl Info {
33 pub fn read_from_str(data: &str) -> Result<Self> {
34 Ok(serde_json::from_str(data)?)
35 }
36
37 pub fn read_from_file(path: &str) -> Result<Self> {
38 Self::read_from_str(&read_string_from_file(path)?)
39 }
40}
41
42#[derive(Serialize, Deserialize, Debug, PartialEq)]
43pub struct DifficultyBeatmapSet {
44 pub _beatmapCharacteristicName: String,
45 pub _difficultyBeatmaps: Vec<DifficultyBeatmap>
46}
47
48#[derive(Serialize, Deserialize, Debug, PartialEq)]
49pub struct DifficultyBeatmap {
50 pub _difficulty: Difficulty,
51 pub _difficultyRank: i32,
52 pub _beatmapFilename: String,
53 pub _noteJumpMovementSpeed: f64,
54 pub _noteJumpStartBeatOffset: f64,
55 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
56 pub _customData: HashMap<String, serde_json::Value>,
57}
58
59#[derive(Debug, PartialEq)]
60pub enum BeatmapFile {
61 Old(OldBeatmapFile),
62 New(NewBeatmapFile)
63}
64
65impl BeatmapFile {
66 pub fn read_from_str(data: &str) -> Result<Self> {
67 let new = serde_json::from_str(data);
68 let old = serde_json::from_str(data);
69 if let Ok(beatmap) = new {
70 Ok(Self::New(beatmap))
71 } else if let Ok(beatmap) = old {
72 Ok(Self::Old(beatmap))
73 } else {
74 Err(Error::BeatmapParsingFailed { err_as_new: new.unwrap_err(), err_as_old: old.unwrap_err() })
75 }
76 }
77
78 pub fn read_from_file(path: &str) -> Result<Self> {
79 Self::read_from_str(&read_string_from_file(path)?)
80 }
81}
82
83#[derive(Serialize, Deserialize, Debug, PartialEq)]
84pub struct NewBeatmapFile {
85 pub version: String,
86 pub bpmEvents: Vec<BpmEvent>,
87 pub rotationEvents: Vec<RotationEvent>,
88 pub colorNotes: Vec<ColorNote>,
89 pub bombNotes: Vec<BombNote>,
90 pub obstacles: Vec<Obstacle>,
91 pub sliders: Vec<Slider>,
92 pub burstSliders: Vec<BurstSlider>,
93 pub waypoints: Vec<serde_json::Value>,
94 pub basicBeatmapEvents: Vec<BasicBeatmapEvent>,
95 pub colorBoostBeatmapEvents: Vec<ColorBoostBeatmapEvent>,
96 pub lightColorEventBoxGroups: Vec<LightColorEventBoxGroup>,
97 pub lightRotationEventBoxGroups: Vec<LightRotationEventBoxGroup>,
98 #[serde(skip_serializing_if = "Vec::is_empty", default)]
99 pub lightTranslationEventBoxGroups: Vec<LightTranslationEventBoxGroup>,
100 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
101 pub basicEventTypesWithKeywords: HashMap<String, serde_json::Value>,
102 pub useNormalEventsAsCompatibleEvents: bool,
103 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
104 pub customData: HashMap<String, serde_json::Value>
105}
106
107#[derive(Serialize, Deserialize, Debug, PartialEq)]
108pub struct BpmEvent {
109 pub b: f64,
110 pub m: f64
111}
112
113fn bool_to_int<S>(value: &bool, serialized: S) -> core::result::Result<S::Ok, S::Error> where S: serde::Serializer {
114 serialized.serialize_i32(*value as i32)
115}
116
117#[derive(Serialize, Deserialize, Debug, PartialEq)]
118pub struct RotationEvent {
119 pub b: f64,
120 #[serde(serialize_with = "bool_to_int")]
121 pub e: bool,
122 pub r: f64
123}
124
125#[derive(Serialize, Deserialize, Debug, PartialEq)]
126pub struct ColorNote {
127 pub b: f64,
128 pub x: i32,
129 pub y: i32,
130 pub c: NoteColor,
131 pub d: Direction,
132 pub a: i32
133}
134
135#[derive(Serialize, Deserialize, Debug, PartialEq)]
136pub struct BombNote {
137 pub b: f64,
138 pub x: i32,
139 pub y: i32
140}
141
142#[derive(Serialize, Deserialize, Debug, PartialEq)]
143pub struct Obstacle {
144 pub b: f64,
145 pub x: i32,
146 pub y: i32,
147 pub d: f64,
148 pub w: f64,
149 pub h: f64
150}
151
152#[derive(Serialize, Deserialize, Debug, PartialEq)]
153pub struct Slider {
154 pub b: f64,
155 pub c: NoteColor,
156 pub x: i32,
157 pub y: i32,
158 pub d: Direction,
159 pub mu: f64,
160 pub tb: f64,
161 pub tx: i32,
162 pub ty: i32,
163 pub tc: Direction,
164 pub tmu: f64,
165 pub m: SliderMidAnchorMode
166}
167
168#[derive(Serialize, Deserialize, Debug, PartialEq)]
169pub struct BurstSlider {
170 pub b: f64,
171 pub c: NoteColor,
172 pub x: i32,
173 pub y: i32,
174 pub d: Direction,
175 pub tb: f64,
176 pub tx: i32,
177 pub ty: i32,
178 pub sc: i32,
179 pub s: f64
180}
181
182#[derive(Serialize, Deserialize, Debug, PartialEq)]
183pub struct BasicBeatmapEvent {
184 pub b: f64,
185 pub et: i32,
186 pub i: i32,
187 #[serde(skip_serializing_if = "Option::is_none", default)]
188 pub f: Option<f64>
189}
190
191#[derive(Serialize, Deserialize, Debug, PartialEq)]
192pub struct ColorBoostBeatmapEvent {
193 pub b: f64,
194 pub o: bool
195}
196
197#[derive(Serialize, Deserialize, Debug, PartialEq)]
198pub struct LightColorEventBoxGroup {
199 pub b: f64,
200 pub g: i32,
201 pub e: Vec<LightColorEventBoxGroupLane>
202}
203
204#[derive(Serialize, Deserialize, Debug, PartialEq)]
205pub struct LightColorEventBoxGroupLane {
206 pub f: FilterObject,
207 pub w: f64,
208 pub d: DistributionKind,
209 pub r: f64,
210 pub t: DistributionKind,
211 #[serde(serialize_with = "bool_to_int")]
212 pub b: bool,
213 #[serde(skip_serializing_if = "Option::is_none", default)]
214 pub i: Option<Easing>,
215 pub e: Vec<LightColorEventData>
216}
217
218#[derive(Serialize, Deserialize, Debug, PartialEq)]
219pub struct LightColorEventData {
220 pub b: f64,
221 pub i: TransitionKind,
222 pub c: LightColor,
223 pub s: f64,
224 pub f: i32
225}
226
227#[derive(Serialize, Deserialize, Debug, PartialEq)]
228pub struct LightRotationEventBoxGroup {
229 pub b: f64,
230 pub g: i32,
231 pub e: Vec<LightRotationEventBoxGroupLane>
232}
233
234#[derive(Serialize, Deserialize, Debug, PartialEq)]
235pub struct LightRotationEventBoxGroupLane {
236 pub f: FilterObject,
237 pub w: f64,
238 pub d: DistributionKind,
239 pub s: f64,
240 pub t: DistributionKind,
241 #[serde(serialize_with = "bool_to_int")]
242 pub b: bool,
243 #[serde(skip_serializing_if = "Option::is_none", default)]
244 pub i: Option<Easing>,
245 pub a: Axis,
246 #[serde(serialize_with = "bool_to_int")]
247 pub r: bool,
248 pub e: Vec<LightRotationEventData>
249}
250
251#[derive(Serialize, Deserialize, Debug, PartialEq)]
252pub struct LightRotationEventData {
253 pub b: f64,
254 pub p: RotationBehaviour,
255 pub l: i32,
256 pub e: Easing,
257 pub r: f64,
258 pub o: RotationDirection
259}
260
261#[derive(Serialize, Deserialize, Debug, PartialEq)]
262pub struct LightTranslationEventBoxGroup {
263 pub b: f64,
264 pub g: i32,
265 pub e: Vec<LightTranslationEventBoxGroupLane>
266}
267
268#[derive(Serialize, Deserialize, Debug, PartialEq)]
269pub struct LightTranslationEventBoxGroupLane {
270 pub f: FilterObject,
271 pub w: f64,
272 pub d: DistributionKind,
273 pub s: f64,
274 pub t: DistributionKind,
275 #[serde(serialize_with = "bool_to_int")]
276 pub b: bool,
277 #[serde(skip_serializing_if = "Option::is_none", default)]
278 pub i: Option<Easing>,
279 pub a: Axis,
280 #[serde(serialize_with = "bool_to_int")]
281 pub r: bool,
282 pub l: Vec<LightTranslationEventData>
283}
284
285#[derive(Serialize, Deserialize, Debug, PartialEq)]
286pub struct LightTranslationEventData {
287 pub b: f64,
288 pub p: RotationBehaviour,
289 pub e: Easing,
290 pub t: f64
291}
292
293#[derive(Serialize, Deserialize, Debug, PartialEq)]
294pub struct FilterObject {
295 pub c: i32,
296 pub f: BoxFilterKind,
297 pub p: i32,
298 pub t: i32,
299 #[serde(serialize_with = "bool_to_int")]
300 pub r: bool,
301 pub n: BoxFilterOrdering,
302 pub s: i32,
303 pub l: f64,
304 pub d: LimitKind
305}
306
307#[derive(Serialize, Deserialize, Debug, PartialEq)]
308pub struct OldBeatmapFile {
309 pub _version: String,
310 pub _notes: Vec<OldNote>,
311 #[serde(skip_serializing_if = "Vec::is_empty", default)]
312 pub _sliders: Vec<OldSlider>,
313 pub _obstacles: Vec<OldObstacle>,
314 pub _events: Vec<OldEvent>,
315 #[serde(skip_serializing_if = "Vec::is_empty", default)]
316 pub _waypoints: Vec<serde_json::Value>,
317 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
318 pub customData: HashMap<String, serde_json::Value>
319}
320
321#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq)]
322#[repr(i8)]
323pub enum OldNoteKind {
324 Red = 0,
325 Blue = 1,
326 Unused = 2,
327 Bomb = 3
328}
329
330#[derive(Serialize, Deserialize, Debug, PartialEq)]
331pub struct OldNote {
332 pub _time: f64,
333 pub _lineIndex: i32,
334 pub _lineLayer: i32,
335 pub _type: OldNoteKind,
336 pub _cutDirection: Direction,
337 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
338 pub _customData: HashMap<String, serde_json::Value>
339}
340
341#[derive(Serialize, Deserialize, Debug, PartialEq)]
342pub struct OldSlider {
343 pub _colorType: NoteColor,
344 pub _headTime: f64,
345 pub _headLineIndex: i32,
346 pub _headLineLayer: i32,
347 pub _headControlPointLengthMultiplier: f64,
348 pub _headCutDirection: Direction,
349 pub _tailTime: f64,
350 pub _tailLineIndex: i32,
351 pub _tailLineLayer: i32,
352 pub _tailControlPointLengthMultiplier: f64,
353 pub _tailCutDirection: Direction,
354 pub _sliderMidAnchorMode: SliderMidAnchorMode,
355 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
356 pub _customData: HashMap<String, serde_json::Value>
357}
358
359#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq)]
360#[repr(i8)]
361pub enum OldObstacleKind {
362 Full = 0,
363 Crouch = 1
364}
365
366#[derive(Serialize, Deserialize, Debug, PartialEq)]
367pub struct OldObstacle {
368 pub _time: f64,
369 pub _lineIndex: i32,
370 pub _type: OldObstacleKind,
371 pub _duration: f64,
372 pub _width: f64,
373 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
374 pub _customData: HashMap<String, serde_json::Value>
375}
376
377#[derive(Serialize, Deserialize, Debug, PartialEq)]
378pub struct OldEvent {
379 pub _time: f64,
380 pub _type: i32,
381 pub _value: i32,
382 #[serde(skip_serializing_if = "Option::is_none", default)]
383 pub _floatValue: Option<f64>,
384 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
385 pub _customData: HashMap<String, serde_json::Value>
386}
387