diff --git a/src/Steps.cpp b/src/Steps.cpp index c1777010f2..4423712dfc 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -32,6 +32,9 @@ #include #include #include +#include + +#include "StepParityGenerator.h" /* register DisplayBPM with StringConversion */ #include "EnumHelper.h" @@ -55,6 +58,7 @@ Steps::Steps(Song *song): m_StepsType(StepsType_Invalid), m_pSong(song), m_sDescription(""), m_sChartStyle(""), m_Difficulty(Difficulty_Invalid), m_iMeter(0), m_bAreCachedRadarValuesJustLoaded(false), + m_bAreCachedTechCountsValuesJustLoaded(false), m_bAreCachedMeasureInfoJustLoaded(false), m_sCredit(""), displayBPMType(DISPLAY_BPM_ACTUAL), specifiedBPMMin(0), specifiedBPMMax(0) {} @@ -296,6 +300,14 @@ void Steps::TidyUpData() SetMeter( int(PredictMeter()) ); } +void Steps::CalculateStepStats( float fMusicLengthSeconds ) +{ + this->CalculateRadarValues(fMusicLengthSeconds); + this->CalculateTechCounts(); + this->CalculateMeasureInfo(); +// this->CalculateGrooveStatsHash(); +} + void Steps::CalculateRadarValues( float fMusicLengthSeconds ) { // If we're autogen, don't calculate values. GetRadarValues will take from our parent. @@ -319,8 +331,9 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds ) NoteData tempNoteData; this->GetNoteData( tempNoteData ); - FOREACH_PlayerNumber( pn ) - m_CachedRadarValues[pn].Zero(); + FOREACH_PlayerNumber(pn) + m_CachedRadarValues[pn] + .Zero(); GAMESTATE->SetProcessedTimingData(this->GetTimingData()); if( tempNoteData.IsComposite() ) @@ -329,7 +342,9 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds ) NoteDataUtil::SplitCompositeNoteData( tempNoteData, vParts ); for( size_t pn = 0; pn < std::min(vParts.size(), size_t(NUM_PLAYERS)); ++pn ) + { NoteDataUtil::CalculateRadarValues( vParts[pn], fMusicLengthSeconds, m_CachedRadarValues[pn] ); + } } else if (GAMEMAN->GetStepsTypeInfo(this->m_StepsType).m_StepsTypeCategory == StepsTypeCategory_Couple) { @@ -352,6 +367,40 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds ) NoteDataUtil::CalculateRadarValues( tempNoteData, fMusicLengthSeconds, m_CachedRadarValues[0] ); std::fill_n( m_CachedRadarValues + 1, NUM_PLAYERS-1, m_CachedRadarValues[0] ); } + + GAMESTATE->SetProcessedTimingData(nullptr); +} + +void Steps::CalculateTechCounts() +{ + if (parent != nullptr) + return; + + if( m_bAreCachedTechCountsValuesJustLoaded ) + { + m_bAreCachedTechCountsValuesJustLoaded = false; + return; + } + + NoteData tempNoteData; + this->GetNoteData( tempNoteData ); + + FOREACH_PlayerNumber(pn) + m_CachedTechCounts[pn] + .Zero(); + + // For now, we're only supporting dance-single and dance-double + if(this->m_StepsType != StepsType_dance_single && this->m_StepsType != StepsType_dance_double) + { + return; + } + + GAMESTATE->SetProcessedTimingData(this->GetTimingData()); + StepParity::StepParityGenerator gen; + gen.analyzeNoteData(tempNoteData, this->m_StepsType); + TechCounts::CalculateTechCountsFromRows(gen.rows, m_CachedTechCounts[0]); + std::fill_n( m_CachedTechCounts + 1, NUM_PLAYERS-1, m_CachedTechCounts[0] ); + GAMESTATE->SetProcessedTimingData(nullptr); } @@ -405,8 +454,6 @@ void Steps::CalculateMeasureInfo() GAMESTATE->SetProcessedTimingData(nullptr); } - - void Steps::ChangeFilenamesForCustomSong() { m_sFilename= custom_songify_path(m_sFilename); @@ -556,6 +603,7 @@ void Steps::DeAutogen( bool bCopyNoteData ) m_Difficulty = Real()->m_Difficulty; m_iMeter = Real()->m_iMeter; std::copy( Real()->m_CachedRadarValues, Real()->m_CachedRadarValues + NUM_PLAYERS, m_CachedRadarValues ); + std::copy( Real()->m_CachedTechCounts, Real()->m_CachedTechCounts + NUM_PLAYERS, m_CachedTechCounts ); std::copy( Real()->m_CachedMeasureInfo, Real()->m_CachedMeasureInfo + NUM_PLAYERS, m_CachedMeasureInfo ); m_sCredit = Real()->m_sCredit; parent = nullptr; @@ -588,7 +636,7 @@ void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds this->SetDescription( pSource->GetDescription() ); this->SetDifficulty( pSource->GetDifficulty() ); this->SetMeter( pSource->GetMeter() ); - this->CalculateRadarValues( fMusicLengthSeconds ); + this->CalculateStepStats(fMusicLengthSeconds); } void Steps::CreateBlank( StepsType ntTo ) @@ -685,6 +733,13 @@ void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] ) m_bAreCachedRadarValuesJustLoaded = true; } +void Steps::SetCachedTechCounts( const TechCounts ts[NUM_PLAYERS] ) +{ + DeAutogen(); + std::copy(ts, ts + NUM_PLAYERS, m_CachedTechCounts); + m_bAreCachedTechCountsValuesJustLoaded = true; +} + void Steps::SetCachedMeasureInfo(const MeasureInfo ms[NUM_PLAYERS]) { DeAutogen(); @@ -815,6 +870,64 @@ public: rv.PushSelf(L); return 1; } + + static int GetTechCounts(T* p, lua_State *L ) + { + PlayerNumber pn = PLAYER_1; + if (!lua_isnil(L, 1)) { + pn = Enum::Check(L, 1); + } + TechCounts &ts = const_cast(p->GetTechCounts(pn)); + ts.PushSelf(L); + return 1; + } + + static int CalculateTechCounts(T* p, lua_State *L ) + { + p->CalculateTechCounts(); + PlayerNumber pn = PLAYER_1; + if (!lua_isnil(L, 1)) { + pn = Enum::Check(L, 1); + } + TechCounts &ts = const_cast(p->GetTechCounts(pn)); + ts.PushSelf(L); + return 1; + } + + static int GetNPSPerMeasure(T *p, lua_State *L) + { + PlayerNumber pn = PLAYER_1; + if (!lua_isnil(L, 1)) { + pn = Enum::Check(L, 1); + } + MeasureInfo &ts = const_cast(p->GetMeasureInfo(pn)); + LuaHelpers::CreateTableFromArray(ts.npsPerMeasure, L); + return 1; + } + + static int GetNotesPerMeasure(T *p, lua_State * L) + { + PlayerNumber pn = PLAYER_1; + if (!lua_isnil(L, 1)) { + pn = Enum::Check(L, 1); + } + MeasureInfo &ts = const_cast(p->GetMeasureInfo(pn)); + LuaHelpers::CreateTableFromArray(ts.notesPerMeasure, L); + + return 1; + } + + static int GetPeakNPS(T *p, lua_State *L) + { + PlayerNumber pn = PLAYER_1; + if (!lua_isnil(L, 1)) { + pn = Enum::Check(L, 1); + } + MeasureInfo &ts = const_cast(p->GetMeasureInfo(pn)); + lua_pushnumber(L, ts.peakNps); + return 1; + } + static int GetTimingData( T* p, lua_State *L ) { p->GetTimingData()->PushSelf(L); @@ -964,7 +1077,9 @@ public: ADD_METHOD( HasSignificantTimingChanges ); ADD_METHOD( HasAttacks ); ADD_METHOD( GetRadarValues ); - ADD_METHOD( GetTimingData ); + ADD_METHOD( GetTechCounts ); + ADD_METHOD(CalculateTechCounts); + ADD_METHOD(GetTimingData); ADD_METHOD( GetChartName ); //ADD_METHOD( GetSMNoteData ); ADD_METHOD( GetStepsType ); diff --git a/src/Steps.h b/src/Steps.h index 282b6ad118..7cbbc27532 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -10,8 +10,8 @@ #include "RageUtil_AutoPtr.h" #include "TimingData.h" #include "ColumnCues.h" +#include "TechCounts.h" #include "MeasureInfo.h" - #include @@ -136,11 +136,15 @@ public: RString GetChartKey(); void SetChartKey(const RString &k) { ChartKey = k; } + /** @brief Produces a chart that's reduced to it's smallest unique representable form. */ + RString MinimizedChartString(); + void ChangeFilenamesForCustomSong(); void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; } void SetMeter( int meter ); void SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] ); + void SetCachedTechCounts(const TechCounts ts[NUM_PLAYERS]); void SetCachedMeasureInfo(const MeasureInfo ms[NUM_PLAYERS]); float PredictMeter() const; @@ -164,7 +168,14 @@ public: bool IsNoteDataEmpty() const; void TidyUpData(); - void CalculateRadarValues( float fMusicLengthSeconds ); + + /** @brief Convenience function to calculate Radar Values, Tech Stats, Measure Stats, and GrooveStats key.*/ + void CalculateStepStats(float fMusicLengthSeconds); + + void CalculateRadarValues (float fMusicLengthSeconds ); + + void CalculateTechCounts(); + const TechCounts &GetTechCounts(PlayerNumber pn) const { return Real()->m_CachedTechCounts[pn]; } void CalculateMeasureInfo(); const MeasureInfo &GetMeasureInfo(PlayerNumber pn) const { return Real()->m_CachedMeasureInfo[pn]; } @@ -262,6 +273,10 @@ private: RadarValues m_CachedRadarValues[NUM_PLAYERS]; bool m_bAreCachedRadarValuesJustLoaded; + /** @brief The tech stats used for each player */ + mutable TechCounts m_CachedTechCounts[NUM_PLAYERS]; + bool m_bAreCachedTechCountsValuesJustLoaded; + mutable MeasureInfo m_CachedMeasureInfo[NUM_PLAYERS]; bool m_bAreCachedMeasureInfoJustLoaded;