lib.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. use rosu_pp::osu::{OsuGradualPerformance, OsuScoreState};
  2. use std::path::Path;
  3. use std::ptr;
  4. use libc;
  5. use rosu_pp;
  6. #[repr(C)]
  7. pub struct pp_info {
  8. pub total_stars: f64,
  9. pub aim_stars: f64,
  10. pub speed_stars: f64,
  11. pub pp: f64,
  12. pub num_objects: u32,
  13. pub num_circles: u32,
  14. pub num_spinners: u32,
  15. pub aim_strains: *mut f64,
  16. pub aim_strains_len: usize,
  17. pub aim_strains_capacity: usize,
  18. pub speed_strains: *mut f64,
  19. pub speed_strains_len: usize,
  20. pub speed_strains_capacity: usize,
  21. pub ok: bool,
  22. }
  23. impl Default for pp_info {
  24. fn default() -> Self {
  25. pp_info {
  26. total_stars: 0.0,
  27. aim_stars: 0.0,
  28. speed_stars: 0.0,
  29. pp: 0.0,
  30. num_objects: 0,
  31. num_circles: 0,
  32. num_spinners: 0,
  33. aim_strains: std::ptr::null_mut(),
  34. aim_strains_len: 0,
  35. aim_strains_capacity: 0,
  36. speed_strains: std::ptr::null_mut(),
  37. speed_strains_len: 0,
  38. speed_strains_capacity: 0,
  39. ok: false,
  40. }
  41. }
  42. }
  43. #[no_mangle]
  44. pub extern "C" fn free_pp_info(info: pp_info) {
  45. if !info.aim_strains.is_null() {
  46. unsafe {
  47. Vec::from_raw_parts(info.aim_strains, info.aim_strains_len, info.aim_strains_capacity);
  48. }
  49. }
  50. if !info.speed_strains.is_null() {
  51. unsafe {
  52. Vec::from_raw_parts(info.speed_strains, info.speed_strains_len, info.speed_strains_capacity);
  53. }
  54. }
  55. }
  56. #[no_mangle]
  57. pub extern "C" fn calculate_full_pp(path: *const libc::c_char, mod_flags: u32, ar: f32, cs: f32, od: f32, speed_multiplier: f64) -> pp_info {
  58. let c_path = unsafe { std::ffi::CStr::from_ptr(path) };
  59. let path = Path::new(c_path.to_str().unwrap());
  60. let map = match rosu_pp::Beatmap::from_path(path) {
  61. Ok(val) => val,
  62. Err(_) => return pp_info::default()
  63. };
  64. let osu_map = match rosu_pp::osu::OsuBeatmap::try_from_owned(map) {
  65. Ok(val) => val,
  66. Err(_) => return pp_info::default()
  67. };
  68. let diff = rosu_pp::Difficulty::new()
  69. .mods(mod_flags)
  70. .ar(ar, false)
  71. .cs(cs, false)
  72. .od(od, false)
  73. .clock_rate(speed_multiplier);
  74. let diff_attrs = diff.with_mode().calculate(&osu_map);
  75. let diff_strains = diff.with_mode().strains(&osu_map);
  76. let mut aim_strains = std::mem::ManuallyDrop::new(diff_strains.aim);
  77. let mut speed_strains = std::mem::ManuallyDrop::new(diff_strains.speed);
  78. let mut result = pp_info {
  79. total_stars: diff_attrs.stars,
  80. aim_stars: diff_attrs.aim,
  81. speed_stars: diff_attrs.speed,
  82. pp: 0.0,
  83. num_objects: diff_attrs.n_circles + diff_attrs.n_sliders + diff_attrs.n_spinners,
  84. num_circles: diff_attrs.n_circles,
  85. num_spinners: diff_attrs.n_spinners,
  86. aim_strains: aim_strains.as_mut_ptr(),
  87. aim_strains_len: aim_strains.len(),
  88. aim_strains_capacity: aim_strains.capacity(),
  89. speed_strains: speed_strains.as_mut_ptr(),
  90. speed_strains_len: speed_strains.len(),
  91. speed_strains_capacity: speed_strains.capacity(),
  92. ok: true,
  93. };
  94. result.pp = rosu_pp::Performance::new(diff_attrs)
  95. .mods(mod_flags)
  96. .ar(ar, false)
  97. .cs(cs, false)
  98. .od(od, false)
  99. .clock_rate(speed_multiplier)
  100. .calculate()
  101. .pp();
  102. return result;
  103. }
  104. #[repr(C)]
  105. pub struct pp_output {
  106. pub stars: f64,
  107. pub pp: f64,
  108. pub map: *mut gradual_data,
  109. }
  110. struct gradual_data {
  111. gradual: OsuGradualPerformance,
  112. last_hitobject_plus_1: usize
  113. }
  114. #[no_mangle]
  115. pub extern "C" fn load_map(path: *const libc::c_char, mod_flags: u32, ar: f32, cs: f32, od: f32, speed_multiplier: f64) -> *mut gradual_data {
  116. let c_path = unsafe { std::ffi::CStr::from_ptr(path) };
  117. let path = Path::new(c_path.to_str().unwrap());
  118. let map = match rosu_pp::Beatmap::from_path(path) {
  119. Ok(val) => val,
  120. Err(_) => return ptr::null_mut()
  121. };
  122. let osu_map = match rosu_pp::osu::OsuBeatmap::try_from_owned(map) {
  123. Ok(val) => val,
  124. Err(_) => return ptr::null_mut()
  125. };
  126. let gradual = rosu_pp::Difficulty::new()
  127. .mods(mod_flags)
  128. .ar(ar, false)
  129. .cs(cs, false)
  130. .od(od, false)
  131. .clock_rate(speed_multiplier)
  132. .with_mode()
  133. .gradual_performance(&osu_map);
  134. return Box::into_raw(Box::new(gradual_data {
  135. gradual: gradual,
  136. last_hitobject_plus_1: 0,
  137. }));
  138. }
  139. #[no_mangle]
  140. pub extern "C" fn process_map(gradual_ptr: *mut gradual_data, cur_hitobject: usize, max_combo: u32, num_300: u32, num_100: u32, num_50: u32, num_misses: u32) -> pp_output {
  141. if gradual_ptr.is_null() {
  142. return pp_output {
  143. stars: 0.0,
  144. pp: 0.0,
  145. map: ptr::null_mut()
  146. };
  147. }
  148. let data = unsafe { &mut *gradual_ptr };
  149. let mut state = OsuScoreState::new();
  150. state.max_combo = max_combo;
  151. state.n300 = num_300;
  152. state.n100 = num_100;
  153. state.n50 = num_50;
  154. state.misses = num_misses;
  155. match data.gradual.nth(state, cur_hitobject - data.last_hitobject_plus_1) {
  156. Some(attrs) => {
  157. data.last_hitobject_plus_1 = cur_hitobject + 1;
  158. return pp_output {
  159. stars: attrs.stars(),
  160. pp: attrs.pp(),
  161. map: gradual_ptr
  162. };
  163. },
  164. None => {
  165. unsafe { drop(Box::from_raw(gradual_ptr)); }
  166. return pp_output {
  167. stars: 0.0,
  168. pp: 0.0,
  169. map: ptr::null_mut()
  170. };
  171. }
  172. }
  173. }
  174. #[no_mangle]
  175. pub extern "C" fn free_map(gradual_ptr: *mut gradual_data) {
  176. if !gradual_ptr.is_null() {
  177. unsafe { drop(Box::from_raw(gradual_ptr)); }
  178. }
  179. }