Added functions for generating GrooveStats hash for a given chart.
This commit is contained in:
+144
@@ -750,6 +750,7 @@ void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] )
|
|||||||
m_bAreCachedRadarValuesJustLoaded = true;
|
m_bAreCachedRadarValuesJustLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Steps::SetCachedTechCounts( const TechCounts ts[NUM_PLAYERS] )
|
void Steps::SetCachedTechCounts( const TechCounts ts[NUM_PLAYERS] )
|
||||||
{
|
{
|
||||||
DeAutogen();
|
DeAutogen();
|
||||||
@@ -776,6 +777,134 @@ void Steps::SetPeakNps(std::vector<float> &peakNps)
|
|||||||
m_PeakNps.assign(peakNps.begin(), peakNps.end());
|
m_PeakNps.assign(peakNps.begin(), peakNps.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RString Steps::GetGrooveStatsHash() const
|
||||||
|
{
|
||||||
|
return GrooveStatsHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steps::CalculateGrooveStatsHash()
|
||||||
|
{
|
||||||
|
if (m_bIsCachedGrooveStatsHashJustLoaded == true)
|
||||||
|
{
|
||||||
|
m_bIsCachedGrooveStatsHashJustLoaded = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->Decompress();
|
||||||
|
|
||||||
|
RString smNoteData = this->MinimizedChartString();
|
||||||
|
|
||||||
|
TimingData * timingData = this->GetTimingData();
|
||||||
|
std::vector<TimingSegment *> segments = timingData->GetTimingSegments(SEGMENT_BPM);
|
||||||
|
std::vector<RString> bpmStrings;
|
||||||
|
for (TimingSegment *segment : segments)
|
||||||
|
{
|
||||||
|
BPMSegment *bpmSegment = ToBPM(segment);
|
||||||
|
float beat = bpmSegment->GetBeat();
|
||||||
|
float bpm = bpmSegment->GetBPM();
|
||||||
|
std::ostringstream os;
|
||||||
|
os << std::fixed << std::setprecision(3) << beat;
|
||||||
|
os << "=";
|
||||||
|
os << std::fixed << std::setprecision(3) << bpm;
|
||||||
|
bpmStrings.push_back(os.str());
|
||||||
|
}
|
||||||
|
RString bpmString = join(",", bpmStrings);
|
||||||
|
|
||||||
|
smNoteData.append(bpmString);
|
||||||
|
RString gsKey = BinaryToHex(CryptManager::GetSHA1ForString(smNoteData));
|
||||||
|
gsKey = gsKey.substr(0, 16);
|
||||||
|
GrooveStatsHash = gsKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
RString Steps::MinimizedChartString()
|
||||||
|
{
|
||||||
|
// We can potentially minimize the chart to get the most compressed
|
||||||
|
// form of the actual chart data.
|
||||||
|
// NOTE(teejusb): This can be more compressed than the data actually
|
||||||
|
// generated by StepMania. This is okay because the charts would still
|
||||||
|
// be considered equivalent.
|
||||||
|
// E.g. 0000 0000
|
||||||
|
// 0000 -- minimized to -->
|
||||||
|
// 0000
|
||||||
|
// 0000
|
||||||
|
// StepMania will always generate the former since quarter notes are
|
||||||
|
// the smallest quantization.
|
||||||
|
|
||||||
|
RString smNoteData = "";
|
||||||
|
|
||||||
|
this->GetSMNoteData(smNoteData);
|
||||||
|
if( smNoteData == "")
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
RString minimizedNoteData = "";
|
||||||
|
|
||||||
|
std::vector<RString> measures;
|
||||||
|
Regex anyNote("[^0]");
|
||||||
|
|
||||||
|
split(smNoteData, ",", measures, true);
|
||||||
|
for (unsigned m = 0; m < measures.size(); m++)
|
||||||
|
{
|
||||||
|
|
||||||
|
Trim(measures[m]);
|
||||||
|
bool isEmpty = true;
|
||||||
|
bool allZeroes = true;
|
||||||
|
bool minimal = false;
|
||||||
|
std::vector<RString> lines;
|
||||||
|
split(measures[m], "\n", lines, true);
|
||||||
|
while (!minimal && lines.size() % 2 == 0)
|
||||||
|
{
|
||||||
|
// If every other line is all 0s, we can minimize the measure
|
||||||
|
for (unsigned i = 1; i < lines.size(); i += 2)
|
||||||
|
{
|
||||||
|
Trim(lines[i]);
|
||||||
|
if (anyNote.Compare(lines[i]) == true)
|
||||||
|
{
|
||||||
|
allZeroes = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allZeroes)
|
||||||
|
{
|
||||||
|
// Iterate through lines, removing every other item.
|
||||||
|
// Note that we're removing the odd indices, so we
|
||||||
|
// call `++it;` and then erase the following line
|
||||||
|
auto it = lines.begin();
|
||||||
|
while (it != lines.end())
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
if (it != lines.end())
|
||||||
|
{
|
||||||
|
it = lines.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minimal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once the measure has been minimized, make sure all of the lines are
|
||||||
|
// actually trimmed.
|
||||||
|
// (for some reason, the chart returned by GetSMNoteData() have a lot
|
||||||
|
// of extra newlines)
|
||||||
|
for (unsigned l = 0; l < lines.size(); l++)
|
||||||
|
{
|
||||||
|
Trim(lines[l]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, rejoin the lines together to make a measure,
|
||||||
|
// and add it to minimizedNoteData.
|
||||||
|
minimizedNoteData += join("\n", lines);
|
||||||
|
if (m < measures.size() - 1)
|
||||||
|
{
|
||||||
|
minimizedNoteData += "\n,\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minimizedNoteData;
|
||||||
|
}
|
||||||
|
|
||||||
RString Steps::GenerateChartKey()
|
RString Steps::GenerateChartKey()
|
||||||
{
|
{
|
||||||
ChartKey = this->GenerateChartKey(*m_pNoteData, this->GetTimingData());
|
ChartKey = this->GenerateChartKey(*m_pNoteData, this->GetTimingData());
|
||||||
@@ -1019,6 +1148,19 @@ public:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static int GetMinimizedChartString(T * p, lua_State *L)
|
||||||
|
{
|
||||||
|
lua_pushstring(L, p->MinimizedChartString());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetGrooveStatsHash(T *p, lua_State *L)
|
||||||
|
{
|
||||||
|
lua_pushstring(L, p->GetGrooveStatsHash());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int GetChartName(T *p, lua_State *L)
|
static int GetChartName(T *p, lua_State *L)
|
||||||
{
|
{
|
||||||
lua_pushstring(L, p->GetChartName());
|
lua_pushstring(L, p->GetChartName());
|
||||||
@@ -1114,6 +1256,8 @@ public:
|
|||||||
ADD_METHOD( GetDifficulty );
|
ADD_METHOD( GetDifficulty );
|
||||||
ADD_METHOD( GetFilename );
|
ADD_METHOD( GetFilename );
|
||||||
ADD_METHOD( GetHash );
|
ADD_METHOD( GetHash );
|
||||||
|
ADD_METHOD( GetMinimizedChartString );
|
||||||
|
ADD_METHOD( GetGrooveStatsHash );
|
||||||
ADD_METHOD( GetMeter );
|
ADD_METHOD( GetMeter );
|
||||||
ADD_METHOD( HasSignificantTimingChanges );
|
ADD_METHOD( HasSignificantTimingChanges );
|
||||||
ADD_METHOD( HasAttacks );
|
ADD_METHOD( HasAttacks );
|
||||||
|
|||||||
+10
@@ -139,6 +139,13 @@ public:
|
|||||||
/** @brief Produces a chart that's reduced to it's smallest unique representable form. */
|
/** @brief Produces a chart that's reduced to it's smallest unique representable form. */
|
||||||
RString MinimizedChartString();
|
RString MinimizedChartString();
|
||||||
|
|
||||||
|
/** @brief Generates a hash used for GrooveStats integration. */
|
||||||
|
void CalculateGrooveStatsHash();
|
||||||
|
const RString GetGrooveStatsHash() const;
|
||||||
|
|
||||||
|
/** @brief Produces a chart that's reduced to it's smallest unique representable form. */
|
||||||
|
RString MinimizedChartString();
|
||||||
|
|
||||||
void ChangeFilenamesForCustomSong();
|
void ChangeFilenamesForCustomSong();
|
||||||
|
|
||||||
void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; }
|
void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; }
|
||||||
@@ -296,6 +303,9 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RString GrooveStatsHash;
|
||||||
|
bool m_bIsCachedGrooveStatsHashJustLoaded;
|
||||||
|
|
||||||
/** @brief The name of the person who created the Steps. */
|
/** @brief The name of the person who created the Steps. */
|
||||||
RString m_sCredit;
|
RString m_sCredit;
|
||||||
/** @brief The name of the chart. */
|
/** @brief The name of the chart. */
|
||||||
|
|||||||
Reference in New Issue
Block a user