Beatsaber Rust Utilities: A Beatsaber V3 parsing library.
beatsaber beatmap
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at dev 586 lines 16 kB view raw
1//! Events that have no effect on gameplay. 2 3pub mod basic; 4pub mod easing; 5pub mod filter; 6pub mod group; 7 8#[doc(hidden)] 9pub use basic::*; 10#[doc(hidden)] 11pub use easing::*; 12#[doc(hidden)] 13pub use filter::*; 14#[doc(hidden)] 15pub use group::*; 16 17use loose_enum::loose_enum; 18 19loose_enum! { 20 /// The way that the distribution value is used. 21 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash)] 22 #[cfg_attr( 23 feature = "bevy_reflect", 24 derive(bevy_reflect::Reflect), 25 reflect(Debug, Clone, PartialEq) 26 )] 27 pub enum DistributionType: i32 { 28 /// The distribution value represents the difference between *the last and first step*. 29 #[default] 30 Wave = 1, 31 /// The distribution value represents the difference between *each step*. 32 Step = 2, 33 } 34} 35 36impl DistributionType { 37 #[deprecated(note = "Experimental. Does not consider random in filter calculations.")] 38 #[allow(deprecated)] 39 fn compute_beat_offset( 40 &self, 41 light_id: i32, 42 group_size: i32, 43 filter: &Filter, 44 dist_value: f32, 45 last_data_offset: Option<f32>, 46 easing: Option<Easing>, 47 ) -> f32 { 48 let filtered_id = filter.get_relative_index(light_id, group_size); 49 50 let filtered_size = if let Some(limit_behaviour) = filter.limit_behaviour 51 && limit_behaviour.beat_enabled() 52 { 53 filter.count_filtered(group_size) 54 } else { 55 filter.count_filtered_without_limit(group_size) 56 }; 57 58 self.compute_offset( 59 filtered_id, 60 filtered_size, 61 dist_value, 62 last_data_offset, 63 easing, 64 ) 65 } 66 67 #[deprecated(note = "Experimental. Does not consider random in filter calculations.")] 68 #[allow(deprecated)] 69 fn compute_value_offset( 70 &self, 71 light_id: i32, 72 group_size: i32, 73 filter: &Filter, 74 dist_value: f32, 75 last_data_offset: Option<f32>, 76 easing: Option<Easing>, 77 ) -> f32 { 78 let filtered_id = filter.get_relative_index(light_id, group_size); 79 80 let filtered_size = if let Some(limit_behaviour) = filter.limit_behaviour 81 && limit_behaviour.value_enabled() 82 { 83 filter.count_filtered(group_size) 84 } else { 85 filter.count_filtered_without_limit(group_size) 86 }; 87 88 self.compute_offset( 89 filtered_id, 90 filtered_size, 91 dist_value, 92 last_data_offset, 93 easing, 94 ) 95 } 96 97 #[deprecated(note = "Experimental. Does not consider random in filter calculations.")] 98 #[allow(deprecated)] 99 #[inline(always)] 100 fn compute_offset( 101 &self, 102 filtered_id: i32, 103 filtered_size: i32, 104 dist_value: f32, 105 last_data_offset: Option<f32>, 106 easing: Option<Easing>, 107 ) -> f32 { 108 let filtered_id = filtered_id as f32; 109 let filtered_size = filtered_size as f32; 110 111 if dist_value == 0.0 { 112 return 0.0; 113 } 114 115 match self { 116 DistributionType::Wave => { 117 let mut modified_value = dist_value; 118 if let Some(offset) = last_data_offset { 119 modified_value = (modified_value - offset).max(0.0); 120 } 121 122 let mut fraction = filtered_id / filtered_size; 123 if let Some(easing) = easing { 124 fraction = easing.ease(fraction); 125 } 126 127 fraction * modified_value 128 } 129 DistributionType::Step => dist_value * filtered_id, 130 DistributionType::Undefined(_) => 0.0, 131 } 132 } 133 134 /// Tests that both [`self.compute_beat_offset`] and [`self.compute_value_offset`] have the same return value, returning that value. 135 /// 136 /// This only makes sense if the [`LimitBehaviour`] is either `None` or `Both`. 137 #[cfg(test)] 138 #[allow(deprecated)] 139 fn compute_both( 140 &self, 141 light_id: i32, 142 group_size: i32, 143 filter: &Filter, 144 dist_value: f32, 145 last_data_offset: Option<f32>, 146 easing: Option<Easing>, 147 ) -> f32 { 148 assert!( 149 matches!( 150 filter.limit_behaviour, 151 None | Some(LimitBehaviour::None) | Some(LimitBehaviour::Both) 152 ), 153 "This test method only makes sense if LimitBehaviour is `None` or `Both`" 154 ); 155 156 let beat = self.compute_beat_offset( 157 light_id, 158 group_size, 159 filter, 160 dist_value, 161 last_data_offset, 162 easing, 163 ); 164 let value = self.compute_value_offset( 165 light_id, 166 group_size, 167 filter, 168 dist_value, 169 last_data_offset, 170 easing, 171 ); 172 assert_eq!(beat, value); 173 beat 174 } 175} 176 177loose_enum! { 178 /// Controls how the state is changed relative to the previous event. 179 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash)] 180 #[cfg_attr( 181 feature = "bevy_reflect", 182 derive(bevy_reflect::Reflect), 183 reflect(Debug, Clone, PartialEq) 184 )] 185 pub enum TransitionType: i32 { 186 /// The state will blend from the previous event's state, using the events [easing](Easing). 187 #[default] 188 Transition = 0, 189 /// The event's state will be ignored, replaced with the state from the previous event. 190 Extend = 1, 191 } 192} 193 194loose_enum! { 195 /// The axis that a rotation/translation event effects. 196 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash)] 197 #[cfg_attr( 198 feature = "bevy_reflect", 199 derive(bevy_reflect::Reflect), 200 reflect(Debug, Clone, PartialEq) 201 )] 202 pub enum EventAxis: i32 { 203 #[default] 204 X = 0, 205 Y = 1, 206 Z = 2, 207 } 208} 209 210// More readable concrete tests are available in the `color` module. 211#[allow(deprecated)] 212#[cfg(test)] 213mod tests { 214 use super::*; 215 use crate::difficulty::lightshow::filter::FilterType; 216 use crate::loose_bool::LooseBool; 217 218 #[test] 219 fn wave() { 220 for i in 0..12 { 221 assert_eq!( 222 DistributionType::Wave.compute_both(i, 12, &Filter::default(), 12.0, None, None), 223 i as f32 224 ); 225 } 226 } 227 228 #[test] 229 fn step() { 230 for i in 0..12 { 231 assert_eq!( 232 DistributionType::Step.compute_both(i, 12, &Filter::default(), 1.0, None, None), 233 i as f32 234 ); 235 } 236 } 237 238 #[test] 239 fn wave_negative() { 240 for i in 0..12 { 241 assert_eq!( 242 DistributionType::Wave.compute_both(i, 12, &Filter::default(), -12.0, None, None), 243 -i as f32 244 ); 245 } 246 } 247 248 #[test] 249 fn step_negative() { 250 for i in 0..12 { 251 assert_eq!( 252 DistributionType::Step.compute_both(i, 12, &Filter::default(), -1.0, None, None), 253 -i as f32 254 ); 255 } 256 } 257 258 #[test] 259 fn wave_zero() { 260 for i in 0..12 { 261 assert_eq!( 262 DistributionType::Wave.compute_both(i, 12, &Filter::default(), 0.0, None, None), 263 0.0 264 ); 265 } 266 } 267 268 #[test] 269 fn step_zero() { 270 for i in 0..12 { 271 assert_eq!( 272 DistributionType::Step.compute_both(i, 12, &Filter::default(), 0.0, None, None), 273 0.0 274 ); 275 } 276 } 277 278 #[test] 279 fn wave_with_division_filter() { 280 for i in 0..6 { 281 assert_eq!( 282 DistributionType::Wave.compute_both( 283 i + 6, 284 12, 285 &Filter { 286 filter_type: FilterType::Division, 287 parameter1: 2, 288 parameter2: 1, 289 ..Default::default() 290 }, 291 6.0, 292 None, 293 None 294 ), 295 i as f32 296 ); 297 } 298 } 299 300 #[test] 301 fn step_with_division_filter() { 302 for i in 0..6 { 303 assert_eq!( 304 DistributionType::Step.compute_both( 305 i + 6, 306 12, 307 &Filter { 308 filter_type: FilterType::Division, 309 parameter1: 2, 310 parameter2: 1, 311 ..Default::default() 312 }, 313 1.0, 314 None, 315 None 316 ), 317 i as f32 318 ); 319 } 320 } 321 322 #[test] 323 fn wave_with_step_filter() { 324 for i in 0..6 { 325 assert_eq!( 326 DistributionType::Wave.compute_both( 327 i * 2, 328 12, 329 &Filter { 330 filter_type: FilterType::StepAndOffset, 331 parameter1: 0, 332 parameter2: 2, 333 ..Default::default() 334 }, 335 6.0, 336 None, 337 None 338 ), 339 i as f32 340 ); 341 } 342 } 343 344 #[test] 345 fn step_with_step_filter() { 346 for i in 0..6 { 347 assert_eq!( 348 DistributionType::Step.compute_both( 349 i * 2, 350 12, 351 &Filter { 352 filter_type: FilterType::StepAndOffset, 353 parameter1: 0, 354 parameter2: 2, 355 ..Default::default() 356 }, 357 1.0, 358 None, 359 None 360 ), 361 i as f32 362 ); 363 } 364 } 365 366 #[test] 367 fn wave_with_reverse_filter() { 368 for i in 0..12 { 369 assert_eq!( 370 DistributionType::Wave.compute_both( 371 i, 372 12, 373 &Filter { 374 reverse: LooseBool::True, 375 ..Default::default() 376 }, 377 12.0, 378 None, 379 None 380 ), 381 12.0 - i as f32 382 ); 383 } 384 } 385 386 #[test] 387 fn step_with_reverse_filter() { 388 for i in 0..12 { 389 assert_eq!( 390 DistributionType::Step.compute_both( 391 i, 392 12, 393 &Filter { 394 reverse: LooseBool::True, 395 ..Default::default() 396 }, 397 1.0, 398 None, 399 None 400 ), 401 12.0 - i as f32 402 ); 403 } 404 } 405 406 #[test] 407 fn wave_with_chunks_of_size_two() { 408 for i in 0..6 { 409 let filter = Filter { 410 chunks: Some(6), 411 ..Default::default() 412 }; 413 assert_eq!( 414 DistributionType::Wave.compute_both(i * 2, 12, &filter, 6.0, None, None), 415 i as f32 416 ); 417 assert_eq!( 418 DistributionType::Wave.compute_both(i * 2 + 1, 12, &filter, 6.0, None, None), 419 i as f32 420 ); 421 } 422 } 423 424 #[test] 425 fn step_with_chunks_of_size_two() { 426 for i in 0..6 { 427 let filter = Filter { 428 chunks: Some(6), 429 ..Default::default() 430 }; 431 assert_eq!( 432 DistributionType::Step.compute_both(i * 2, 12, &filter, 1.0, None, None), 433 i as f32 434 ); 435 assert_eq!( 436 DistributionType::Step.compute_both(i * 2 + 1, 12, &filter, 1.0, None, None), 437 i as f32 438 ); 439 } 440 } 441 442 #[test] 443 fn wave_with_chunks_of_size_six() { 444 for i in 0..6 { 445 let filter = Filter { 446 chunks: Some(2), 447 ..Default::default() 448 }; 449 assert_eq!( 450 DistributionType::Wave.compute_both(i, 12, &filter, 2.0, None, None), 451 0.0 452 ); 453 assert_eq!( 454 DistributionType::Wave.compute_both(i + 6, 12, &filter, 2.0, None, None), 455 1.0 456 ); 457 } 458 } 459 460 #[test] 461 fn step_with_chunks_of_size_six() { 462 for i in 0..6 { 463 let filter = Filter { 464 chunks: Some(2), 465 ..Default::default() 466 }; 467 assert_eq!( 468 DistributionType::Step.compute_both(i, 12, &filter, 1.0, None, None), 469 0.0 470 ); 471 assert_eq!( 472 DistributionType::Step.compute_both(i + 6, 12, &filter, 1.0, None, None), 473 1.0 474 ); 475 } 476 } 477 478 #[test] 479 fn wave_with_chunks_out_of_bounds() { 480 let filter = Filter { 481 chunks: Some(24), 482 ..Default::default() 483 }; 484 485 for i in 0..12 { 486 assert_eq!( 487 DistributionType::Wave.compute_both(i, 12, &filter, 12.0, None, None), 488 i as f32 489 ); 490 } 491 } 492 493 #[test] 494 fn step_with_chunks_out_of_bounds() { 495 let filter = Filter { 496 chunks: Some(24), 497 ..Default::default() 498 }; 499 500 for i in 0..12 { 501 assert_eq!( 502 DistributionType::Step.compute_both(i, 12, &filter, 1.0, None, None), 503 i as f32 504 ); 505 } 506 } 507 508 #[test] 509 fn wave_with_limit() { 510 let filter = Filter { 511 limit_percent: Some(0.5), 512 ..Default::default() 513 }; 514 515 for i in 0..6 { 516 assert_eq!( 517 DistributionType::Wave.compute_both(i, 12, &filter, 12.0, None, None), 518 i as f32 519 ); 520 } 521 } 522 523 #[test] 524 fn step_with_limit() { 525 let filter = Filter { 526 limit_percent: Some(0.5), 527 ..Default::default() 528 }; 529 530 for i in 0..6 { 531 assert_eq!( 532 DistributionType::Step.compute_both(i, 12, &filter, 1.0, None, None), 533 i as f32 534 ); 535 } 536 } 537 538 #[test] 539 fn wave_with_enabled_limit() { 540 let filter = Filter { 541 limit_behaviour: Some(LimitBehaviour::Both), 542 limit_percent: Some(0.5), 543 ..Default::default() 544 }; 545 546 for i in 0..6 { 547 assert_eq!( 548 DistributionType::Wave.compute_both(i, 12, &filter, 12.0, None, None), 549 (i * 2) as f32 550 ); 551 } 552 } 553 554 #[test] 555 fn step_with_enabled_limit() { 556 let filter = Filter { 557 limit_behaviour: Some(LimitBehaviour::Both), 558 limit_percent: Some(0.5), 559 ..Default::default() 560 }; 561 562 for i in 0..6 { 563 assert_eq!( 564 DistributionType::Step.compute_both(i, 12, &filter, 1.0, None, None), 565 i as f32 566 ); 567 } 568 } 569 570 #[test] 571 fn wave_with_value_less_than_data_offset() { 572 for i in 0..12 { 573 assert_eq!( 574 DistributionType::Wave.compute_both( 575 i, 576 12, 577 &Filter::default(), 578 1.0, 579 Some(2.0), 580 None 581 ), 582 0.0 583 ); 584 } 585 } 586}