From bb6f55e8b9d52b962080b3b01b3be66d81246b7e Mon Sep 17 00:00:00 2001 From: Michael Votaw Date: Tue, 18 Mar 2025 19:26:00 -0500 Subject: [PATCH] Explicitly cache #PEAKNPS instead of deriving it from NPSPerMeasure. --- src/NotesLoaderSSC.cpp | 28 +++++++++++++++++++++++++++- src/NotesWriterSSC.cpp | 3 +++ src/Steps.cpp | 17 +++++------------ src/Steps.h | 3 ++- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 067bc7a45f..31f11ad785 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -478,6 +478,32 @@ void SetNotesPerMeasure(StepsTagInfo& info) info.ssc_format= true; } +void SetPeakNps(StepsTagInfo& info) +{ + if (info.from_cache || info.for_load_edit) + { + std::vector valuesPerPlayer; + split((*info.params)[1], "|", valuesPerPlayer, true); + + if(valuesPerPlayer.size() > NUM_PlayerNumber) + { + LOG->Warn("#PEAKNPS has more sections (%zu) than possible number of players (%d)!", valuesPerPlayer.size(), NUM_PlayerNumber); + } + + std::vector peakNps; + for(std::size_t pn = 0; pn < valuesPerPlayer.size() && pn < NUM_PlayerNumber; pn++) + { + peakNps.push_back(StringToFloat(valuesPerPlayer[pn])); + } + info.steps->SetPeakNps(peakNps); + } + else + { + // just recalc at time. + } + info.ssc_format= true; +} + void SetCredit(StepsTagInfo& info) { info.steps->SetCredit((*info.params)[1]); @@ -721,7 +747,7 @@ struct ssc_parser_helper_t steps_tag_handlers["TECHCOUNTS"] = &SetTechCounts; steps_tag_handlers["NPSPERMEASURE"] = &SetNpsPerMeasure; steps_tag_handlers["NOTESPERMEASURE"] = &SetNotesPerMeasure; - + steps_tag_handlers["PEAKNPS"] = &SetPeakNps; /* If this is called, the chart does not use the same attacks * as the Song's timing. No other changes are required. */ steps_tag_handlers["ATTACKS"]= &SetStepsAttacks; diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index a0a7d1958b..f216834522 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -465,6 +465,9 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa lines.push_back( ssprintf( "#NOTESPERMEASURE:%s;", join("|",notesPerMeasureStrings).c_str() ) ); + const std::vector &peakNps = in.GetAllPeakNps(); + lines.push_back("#PEAKNPS:" + serialize(peakNps, "|", 3) + ";"); + // NOTE(MV): #STEPFILENAME has to be at the end of the cache tags, // because it's used in SSCLoader::LoadFromSimfile to determine when // to switch the state back to GETTING_SONG_INFO, which means any tags diff --git a/src/Steps.cpp b/src/Steps.cpp index d984e71332..60039a297b 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -761,28 +761,21 @@ void Steps::SetCachedNpsPerMeasure(std::vector>& npsPerMeasur { DeAutogen(); m_CachedNpsPerMeasure.assign(npsPerMeasure.begin(), npsPerMeasure.end()); - m_PeakNps.clear(); - - for(std::vector n : npsPerMeasure) - { - std::vector::iterator peakNps = std::max_element(n.begin(), n.end()); - if(peakNps != n.end()) - { - m_PeakNps.push_back(*peakNps); - } - } - m_AreCachedNpsPerMeasureJustLoaded = true; } void Steps::SetCachedNotesPerMeasure(std::vector>& notesPerMeasure) { DeAutogen(); - m_CachedNotesPerMeasure.assign(notesPerMeasure.begin(), notesPerMeasure.end()); m_AreCachedNotesPerMeasureJustLoaded = true; } +void Steps::SetPeakNps(std::vector &peakNps) +{ + m_PeakNps.assign(peakNps.begin(), peakNps.end()); +} + RString Steps::GenerateChartKey() { ChartKey = this->GenerateChartKey(*m_pNoteData, this->GetTimingData()); diff --git a/src/Steps.h b/src/Steps.h index 12799a987f..27461941a2 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -147,6 +147,7 @@ public: void SetCachedTechCounts(const TechCounts ts[NUM_PLAYERS]); void SetCachedNpsPerMeasure(std::vector>& npsPerMeasure); void SetCachedNotesPerMeasure(std::vector>& notesPerMeasure); + void SetPeakNps(std::vector& peakNps); float PredictMeter() const; unsigned GetHash() const; @@ -186,7 +187,7 @@ public: const std::vector &GetNotesPerMeasure(PlayerNumber pn) const; float GetPeakNps(PlayerNumber pn) const; - + const std::vector & GetAllPeakNps() const { return Real()->m_PeakNps; } /** * @brief The TimingData used by the Steps. *