Add ColumnCues calculations, exposed to themes via Lua function on Steps object

This commit is contained in:
Michael Votaw
2024-08-11 09:43:54 -07:00
committed by teejusb
parent d74ad50707
commit 5db1a56d48
5 changed files with 178 additions and 2 deletions
+4 -2
View File
@@ -52,12 +52,14 @@ source_group("Data Structures\\\\Courses and Trails"
list(APPEND SM_DATA_NOTEDATA_SRC
"NoteData.cpp"
"NoteDataUtil.cpp"
"NoteDataWithScoring.cpp")
"NoteDataWithScoring.cpp"
"ColumnCues.cpp")
list(APPEND SM_DATA_NOTEDATA_HPP
"NoteData.h"
"NoteDataUtil.h"
"NoteDataWithScoring.h")
"NoteDataWithScoring.h"
"ColumnCues.h")
source_group("Data Structures\\\\Note Data"
FILES
+61
View File
@@ -0,0 +1,61 @@
#include "global.h"
#include "ColumnCues.h"
#include "GameState.h"
#include "NoteData.h"
#include "TimingData.h"
void ColumnCue::CalculateColumnCues(const NoteData &in, std::vector<ColumnCue> &out, float minDuration)
{
TimingData *timing = GAMESTATE->GetProcessedTimingData();
NoteData::all_tracks_const_iterator curr_note = in.GetTapNoteRangeAllTracks(0, MAX_NOTE_ROW);
int curr_row = -1;
std::vector<ColumnCue> allColumnCues;
ColumnCue currentCue = ColumnCue();
while (!curr_note.IsAtEnd())
{
if(curr_note.Row() != curr_row)
{
if (currentCue.startTime != -1 )
{
allColumnCues.push_back(currentCue);
}
currentCue = ColumnCue();
currentCue.startTime = timing->GetElapsedTimeFromBeat(NoteRowToBeat(curr_note.Row()));
curr_row = curr_note.Row();
}
if (curr_note->type == TapNoteType_Tap || curr_note->type == TapNoteType_HoldHead)
{
currentCue.columns.push_back(ColumnCueColumn(curr_note.Track() + 1, false));
}
else if(curr_note->type == TapNoteType_Mine)
{
currentCue.columns.push_back(ColumnCueColumn(curr_note.Track() + 1, true));
}
++curr_note;
}
// If there's a remaining columnCue from the last row, add it
if( currentCue.startTime != -1)
{
allColumnCues.push_back(currentCue);
}
float previousCueTime = 0;
std::vector<ColumnCue> columnCues;
for( ColumnCue columnCue : allColumnCues )
{
float duration = columnCue.startTime - previousCueTime;
if( duration > minDuration || previousCueTime == 0)
{
columnCues.push_back(ColumnCue(previousCueTime, duration, columnCue.columns));
}
previousCueTime = columnCue.startTime;
}
out.clear();
out.assign(columnCues.begin(), columnCues.end());
}
+51
View File
@@ -0,0 +1,51 @@
#ifndef COLUMN_CUES_H
#define COLUMN_CUES_H
#include "GameConstantsAndTypes.h"
class NoteData;
/* ColumnCues are used to indicate to the player which column the next note will occur
after a long gap in the stepchart.
This info is made available to the theme via lua functions in Steps.cpp
*/
struct ColumnCueColumn
{
int colNum;
bool isMine;
ColumnCueColumn()
{
colNum = 0;
isMine = false;
}
ColumnCueColumn(int c, bool m)
{
colNum = c;
isMine = m;
}
};
struct ColumnCue
{
float startTime;
float duration;
std::vector<ColumnCueColumn> columns;
ColumnCue()
{
startTime = -1;
duration = -1;
}
ColumnCue(float s, float d, std::vector<ColumnCueColumn> c)
{
startTime = s;
duration = d;
columns.assign(c.begin(), c.end());
}
/** @brief Calculates the set of ColumnCues for the given NoteData. Each "cue" is for any note that has a
* minimum of minDuration seconds between it and the previous note on that same column.
*/
static void CalculateColumnCues(const NoteData &in, std::vector<ColumnCue> &out, float minDuration);
};
#endif
+59
View File
@@ -701,6 +701,20 @@ RString Steps::GenerateChartKey(NoteData &nd, TimingData *td)
return o;
}
std::vector<ColumnCue> Steps::GetColumnCues(float minDuration)
{
// TODO: Should we worry about getting the right steps per player?
// It seems like this is only necessary when dealing with Couples charts
std::vector<ColumnCue> cues;
NoteData noteData;
this->GetNoteData( noteData );
GAMESTATE->SetProcessedTimingData(this->GetTimingData());
ColumnCue::CalculateColumnCues(noteData, cues, minDuration);
GAMESTATE->SetProcessedTimingData(nullptr);
return cues;
}
// lua start
#include "LuaBinding.h"
@@ -799,6 +813,50 @@ public:
return 1;
}
static int GetColumnCues(T *p, lua_State*L)
{
float minDuration = 1.5;
if (lua_isnumber(L, 1))
{
minDuration = lua_tonumber(L, 1);
}
std::vector<ColumnCue> cues = p->GetColumnCues(minDuration);
lua_createtable(L, cues.size(), 0);
for (unsigned i = 0; i < cues.size(); i++)
{
lua_newtable(L);
lua_pushstring(L, "startTime");
lua_pushnumber(L, cues[i].startTime);
lua_settable(L, -3);
lua_pushstring(L, "duration");
lua_pushnumber(L, cues[i].duration);
lua_settable(L, -3);
lua_pushstring(L, "columns");
lua_createtable(L, cues[i].columns.size(), 0);
for (unsigned c = 0; c < cues[i].columns.size(); c++)
{
lua_newtable(L);
lua_pushstring(L, "colNum");
lua_pushinteger(L, cues[i].columns[c].colNum);
lua_settable(L, -3);
lua_pushstring(L, "isMine");
lua_pushboolean(L, cues[i].columns[c].isMine);
lua_settable(L, -3);
lua_rawseti(L, -2, c + 1);
}
lua_settable(L, -3);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
LunaSteps()
{
ADD_METHOD( GetAuthorCredit );
@@ -824,6 +882,7 @@ public:
ADD_METHOD( IsDisplayBpmRandom );
ADD_METHOD( PredictMeter );
ADD_METHOD( GetDisplayBPMType );
ADD_METHOD( GetColumnCues );
}
};
+3
View File
@@ -9,6 +9,7 @@
#include "Difficulty.h"
#include "RageUtil_AutoPtr.h"
#include "TimingData.h"
#include "ColumnCues.h"
#include <vector>
@@ -210,6 +211,8 @@ public:
{
return join(":", this->m_sAttackString);
}
std::vector<ColumnCue> GetColumnCues(float minDuration);
private:
inline const Steps *Real() const { return parent ? parent : this; }