OsuBeatmap.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. #pragma once
  2. #include "OsuDatabaseBeatmap.h"
  3. #include "OsuReplay.h"
  4. #include "OsuScore.h"
  5. #include "Timer.h"
  6. #include "UString.h"
  7. #include "cbase.h"
  8. class Sound;
  9. class ConVar;
  10. class Osu;
  11. class OsuSkin;
  12. class OsuHitObject;
  13. class OsuDatabaseBeatmap;
  14. class OsuBackgroundStarCacheLoader;
  15. class OsuBackgroundStarCalcHandler;
  16. struct OsuBeatmap {
  17. friend class OsuBackgroundStarCacheLoader;
  18. friend class OsuBackgroundStarCalcHandler;
  19. OsuBeatmap(Osu *osu);
  20. ~OsuBeatmap();
  21. void draw(Graphics *g);
  22. void drawDebug(Graphics *g);
  23. void drawBackground(Graphics *g);
  24. void update();
  25. void update2(); // Used to be OsuBeatmap::update()
  26. void onKeyDown(KeyboardEvent &e);
  27. // Potentially Visible Set gate time size, for optimizing draw() and update() when iterating over all hitobjects
  28. long getPVS();
  29. // this should make all the necessary internal updates to hitobjects when legacy osu mods or static mods change
  30. // live (but also on start)
  31. void onModUpdate(bool rebuildSliderVertexBuffers = true, bool recomputeDrainRate = true);
  32. // Returns true if we're loading or waiting on other players
  33. bool isLoading();
  34. // Returns true if the local player is loading
  35. bool isActuallyLoading();
  36. Vector2 pixels2OsuCoords(Vector2 pixelCoords) const; // only used for positional audio atm
  37. Vector2 osuCoords2Pixels(
  38. Vector2 coords) const; // hitobjects should use this one (includes lots of special behaviour)
  39. Vector2 osuCoords2RawPixels(
  40. Vector2 coords) const; // raw transform from osu!pixels to absolute screen pixels (without any mods whatsoever)
  41. Vector3 osuCoordsTo3D(Vector2 coords, const OsuHitObject *hitObject) const;
  42. Vector3 osuCoordsToRaw3D(Vector2 coords) const; // (without any mods whatsoever)
  43. Vector2 osuCoords2LegacyPixels(
  44. Vector2 coords) const; // only applies vanilla osu mods and static mods to the coordinates (used for generating
  45. // the static slider mesh) centered at (0, 0, 0)
  46. // cursor
  47. Vector2 getMousePos() const;
  48. Vector2 getCursorPos() const;
  49. Vector2 getFirstPersonCursorDelta() const;
  50. inline Vector2 getContinueCursorPoint() const { return m_vContinueCursorPoint; }
  51. // playfield
  52. inline Vector2 getPlayfieldSize() const { return m_vPlayfieldSize; }
  53. inline Vector2 getPlayfieldCenter() const { return m_vPlayfieldCenter; }
  54. inline float getPlayfieldRotation() const { return m_fPlayfieldRotation; }
  55. // hitobjects
  56. float getHitcircleDiameter() const; // in actual scaled pixels to the current resolution
  57. inline float getRawHitcircleDiameter() const { return m_fRawHitcircleDiameter; } // in osu!pixels
  58. inline float getHitcircleXMultiplier() const {
  59. return m_fXMultiplier;
  60. } // multiply osu!pixels with this to get screen pixels
  61. inline float getNumberScale() const { return m_fNumberScale; }
  62. inline float getHitcircleOverlapScale() const { return m_fHitcircleOverlapScale; }
  63. inline float getSliderFollowCircleDiameter() const { return m_fSliderFollowCircleDiameter; }
  64. inline float getRawSliderFollowCircleDiameter() const { return m_fRawSliderFollowCircleDiameter; }
  65. inline bool isInMafhamRenderChunk() const { return m_bInMafhamRenderChunk; }
  66. // score
  67. inline int getNumHitObjects() const { return m_hitobjects.size(); }
  68. inline float getAimStars() const { return m_fAimStars; }
  69. inline float getAimSliderFactor() const { return m_fAimSliderFactor; }
  70. inline float getSpeedStars() const { return m_fSpeedStars; }
  71. inline float getSpeedNotes() const { return m_fSpeedNotes; }
  72. // hud
  73. inline bool isSpinnerActive() const { return m_bIsSpinnerActive; }
  74. // callbacks called by the Osu class (osu!standard)
  75. void skipEmptySection();
  76. void keyPressed1(bool mouse);
  77. void keyPressed2(bool mouse);
  78. void keyReleased1(bool mouse);
  79. void keyReleased2(bool mouse);
  80. // songbrowser & player logic
  81. void select(); // loads the music of the currently selected diff and starts playing from the previewTime (e.g.
  82. // clicking on a beatmap)
  83. void selectDifficulty2(OsuDatabaseBeatmap *difficulty2);
  84. void deselect(); // stops + unloads the currently loaded music and deletes all hitobjects
  85. bool watch(std::vector<OsuReplay::Frame> replay);
  86. bool play();
  87. void restart(bool quick = false);
  88. void pause(bool quitIfWaiting = true);
  89. void pausePreviewMusic(bool toggle = true);
  90. bool isPreviewMusicPlaying();
  91. void stop(bool quit = true);
  92. void fail();
  93. void cancelFailing();
  94. void resetScore();
  95. // loader
  96. void setMaxPossibleCombo(int maxPossibleCombo) { m_iMaxPossibleCombo = maxPossibleCombo; }
  97. void setScoreV2ComboPortionMaximum(unsigned long long scoreV2ComboPortionMaximum) {
  98. m_iScoreV2ComboPortionMaximum = scoreV2ComboPortionMaximum;
  99. }
  100. // music/sound
  101. void loadMusic(bool stream = true, bool prescan = false);
  102. void unloadMusic();
  103. void setVolume(float volume);
  104. void setSpeed(float speed);
  105. void seekPercent(double percent);
  106. void seekPercentPlayable(double percent);
  107. inline Sound *getMusic() const { return m_music; }
  108. unsigned long getTime() const;
  109. unsigned long getStartTimePlayable() const;
  110. unsigned long getLength() const;
  111. unsigned long getLengthPlayable() const;
  112. float getPercentFinished() const;
  113. float getPercentFinishedPlayable() const;
  114. // live statistics
  115. int getMostCommonBPM() const;
  116. float getSpeedMultiplier() const;
  117. inline int getNPS() const { return m_iNPS; }
  118. inline int getND() const { return m_iND; }
  119. inline int getHitObjectIndexForCurrentTime() const { return m_iCurrentHitObjectIndex; }
  120. inline int getNumCirclesForCurrentTime() const { return m_iCurrentNumCircles; }
  121. inline int getNumSlidersForCurrentTime() const { return m_iCurrentNumSliders; }
  122. inline int getNumSpinnersForCurrentTime() const { return m_iCurrentNumSpinners; }
  123. inline int getMaxPossibleCombo() const { return m_iMaxPossibleCombo; }
  124. inline unsigned long long getScoreV2ComboPortionMaximum() const { return m_iScoreV2ComboPortionMaximum; }
  125. inline double getAimStarsForUpToHitObjectIndex(int upToHitObjectIndex) const {
  126. return (
  127. m_aimStarsForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
  128. ? m_aimStarsForNumHitObjects[clamp<int>(upToHitObjectIndex, 0, m_aimStarsForNumHitObjects.size() - 1)]
  129. : 0);
  130. }
  131. inline double getAimSliderFactorForUpToHitObjectIndex(int upToHitObjectIndex) const {
  132. return (m_aimSliderFactorForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
  133. ? m_aimSliderFactorForNumHitObjects[clamp<int>(upToHitObjectIndex, 0,
  134. m_aimSliderFactorForNumHitObjects.size() - 1)]
  135. : 0);
  136. }
  137. inline double getSpeedStarsForUpToHitObjectIndex(int upToHitObjectIndex) const {
  138. return (m_speedStarsForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
  139. ? m_speedStarsForNumHitObjects[clamp<int>(upToHitObjectIndex, 0,
  140. m_speedStarsForNumHitObjects.size() - 1)]
  141. : 0);
  142. }
  143. inline double getSpeedNotesForUpToHitObjectIndex(int upToHitObjectIndex) const {
  144. return (m_speedNotesForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
  145. ? m_speedNotesForNumHitObjects[clamp<int>(upToHitObjectIndex, 0,
  146. m_speedNotesForNumHitObjects.size() - 1)]
  147. : 0);
  148. }
  149. inline const std::vector<double> &getAimStrains() const { return m_aimStrains; }
  150. inline const std::vector<double> &getSpeedStrains() const { return m_speedStrains; }
  151. // set to false when using non-vanilla mods (disables score submission)
  152. bool vanilla = true;
  153. // replay recording
  154. void write_frame();
  155. std::vector<OsuReplay::Frame> live_replay;
  156. double last_event_time = 0.0;
  157. long last_event_ms = 0;
  158. uint8_t current_keys = 0;
  159. uint8_t last_keys = 0;
  160. // replay replaying
  161. // last_event_ms, current_keys, last_keys also reused
  162. std::vector<OsuReplay::Frame> spectated_replay;
  163. Vector2 m_interpolatedMousePos;
  164. bool m_bIsWatchingReplay = false;
  165. // used by OsuHitObject children and OsuModSelector
  166. inline Osu *getOsu() const { return m_osu; }
  167. OsuSkin *getSkin() const; // maybe use this for beatmap skins, maybe
  168. inline int getRandomSeed() const { return m_iRandomSeed; }
  169. inline long getCurMusicPos() const { return m_iCurMusicPos; }
  170. inline long getCurMusicPosWithOffsets() const { return m_iCurMusicPosWithOffsets; }
  171. float getRawAR() const;
  172. float getAR() const;
  173. float getCS() const;
  174. float getHP() const;
  175. float getRawOD() const;
  176. float getOD() const;
  177. // health
  178. inline double getHealth() const { return m_fHealth; }
  179. inline bool hasFailed() const { return m_bFailed; }
  180. inline double getHPMultiplierNormal() const { return m_fHpMultiplierNormal; }
  181. inline double getHPMultiplierComboEnd() const { return m_fHpMultiplierComboEnd; }
  182. // database (legacy)
  183. inline OsuDatabaseBeatmap *getSelectedDifficulty2() const { return m_selectedDifficulty2; }
  184. // generic state
  185. inline bool isPlaying() const { return m_bIsPlaying; }
  186. inline bool isPaused() const { return m_bIsPaused; }
  187. inline bool isRestartScheduled() const { return m_bIsRestartScheduled; }
  188. inline bool isContinueScheduled() const { return m_bContinueScheduled; }
  189. inline bool isWaiting() const { return m_bIsWaiting; }
  190. inline bool isInSkippableSection() const { return m_bIsInSkippableSection; }
  191. inline bool isInBreak() const { return m_bInBreak; }
  192. inline bool shouldFlashWarningArrows() const { return m_bShouldFlashWarningArrows; }
  193. inline float shouldFlashSectionPass() const { return m_fShouldFlashSectionPass; }
  194. inline float shouldFlashSectionFail() const { return m_fShouldFlashSectionFail; }
  195. bool isKey1Down();
  196. bool isKey2Down();
  197. bool isClickHeld();
  198. bool isLastKeyDownKey1();
  199. UString getTitle() const;
  200. UString getArtist() const;
  201. inline const std::vector<OsuDatabaseBeatmap::BREAK> &getBreaks() const { return m_breaks; }
  202. unsigned long getBreakDurationTotal() const;
  203. OsuDatabaseBeatmap::BREAK getBreakForTimeRange(long startMS, long positionMS, long endMS) const;
  204. // OsuHitObject and other helper functions
  205. OsuScore::HIT addHitResult(OsuHitObject *hitObject, OsuScore::HIT hit, long delta, bool isEndOfCombo = false,
  206. bool ignoreOnHitErrorBar = false, bool hitErrorBarOnly = false, bool ignoreCombo = false,
  207. bool ignoreScore = false, bool ignoreHealth = false);
  208. void addSliderBreak();
  209. void addScorePoints(int points, bool isSpinner = false);
  210. void addHealth(double percent, bool isFromHitResult);
  211. void updateTimingPoints(long curPos);
  212. // ILLEGAL:
  213. inline const std::vector<OsuHitObject *> &getHitObjectsPointer() const { return m_hitobjects; }
  214. inline float getBreakBackgroundFadeAnim() const { return m_fBreakBackgroundFade; }
  215. protected:
  216. // internal
  217. bool canDraw();
  218. bool canUpdate();
  219. void actualRestart();
  220. void handlePreviewPlay();
  221. void unloadObjects();
  222. void resetHitObjects(long curPos = 0);
  223. void playMissSound();
  224. unsigned long getMusicPositionMSInterpolated();
  225. Osu *m_osu;
  226. // beatmap state
  227. bool m_bIsPlaying;
  228. bool m_bIsPaused;
  229. bool m_bIsWaiting;
  230. bool m_bIsRestartScheduled;
  231. bool m_bIsRestartScheduledQuick;
  232. bool m_bIsInSkippableSection;
  233. bool m_bShouldFlashWarningArrows;
  234. float m_fShouldFlashSectionPass;
  235. float m_fShouldFlashSectionFail;
  236. bool m_bContinueScheduled;
  237. unsigned long m_iContinueMusicPos;
  238. float m_fWaitTime;
  239. // database
  240. OsuDatabaseBeatmap *m_selectedDifficulty2;
  241. // sound
  242. Sound *m_music;
  243. float m_fMusicFrequencyBackup;
  244. long m_iCurMusicPos;
  245. long m_iCurMusicPosWithOffsets;
  246. bool m_bWasSeekFrame;
  247. double m_fInterpolatedMusicPos;
  248. double m_fLastAudioTimeAccurateSet;
  249. double m_fLastRealTimeForInterpolationDelta;
  250. int m_iResourceLoadUpdateDelayHack;
  251. bool m_bForceStreamPlayback;
  252. float m_fAfterMusicIsFinishedVirtualAudioTimeStart;
  253. bool m_bIsFirstMissSound;
  254. // health
  255. bool m_bFailed;
  256. float m_fFailAnim;
  257. double m_fHealth;
  258. float m_fHealth2;
  259. // drain
  260. double m_fDrainRate;
  261. double m_fHpMultiplierNormal;
  262. double m_fHpMultiplierComboEnd;
  263. // breaks
  264. std::vector<OsuDatabaseBeatmap::BREAK> m_breaks;
  265. float m_fBreakBackgroundFade;
  266. bool m_bInBreak;
  267. OsuHitObject *m_currentHitObject;
  268. long m_iNextHitObjectTime;
  269. long m_iPreviousHitObjectTime;
  270. long m_iPreviousSectionPassFailTime;
  271. // player input
  272. bool m_bClick1Held;
  273. bool m_bClick2Held;
  274. bool m_bClickedContinue;
  275. bool m_bPrevKeyWasKey1;
  276. int m_iAllowAnyNextKeyForFullAlternateUntilHitObjectIndex;
  277. std::vector<long> m_clicks;
  278. // hitobjects
  279. std::vector<OsuHitObject *> m_hitobjects;
  280. std::vector<OsuHitObject *> m_hitobjectsSortedByEndTime;
  281. std::vector<OsuHitObject *> m_misaimObjects;
  282. int m_iRandomSeed;
  283. // statistics
  284. int m_iNPS;
  285. int m_iND;
  286. int m_iCurrentHitObjectIndex;
  287. int m_iCurrentNumCircles;
  288. int m_iCurrentNumSliders;
  289. int m_iCurrentNumSpinners;
  290. int m_iMaxPossibleCombo;
  291. unsigned long long m_iScoreV2ComboPortionMaximum;
  292. std::vector<double> m_aimStarsForNumHitObjects;
  293. std::vector<double> m_aimSliderFactorForNumHitObjects;
  294. std::vector<double> m_speedStarsForNumHitObjects;
  295. std::vector<double> m_speedNotesForNumHitObjects;
  296. std::vector<double> m_aimStrains;
  297. std::vector<double> m_speedStrains;
  298. // custom
  299. int m_iPreviousFollowPointObjectIndex; // TODO: this shouldn't be in this class
  300. private:
  301. ConVar *m_osu_pvs = nullptr;
  302. ConVar *m_osu_draw_hitobjects_ref = nullptr;
  303. ConVar *m_osu_followpoints_prevfadetime_ref = nullptr;
  304. ConVar *m_osu_universal_offset_ref = nullptr;
  305. ConVar *m_osu_early_note_time_ref = nullptr;
  306. ConVar *m_osu_fail_time_ref = nullptr;
  307. ConVar *m_osu_drain_type_ref = nullptr;
  308. ConVar *m_osu_draw_hud_ref = nullptr;
  309. ConVar *m_osu_draw_scorebarbg_ref = nullptr;
  310. ConVar *m_osu_hud_scorebar_hide_during_breaks_ref = nullptr;
  311. ConVar *m_osu_drain_stable_hpbar_maximum_ref = nullptr;
  312. ConVar *m_osu_volume_music_ref = nullptr;
  313. ConVar *m_osu_mod_fposu_ref = nullptr;
  314. ConVar *m_fposu_draw_scorebarbg_on_top_ref = nullptr;
  315. ConVar *m_osu_draw_statistics_pp_ref = nullptr;
  316. ConVar *m_osu_draw_statistics_livestars_ref = nullptr;
  317. ConVar *m_osu_mod_fullalternate_ref = nullptr;
  318. ConVar *m_fposu_distance_ref = nullptr;
  319. ConVar *m_fposu_curved_ref = nullptr;
  320. ConVar *m_fposu_mod_strafing_ref = nullptr;
  321. ConVar *m_fposu_mod_strafing_frequency_x_ref = nullptr;
  322. ConVar *m_fposu_mod_strafing_frequency_y_ref = nullptr;
  323. ConVar *m_fposu_mod_strafing_frequency_z_ref = nullptr;
  324. ConVar *m_fposu_mod_strafing_strength_x_ref = nullptr;
  325. ConVar *m_fposu_mod_strafing_strength_y_ref = nullptr;
  326. ConVar *m_fposu_mod_strafing_strength_z_ref = nullptr;
  327. ConVar *m_fposu_mod_3d_depthwobble_ref = nullptr;
  328. ConVar *m_osu_slider_scorev2_ref = nullptr;
  329. static inline Vector2 mapNormalizedCoordsOntoUnitCircle(const Vector2 &in) {
  330. return Vector2(in.x * std::sqrt(1.0f - in.y * in.y / 2.0f), in.y * std::sqrt(1.0f - in.x * in.x / 2.0f));
  331. }
  332. static float quadLerp3f(float left, float center, float right, float percent) {
  333. if(percent >= 0.5f) {
  334. percent = (percent - 0.5f) / 0.5f;
  335. percent *= percent;
  336. return lerp<float>(center, right, percent);
  337. } else {
  338. percent = percent / 0.5f;
  339. percent = 1.0f - (1.0f - percent) * (1.0f - percent);
  340. return lerp<float>(left, center, percent);
  341. }
  342. }
  343. void onPlayStart();
  344. void onBeforeStop(bool quit);
  345. void onPaused(bool first);
  346. void drawFollowPoints(Graphics *g);
  347. void drawHitObjects(Graphics *g);
  348. void updateAutoCursorPos();
  349. void updatePlayfieldMetrics();
  350. void updateHitobjectMetrics();
  351. void updateSliderVertexBuffers();
  352. void calculateStacks();
  353. void computeDrainRate();
  354. void updateStarCache();
  355. void stopStarCacheLoader();
  356. bool isLoadingStarCache();
  357. // beatmap
  358. bool m_bIsSpinnerActive;
  359. Vector2 m_vContinueCursorPoint;
  360. // playfield
  361. float m_fPlayfieldRotation;
  362. float m_fScaleFactor;
  363. Vector2 m_vPlayfieldCenter;
  364. Vector2 m_vPlayfieldOffset;
  365. Vector2 m_vPlayfieldSize;
  366. // hitobject scaling
  367. float m_fXMultiplier;
  368. float m_fRawHitcircleDiameter;
  369. float m_fHitcircleDiameter;
  370. float m_fNumberScale;
  371. float m_fHitcircleOverlapScale;
  372. float m_fSliderFollowCircleDiameter;
  373. float m_fRawSliderFollowCircleDiameter;
  374. // auto
  375. Vector2 m_vAutoCursorPos;
  376. int m_iAutoCursorDanceIndex;
  377. // pp calculation buffer (only needs to be recalculated in onModUpdate(), instead of on every hit)
  378. float m_fAimStars;
  379. float m_fAimSliderFactor;
  380. float m_fSpeedStars;
  381. float m_fSpeedNotes;
  382. OsuBackgroundStarCacheLoader *m_starCacheLoader;
  383. float m_fStarCacheTime;
  384. // dynamic slider vertex buffer and other recalculation checks (for live mod switching)
  385. float m_fPrevHitCircleDiameter;
  386. bool m_bWasHorizontalMirrorEnabled;
  387. bool m_bWasVerticalMirrorEnabled;
  388. bool m_bWasEZEnabled;
  389. bool m_bWasMafhamEnabled;
  390. float m_fPrevPlayfieldRotationFromConVar;
  391. float m_fPrevPlayfieldStretchX;
  392. float m_fPrevPlayfieldStretchY;
  393. float m_fPrevHitCircleDiameterForStarCache;
  394. float m_fPrevSpeedForStarCache;
  395. // custom
  396. bool m_bIsPreLoading;
  397. int m_iPreLoadingIndex;
  398. bool m_bWasHREnabled; // dynamic stack recalculation
  399. RenderTarget *m_mafhamActiveRenderTarget;
  400. RenderTarget *m_mafhamFinishedRenderTarget;
  401. bool m_bMafhamRenderScheduled;
  402. int m_iMafhamHitObjectRenderIndex; // scene buffering for rendering entire beatmaps at once with an acceptable
  403. // framerate
  404. int m_iMafhamPrevHitObjectIndex;
  405. int m_iMafhamActiveRenderHitObjectIndex;
  406. int m_iMafhamFinishedRenderHitObjectIndex;
  407. bool m_bInMafhamRenderChunk; // used by OsuSlider to not animate the reverse arrow, and by OsuCircle to not animate
  408. // note blocking shaking, while being rendered into the scene buffer
  409. int m_iMandalaIndex;
  410. };