Beatsaber Rust Utilities: A Beatsaber V3 parsing library.
beatsaber
beatmap
1//! Events that control the translation/position of objects.
2
3use crate::difficulty::lightshow::easing::Easing;
4use crate::difficulty::lightshow::filter::Filter;
5use crate::difficulty::lightshow::group::EventData;
6use crate::difficulty::lightshow::{DistributionType, EventAxis, TransitionType};
7use crate::loose_bool::LooseBool;
8use crate::{impl_event_box, impl_event_group, impl_timed};
9use serde::{Deserialize, Serialize};
10
11/// A collection of [`TranslationEventGroup`]s that share the same group ID and beat.
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13#[cfg_attr(
14 feature = "bevy_reflect",
15 derive(bevy_reflect::Reflect),
16 reflect(Debug, Clone, PartialEq)
17)]
18pub struct TranslationEventBox {
19 /// The time the event takes place.
20 #[serde(rename = "b")]
21 pub beat: f32,
22 /// The ID of the collection of objects that this event effects.
23 #[serde(rename = "g")]
24 pub group_id: i32,
25 #[serde(rename = "e")]
26 pub groups: Vec<TranslationEventGroup>,
27}
28
29impl Default for TranslationEventBox {
30 fn default() -> Self {
31 Self {
32 beat: 0.0,
33 group_id: 0,
34 groups: vec![TranslationEventGroup::default()],
35 }
36 }
37}
38
39impl_timed!(TranslationEventBox::beat);
40impl_event_box!(
41 TranslationEventBox,
42 TranslationEventGroup,
43 TranslationEventData
44);
45
46/// A collection of [`TranslationEventData`] that share the same [`EventAxis`], [`Filter`], and distribution.
47#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
48#[cfg_attr(
49 feature = "bevy_reflect",
50 derive(bevy_reflect::Reflect),
51 reflect(Debug, Clone, PartialEq)
52)]
53pub struct TranslationEventGroup {
54 #[serde(rename = "f")]
55 pub filter: Filter,
56 #[serde(rename = "d")]
57 pub beat_dist_type: DistributionType,
58 /// The strength of the beat distribution. Dependent on the [beat distribution type](Self::beat_dist_type).
59 ///
60 /// A value of zero will have no effect.
61 #[serde(rename = "w")]
62 pub beat_dist_value: f32,
63 #[serde(rename = "t")]
64 pub translation_dist_type: DistributionType,
65 /// The strength of the translation distribution. Dependent on the [distribution type](Self::translation_dist_type).
66 ///
67 /// A value of zero will have no effect.
68 #[serde(rename = "s")]
69 pub translation_dist_value: f32,
70 /// Whether the first [`TranslationEventData`] of the group will be effected by translation distribution.
71 #[serde(rename = "b")]
72 pub translation_dist_effect_first: LooseBool,
73 #[serde(rename = "i")]
74 pub translation_dist_easing: Easing,
75 #[serde(rename = "a")]
76 pub axis: EventAxis,
77 /// If true, the translation will be mirrored.
78 #[serde(rename = "r")]
79 pub invert_axis: LooseBool,
80 #[serde(rename = "l")]
81 pub data: Vec<TranslationEventData>,
82}
83
84impl Default for TranslationEventGroup {
85 fn default() -> Self {
86 Self {
87 filter: Default::default(),
88 beat_dist_type: Default::default(),
89 beat_dist_value: 0.0,
90 translation_dist_type: Default::default(),
91 translation_dist_value: 0.0,
92 translation_dist_effect_first: Default::default(),
93 translation_dist_easing: Easing::Linear,
94 axis: Default::default(),
95 invert_axis: Default::default(),
96 data: vec![TranslationEventData::default()],
97 }
98 }
99}
100
101impl_event_group!(
102 TranslationEventGroup::get_translation_offset,
103 TranslationEventData
104);
105
106impl TranslationEventGroup {
107 /// Returns the number of units that the event will be offset for a given light ID.
108 /// # Panics
109 /// Will panic if the light ID is greater than or equal to the group size.
110 #[deprecated(note = "Experimental. Does not consider random in filter calculations.")]
111 #[allow(deprecated)]
112 pub fn get_translation_offset(&self, light_id: i32, group_size: i32) -> f32 {
113 self.translation_dist_type.compute_value_offset(
114 light_id,
115 group_size,
116 &self.filter,
117 self.translation_dist_value,
118 self.data.last().map(|data| data.beat_offset),
119 Some(self.translation_dist_easing),
120 )
121 }
122}
123
124/// The lowest-level group event type, which determines the base position of the event.
125#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
126#[cfg_attr(
127 feature = "bevy_reflect",
128 derive(bevy_reflect::Reflect),
129 reflect(Debug, Clone, PartialEq)
130)]
131pub struct TranslationEventData {
132 /// The number of beats the event will be offset from the [`TranslationEventBox`]'s beat.
133 #[serde(rename = "b")]
134 pub beat_offset: f32,
135 #[serde(rename = "p")]
136 pub transition_type: TransitionType,
137 #[serde(rename = "e")]
138 pub easing: Easing,
139 /// The base number of units the event will offset objects by.
140 #[serde(rename = "t")]
141 pub value: f32,
142}
143
144impl EventData for TranslationEventData {
145 fn get_beat_offset(&self) -> f32 {
146 self.beat_offset
147 }
148}