123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- #pragma once
- #include "OsuDatabaseBeatmap.h"
- #include "OsuReplay.h"
- #include "OsuScore.h"
- #include "Timer.h"
- #include "UString.h"
- #include "cbase.h"
- class Sound;
- class ConVar;
- class Osu;
- class OsuSkin;
- class OsuHitObject;
- class OsuDatabaseBeatmap;
- class OsuBackgroundStarCacheLoader;
- class OsuBackgroundStarCalcHandler;
- struct OsuBeatmap {
- friend class OsuBackgroundStarCacheLoader;
- friend class OsuBackgroundStarCalcHandler;
- OsuBeatmap(Osu *osu);
- ~OsuBeatmap();
- void draw(Graphics *g);
- void drawDebug(Graphics *g);
- void drawBackground(Graphics *g);
- void update();
- void update2(); // Used to be OsuBeatmap::update()
- void onKeyDown(KeyboardEvent &e);
- // Potentially Visible Set gate time size, for optimizing draw() and update() when iterating over all hitobjects
- long getPVS();
- // this should make all the necessary internal updates to hitobjects when legacy osu mods or static mods change
- // live (but also on start)
- void onModUpdate(bool rebuildSliderVertexBuffers = true, bool recomputeDrainRate = true);
- // Returns true if we're loading or waiting on other players
- bool isLoading();
- // Returns true if the local player is loading
- bool isActuallyLoading();
- Vector2 pixels2OsuCoords(Vector2 pixelCoords) const; // only used for positional audio atm
- Vector2 osuCoords2Pixels(
- Vector2 coords) const; // hitobjects should use this one (includes lots of special behaviour)
- Vector2 osuCoords2RawPixels(
- Vector2 coords) const; // raw transform from osu!pixels to absolute screen pixels (without any mods whatsoever)
- Vector3 osuCoordsTo3D(Vector2 coords, const OsuHitObject *hitObject) const;
- Vector3 osuCoordsToRaw3D(Vector2 coords) const; // (without any mods whatsoever)
- Vector2 osuCoords2LegacyPixels(
- Vector2 coords) const; // only applies vanilla osu mods and static mods to the coordinates (used for generating
- // the static slider mesh) centered at (0, 0, 0)
- // cursor
- Vector2 getMousePos() const;
- Vector2 getCursorPos() const;
- Vector2 getFirstPersonCursorDelta() const;
- inline Vector2 getContinueCursorPoint() const { return m_vContinueCursorPoint; }
- // playfield
- inline Vector2 getPlayfieldSize() const { return m_vPlayfieldSize; }
- inline Vector2 getPlayfieldCenter() const { return m_vPlayfieldCenter; }
- inline float getPlayfieldRotation() const { return m_fPlayfieldRotation; }
- // hitobjects
- float getHitcircleDiameter() const; // in actual scaled pixels to the current resolution
- inline float getRawHitcircleDiameter() const { return m_fRawHitcircleDiameter; } // in osu!pixels
- inline float getHitcircleXMultiplier() const {
- return m_fXMultiplier;
- } // multiply osu!pixels with this to get screen pixels
- inline float getNumberScale() const { return m_fNumberScale; }
- inline float getHitcircleOverlapScale() const { return m_fHitcircleOverlapScale; }
- inline float getSliderFollowCircleDiameter() const { return m_fSliderFollowCircleDiameter; }
- inline float getRawSliderFollowCircleDiameter() const { return m_fRawSliderFollowCircleDiameter; }
- inline bool isInMafhamRenderChunk() const { return m_bInMafhamRenderChunk; }
- // score
- inline int getNumHitObjects() const { return m_hitobjects.size(); }
- inline float getAimStars() const { return m_fAimStars; }
- inline float getAimSliderFactor() const { return m_fAimSliderFactor; }
- inline float getSpeedStars() const { return m_fSpeedStars; }
- inline float getSpeedNotes() const { return m_fSpeedNotes; }
- // hud
- inline bool isSpinnerActive() const { return m_bIsSpinnerActive; }
- // callbacks called by the Osu class (osu!standard)
- void skipEmptySection();
- void keyPressed1(bool mouse);
- void keyPressed2(bool mouse);
- void keyReleased1(bool mouse);
- void keyReleased2(bool mouse);
- // songbrowser & player logic
- void select(); // loads the music of the currently selected diff and starts playing from the previewTime (e.g.
- // clicking on a beatmap)
- void selectDifficulty2(OsuDatabaseBeatmap *difficulty2);
- void deselect(); // stops + unloads the currently loaded music and deletes all hitobjects
- bool watch(std::vector<OsuReplay::Frame> replay);
- bool play();
- void restart(bool quick = false);
- void pause(bool quitIfWaiting = true);
- void pausePreviewMusic(bool toggle = true);
- bool isPreviewMusicPlaying();
- void stop(bool quit = true);
- void fail();
- void cancelFailing();
- void resetScore();
- // loader
- void setMaxPossibleCombo(int maxPossibleCombo) { m_iMaxPossibleCombo = maxPossibleCombo; }
- void setScoreV2ComboPortionMaximum(unsigned long long scoreV2ComboPortionMaximum) {
- m_iScoreV2ComboPortionMaximum = scoreV2ComboPortionMaximum;
- }
- // music/sound
- void loadMusic(bool stream = true, bool prescan = false);
- void unloadMusic();
- void setVolume(float volume);
- void setSpeed(float speed);
- void seekPercent(double percent);
- void seekPercentPlayable(double percent);
- inline Sound *getMusic() const { return m_music; }
- unsigned long getTime() const;
- unsigned long getStartTimePlayable() const;
- unsigned long getLength() const;
- unsigned long getLengthPlayable() const;
- float getPercentFinished() const;
- float getPercentFinishedPlayable() const;
- // live statistics
- int getMostCommonBPM() const;
- float getSpeedMultiplier() const;
- inline int getNPS() const { return m_iNPS; }
- inline int getND() const { return m_iND; }
- inline int getHitObjectIndexForCurrentTime() const { return m_iCurrentHitObjectIndex; }
- inline int getNumCirclesForCurrentTime() const { return m_iCurrentNumCircles; }
- inline int getNumSlidersForCurrentTime() const { return m_iCurrentNumSliders; }
- inline int getNumSpinnersForCurrentTime() const { return m_iCurrentNumSpinners; }
- inline int getMaxPossibleCombo() const { return m_iMaxPossibleCombo; }
- inline unsigned long long getScoreV2ComboPortionMaximum() const { return m_iScoreV2ComboPortionMaximum; }
- inline double getAimStarsForUpToHitObjectIndex(int upToHitObjectIndex) const {
- return (
- m_aimStarsForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
- ? m_aimStarsForNumHitObjects[clamp<int>(upToHitObjectIndex, 0, m_aimStarsForNumHitObjects.size() - 1)]
- : 0);
- }
- inline double getAimSliderFactorForUpToHitObjectIndex(int upToHitObjectIndex) const {
- return (m_aimSliderFactorForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
- ? m_aimSliderFactorForNumHitObjects[clamp<int>(upToHitObjectIndex, 0,
- m_aimSliderFactorForNumHitObjects.size() - 1)]
- : 0);
- }
- inline double getSpeedStarsForUpToHitObjectIndex(int upToHitObjectIndex) const {
- return (m_speedStarsForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
- ? m_speedStarsForNumHitObjects[clamp<int>(upToHitObjectIndex, 0,
- m_speedStarsForNumHitObjects.size() - 1)]
- : 0);
- }
- inline double getSpeedNotesForUpToHitObjectIndex(int upToHitObjectIndex) const {
- return (m_speedNotesForNumHitObjects.size() > 0 && upToHitObjectIndex > -1
- ? m_speedNotesForNumHitObjects[clamp<int>(upToHitObjectIndex, 0,
- m_speedNotesForNumHitObjects.size() - 1)]
- : 0);
- }
- inline const std::vector<double> &getAimStrains() const { return m_aimStrains; }
- inline const std::vector<double> &getSpeedStrains() const { return m_speedStrains; }
- // set to false when using non-vanilla mods (disables score submission)
- bool vanilla = true;
- // replay recording
- void write_frame();
- std::vector<OsuReplay::Frame> live_replay;
- double last_event_time = 0.0;
- long last_event_ms = 0;
- uint8_t current_keys = 0;
- uint8_t last_keys = 0;
- // replay replaying
- // last_event_ms, current_keys, last_keys also reused
- std::vector<OsuReplay::Frame> spectated_replay;
- Vector2 m_interpolatedMousePos;
- bool m_bIsWatchingReplay = false;
- // used by OsuHitObject children and OsuModSelector
- inline Osu *getOsu() const { return m_osu; }
- OsuSkin *getSkin() const; // maybe use this for beatmap skins, maybe
- inline int getRandomSeed() const { return m_iRandomSeed; }
- inline long getCurMusicPos() const { return m_iCurMusicPos; }
- inline long getCurMusicPosWithOffsets() const { return m_iCurMusicPosWithOffsets; }
- float getRawAR() const;
- float getAR() const;
- float getCS() const;
- float getHP() const;
- float getRawOD() const;
- float getOD() const;
- // health
- inline double getHealth() const { return m_fHealth; }
- inline bool hasFailed() const { return m_bFailed; }
- inline double getHPMultiplierNormal() const { return m_fHpMultiplierNormal; }
- inline double getHPMultiplierComboEnd() const { return m_fHpMultiplierComboEnd; }
- // database (legacy)
- inline OsuDatabaseBeatmap *getSelectedDifficulty2() const { return m_selectedDifficulty2; }
- // generic state
- inline bool isPlaying() const { return m_bIsPlaying; }
- inline bool isPaused() const { return m_bIsPaused; }
- inline bool isRestartScheduled() const { return m_bIsRestartScheduled; }
- inline bool isContinueScheduled() const { return m_bContinueScheduled; }
- inline bool isWaiting() const { return m_bIsWaiting; }
- inline bool isInSkippableSection() const { return m_bIsInSkippableSection; }
- inline bool isInBreak() const { return m_bInBreak; }
- inline bool shouldFlashWarningArrows() const { return m_bShouldFlashWarningArrows; }
- inline float shouldFlashSectionPass() const { return m_fShouldFlashSectionPass; }
- inline float shouldFlashSectionFail() const { return m_fShouldFlashSectionFail; }
- bool isKey1Down();
- bool isKey2Down();
- bool isClickHeld();
- bool isLastKeyDownKey1();
- UString getTitle() const;
- UString getArtist() const;
- inline const std::vector<OsuDatabaseBeatmap::BREAK> &getBreaks() const { return m_breaks; }
- unsigned long getBreakDurationTotal() const;
- OsuDatabaseBeatmap::BREAK getBreakForTimeRange(long startMS, long positionMS, long endMS) const;
- // OsuHitObject and other helper functions
- OsuScore::HIT addHitResult(OsuHitObject *hitObject, OsuScore::HIT hit, long delta, bool isEndOfCombo = false,
- bool ignoreOnHitErrorBar = false, bool hitErrorBarOnly = false, bool ignoreCombo = false,
- bool ignoreScore = false, bool ignoreHealth = false);
- void addSliderBreak();
- void addScorePoints(int points, bool isSpinner = false);
- void addHealth(double percent, bool isFromHitResult);
- void updateTimingPoints(long curPos);
- // ILLEGAL:
- inline const std::vector<OsuHitObject *> &getHitObjectsPointer() const { return m_hitobjects; }
- inline float getBreakBackgroundFadeAnim() const { return m_fBreakBackgroundFade; }
- protected:
- // internal
- bool canDraw();
- bool canUpdate();
- void actualRestart();
- void handlePreviewPlay();
- void unloadObjects();
- void resetHitObjects(long curPos = 0);
- void playMissSound();
- unsigned long getMusicPositionMSInterpolated();
- Osu *m_osu;
- // beatmap state
- bool m_bIsPlaying;
- bool m_bIsPaused;
- bool m_bIsWaiting;
- bool m_bIsRestartScheduled;
- bool m_bIsRestartScheduledQuick;
- bool m_bIsInSkippableSection;
- bool m_bShouldFlashWarningArrows;
- float m_fShouldFlashSectionPass;
- float m_fShouldFlashSectionFail;
- bool m_bContinueScheduled;
- unsigned long m_iContinueMusicPos;
- float m_fWaitTime;
- // database
- OsuDatabaseBeatmap *m_selectedDifficulty2;
- // sound
- Sound *m_music;
- float m_fMusicFrequencyBackup;
- long m_iCurMusicPos;
- long m_iCurMusicPosWithOffsets;
- bool m_bWasSeekFrame;
- double m_fInterpolatedMusicPos;
- double m_fLastAudioTimeAccurateSet;
- double m_fLastRealTimeForInterpolationDelta;
- int m_iResourceLoadUpdateDelayHack;
- bool m_bForceStreamPlayback;
- float m_fAfterMusicIsFinishedVirtualAudioTimeStart;
- bool m_bIsFirstMissSound;
- // health
- bool m_bFailed;
- float m_fFailAnim;
- double m_fHealth;
- float m_fHealth2;
- // drain
- double m_fDrainRate;
- double m_fHpMultiplierNormal;
- double m_fHpMultiplierComboEnd;
- // breaks
- std::vector<OsuDatabaseBeatmap::BREAK> m_breaks;
- float m_fBreakBackgroundFade;
- bool m_bInBreak;
- OsuHitObject *m_currentHitObject;
- long m_iNextHitObjectTime;
- long m_iPreviousHitObjectTime;
- long m_iPreviousSectionPassFailTime;
- // player input
- bool m_bClick1Held;
- bool m_bClick2Held;
- bool m_bClickedContinue;
- bool m_bPrevKeyWasKey1;
- int m_iAllowAnyNextKeyForFullAlternateUntilHitObjectIndex;
- std::vector<long> m_clicks;
- // hitobjects
- std::vector<OsuHitObject *> m_hitobjects;
- std::vector<OsuHitObject *> m_hitobjectsSortedByEndTime;
- std::vector<OsuHitObject *> m_misaimObjects;
- int m_iRandomSeed;
- // statistics
- int m_iNPS;
- int m_iND;
- int m_iCurrentHitObjectIndex;
- int m_iCurrentNumCircles;
- int m_iCurrentNumSliders;
- int m_iCurrentNumSpinners;
- int m_iMaxPossibleCombo;
- unsigned long long m_iScoreV2ComboPortionMaximum;
- std::vector<double> m_aimStarsForNumHitObjects;
- std::vector<double> m_aimSliderFactorForNumHitObjects;
- std::vector<double> m_speedStarsForNumHitObjects;
- std::vector<double> m_speedNotesForNumHitObjects;
- std::vector<double> m_aimStrains;
- std::vector<double> m_speedStrains;
- // custom
- int m_iPreviousFollowPointObjectIndex; // TODO: this shouldn't be in this class
- private:
- ConVar *m_osu_pvs = nullptr;
- ConVar *m_osu_draw_hitobjects_ref = nullptr;
- ConVar *m_osu_followpoints_prevfadetime_ref = nullptr;
- ConVar *m_osu_universal_offset_ref = nullptr;
- ConVar *m_osu_early_note_time_ref = nullptr;
- ConVar *m_osu_fail_time_ref = nullptr;
- ConVar *m_osu_drain_type_ref = nullptr;
- ConVar *m_osu_draw_hud_ref = nullptr;
- ConVar *m_osu_draw_scorebarbg_ref = nullptr;
- ConVar *m_osu_hud_scorebar_hide_during_breaks_ref = nullptr;
- ConVar *m_osu_drain_stable_hpbar_maximum_ref = nullptr;
- ConVar *m_osu_volume_music_ref = nullptr;
- ConVar *m_osu_mod_fposu_ref = nullptr;
- ConVar *m_fposu_draw_scorebarbg_on_top_ref = nullptr;
- ConVar *m_osu_draw_statistics_pp_ref = nullptr;
- ConVar *m_osu_draw_statistics_livestars_ref = nullptr;
- ConVar *m_osu_mod_fullalternate_ref = nullptr;
- ConVar *m_fposu_distance_ref = nullptr;
- ConVar *m_fposu_curved_ref = nullptr;
- ConVar *m_fposu_mod_strafing_ref = nullptr;
- ConVar *m_fposu_mod_strafing_frequency_x_ref = nullptr;
- ConVar *m_fposu_mod_strafing_frequency_y_ref = nullptr;
- ConVar *m_fposu_mod_strafing_frequency_z_ref = nullptr;
- ConVar *m_fposu_mod_strafing_strength_x_ref = nullptr;
- ConVar *m_fposu_mod_strafing_strength_y_ref = nullptr;
- ConVar *m_fposu_mod_strafing_strength_z_ref = nullptr;
- ConVar *m_fposu_mod_3d_depthwobble_ref = nullptr;
- ConVar *m_osu_slider_scorev2_ref = nullptr;
- static inline Vector2 mapNormalizedCoordsOntoUnitCircle(const Vector2 &in) {
- 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));
- }
- static float quadLerp3f(float left, float center, float right, float percent) {
- if(percent >= 0.5f) {
- percent = (percent - 0.5f) / 0.5f;
- percent *= percent;
- return lerp<float>(center, right, percent);
- } else {
- percent = percent / 0.5f;
- percent = 1.0f - (1.0f - percent) * (1.0f - percent);
- return lerp<float>(left, center, percent);
- }
- }
- void onPlayStart();
- void onBeforeStop(bool quit);
- void onPaused(bool first);
- void drawFollowPoints(Graphics *g);
- void drawHitObjects(Graphics *g);
- void updateAutoCursorPos();
- void updatePlayfieldMetrics();
- void updateHitobjectMetrics();
- void updateSliderVertexBuffers();
- void calculateStacks();
- void computeDrainRate();
- void updateStarCache();
- void stopStarCacheLoader();
- bool isLoadingStarCache();
- // beatmap
- bool m_bIsSpinnerActive;
- Vector2 m_vContinueCursorPoint;
- // playfield
- float m_fPlayfieldRotation;
- float m_fScaleFactor;
- Vector2 m_vPlayfieldCenter;
- Vector2 m_vPlayfieldOffset;
- Vector2 m_vPlayfieldSize;
- // hitobject scaling
- float m_fXMultiplier;
- float m_fRawHitcircleDiameter;
- float m_fHitcircleDiameter;
- float m_fNumberScale;
- float m_fHitcircleOverlapScale;
- float m_fSliderFollowCircleDiameter;
- float m_fRawSliderFollowCircleDiameter;
- // auto
- Vector2 m_vAutoCursorPos;
- int m_iAutoCursorDanceIndex;
- // pp calculation buffer (only needs to be recalculated in onModUpdate(), instead of on every hit)
- float m_fAimStars;
- float m_fAimSliderFactor;
- float m_fSpeedStars;
- float m_fSpeedNotes;
- OsuBackgroundStarCacheLoader *m_starCacheLoader;
- float m_fStarCacheTime;
- // dynamic slider vertex buffer and other recalculation checks (for live mod switching)
- float m_fPrevHitCircleDiameter;
- bool m_bWasHorizontalMirrorEnabled;
- bool m_bWasVerticalMirrorEnabled;
- bool m_bWasEZEnabled;
- bool m_bWasMafhamEnabled;
- float m_fPrevPlayfieldRotationFromConVar;
- float m_fPrevPlayfieldStretchX;
- float m_fPrevPlayfieldStretchY;
- float m_fPrevHitCircleDiameterForStarCache;
- float m_fPrevSpeedForStarCache;
- // custom
- bool m_bIsPreLoading;
- int m_iPreLoadingIndex;
- bool m_bWasHREnabled; // dynamic stack recalculation
- RenderTarget *m_mafhamActiveRenderTarget;
- RenderTarget *m_mafhamFinishedRenderTarget;
- bool m_bMafhamRenderScheduled;
- int m_iMafhamHitObjectRenderIndex; // scene buffering for rendering entire beatmaps at once with an acceptable
- // framerate
- int m_iMafhamPrevHitObjectIndex;
- int m_iMafhamActiveRenderHitObjectIndex;
- int m_iMafhamFinishedRenderHitObjectIndex;
- bool m_bInMafhamRenderChunk; // used by OsuSlider to not animate the reverse arrow, and by OsuCircle to not animate
- // note blocking shaking, while being rendered into the scene buffer
- int m_iMandalaIndex;
- };
|