Skip to content

Commit

Permalink
Reconfigured the system to avoid recalculating unnecessary timing val…
Browse files Browse the repository at this point in the history
…ues in a way that makes slightly more sense.

Also it shouldn't crash anymore. In most cases. Probably.
  • Loading branch information
Sam Feeney committed Sep 7, 2016
1 parent 6a22b70 commit ddf6bc6
Showing 9 changed files with 81 additions and 97 deletions.
4 changes: 2 additions & 2 deletions src/ArrowEffects.cpp
Original file line number Diff line number Diff line change
@@ -222,7 +222,7 @@ void ArrowEffects::Update()
float fAccelTime = 0.2f, fTotalTime = 0.5f;
float fBeat = position.m_fSongBeatVisible + fAccelTime;

const bool bEvenBeat = (int(fBeat) % 2) != 0;
const bool bEvenBeat = (static_cast<int>(fBeat) % 2) != 0;

data.m_fBeatFactor = 0;
if (fBeat < 0)
@@ -319,7 +319,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
if( curr_options->m_fTimeSpacing != 0.0f )
{
float fSongSeconds = GAMESTATE->m_Position.m_fMusicSecondsVisible;
float fNoteSeconds = GAMESTATE->WhereUAtBro(pn, fNoteBeat) ;
float fNoteSeconds = pCurSteps->GetTimingData()->WhereUAtBro(fNoteBeat) ;
float fSecondsUntilStep = fNoteSeconds - fSongSeconds;
float fBPM = curr_options->m_fScrollBPM;
float fBPS = fBPM/60.f / GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
52 changes: 0 additions & 52 deletions src/GameState.cpp
Original file line number Diff line number Diff line change
@@ -2599,58 +2599,6 @@ MultiPlayer GetNextEnabledMultiPlayer( MultiPlayer mp )
return MultiPlayer_Invalid;
}


float GameState::WhereUAtBro(PlayerNumber pn, float beat) {
if (beat < 0) return 0;

//bool ValidSequentialAssumption = m_pCurSteps[pn]->GetTimingData()->IsSequentialAssumptionValid();

if (true)
{
return m_pCurSteps[pn]->GetElapsedTimeAtRow(BeatToNoteRow(beat)) - GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * PREFSMAN->m_fGlobalOffsetSeconds;
}
else
{
TimingData *td = m_pCurSteps[pn]->GetTimingData();
return td->GetElapsedTimeFromBeat(beat);
}
}

float GameState::WhereUAtBro(PlayerNumber pn, float beat) const {
if (beat < 0) return 0;

//bool ValidSequentialAssumption = m_pCurSteps[pn]->GetTimingData()->IsSequentialAssumptionValid();

if (true)
{
return m_pCurSteps[pn]->GetElapsedTimeAtRow(BeatToNoteRow(beat)) - GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * PREFSMAN->m_fGlobalOffsetSeconds;
}
else
{
TimingData *td = m_pCurSteps[pn]->GetTimingData();
return td->GetElapsedTimeFromBeat(beat);
}
}

float GameState::WhereUAtBro(PlayerNumber pn, int row) {
if (row < 0) return 0;

//bool ValidSequentialAssumption = m_pCurSteps[pn]->GetTimingData()->IsSequentialAssumptionValid();

if (true)
{
return m_pCurSteps[pn]->GetElapsedTimeAtRow(row) - GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * PREFSMAN->m_fGlobalOffsetSeconds;
}
else
{
TimingData *td = m_pCurSteps[pn]->GetTimingData();
return td->GetElapsedTimeFromBeat(NoteRowToBeat(row));
}
}




// lua start
#include "LuaBinding.h"
#include "Game.h"
4 changes: 0 additions & 4 deletions src/GameState.h
Original file line number Diff line number Diff line change
@@ -403,10 +403,6 @@ class GameState
BroadcastOnChange<RString> m_sEditLocalProfileID;
Profile* GetEditLocalProfile();

float WhereUAtBro(PlayerNumber pn, float beat) const;
float WhereUAtBro(PlayerNumber pn, float beat);
float WhereUAtBro(PlayerNumber pn, int row);

// Workout stuff
float GetGoalPercentComplete( PlayerNumber pn );
bool IsGoalComplete( PlayerNumber pn ) { return GetGoalPercentComplete( pn ) >= 1; }
2 changes: 1 addition & 1 deletion src/NoteDataWithScoring.cpp
Original file line number Diff line number Diff line change
@@ -387,7 +387,7 @@ void NoteDataWithScoring::GetActualRadarValues(const NoteData &in,
int jump_count= out[RadarCategory_Jumps];
int hold_count= out[RadarCategory_Holds];
int tap_count= out[RadarCategory_TapsAndHolds];
float hittable_steps_length= max(0, GAMESTATE->WhereUAtBro(pn, last_hittable_row) - GAMESTATE->WhereUAtBro(pn, first_hittable_row));
float hittable_steps_length= max(0, timing->WhereUAtBro(last_hittable_row) - timing->WhereUAtBro(first_hittable_row));
// The for loop and the assert are used to ensure that all fields of
// RadarValue get set in here.
FOREACH_ENUM(RadarCategory, rc)
26 changes: 14 additions & 12 deletions src/Player.cpp
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ class JudgedRows
{
if( iRow < m_iStart )
return true;
if( iRow >= m_iStart+int(m_vRows.size()) )
if( iRow >= m_iStart + static_cast<int>(m_vRows.size()) )
Resize( iRow+1-m_iStart );
const int iIndex = (iRow - m_iStart + m_iOffset) % m_vRows.size();
const bool ret = m_vRows[iIndex];
@@ -80,7 +80,7 @@ class JudgedRows
{
m_vRows[m_iOffset] = false;
++m_iStart;
if( ++m_iOffset >= int(m_vRows.size()) )
if( ++m_iOffset >= static_cast<int>(m_vRows.size()) )
m_iOffset -= m_vRows.size();
}
return ret;
@@ -94,7 +94,7 @@ class JudgedRows
};


RString ATTACK_DISPLAY_X_NAME( size_t p, size_t both_sides ) { return "AttackDisplayXOffset" + (both_sides ? RString("BothSides") : ssprintf("OneSideP%d",int(p+1)) ); }
RString ATTACK_DISPLAY_X_NAME( size_t p, size_t both_sides ) { return "AttackDisplayXOffset" + (both_sides ? RString("BothSides") : ssprintf("OneSideP%d", static_cast<int>(p+1)) ); }

void TimingWindowSecondsInit( size_t /*TimingWindow*/ i, RString &sNameOut, float &defaultValueOut )
{
@@ -669,6 +669,7 @@ void Player::Load()
// Mina garbage - Mina
m_Timing = GAMESTATE->m_pCurSteps[pn]->GetTimingData();
m_Timing->NegStopAndBPMCheck();
m_Timing->SetElapsedTimesAtAllRows(GAMESTATE->m_pCurSteps[pn]->GetElapsedTimesAtAllRows());

/* Apply transforms. */
NoteDataUtil::TransformNoteData(m_NoteData, *m_Timing, m_pPlayerState->m_PlayerOptions.GetStage(), GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->m_StepsType);
@@ -1788,8 +1789,8 @@ int Player::GetClosestNote( int col, int iNoteRow, int iMaxRowsAhead, int iMaxRo

// Get the current time, previous time, and next time.
float fNoteTime = m_pPlayerState->m_Position.m_fMusicSeconds;
float fNextTime = GAMESTATE->WhereUAtBro(pn, iNextIndex);
float fPrevTime = GAMESTATE->WhereUAtBro(pn, iPrevIndex);
float fNextTime = m_Timing->WhereUAtBro(iNextIndex);
float fPrevTime = m_Timing->WhereUAtBro(iPrevIndex);

/* Figure out which row is closer. */
if( fabsf(fNoteTime-fNextTime) > fabsf(fNoteTime-fPrevTime) )
@@ -1855,8 +1856,8 @@ int Player::GetClosestNonEmptyRow( int iNoteRow, int iMaxRowsAhead, int iMaxRows

// Get the current time, previous time, and next time.
float fNoteTime = m_pPlayerState->m_Position.m_fMusicSeconds;
float fNextTime = GAMESTATE->WhereUAtBro(pn, iNextRow);
float fPrevTime = GAMESTATE->WhereUAtBro(pn, iPrevRow);
float fNextTime = m_Timing->WhereUAtBro(iNextRow);
float fPrevTime = m_Timing->WhereUAtBro(iPrevRow);

/* Figure out which row is closer. */
if( fabsf(fNoteTime-fNextTime) > fabsf(fNoteTime-fPrevTime) )
@@ -2111,8 +2112,9 @@ void Player::Step( int col, int row, const RageTimer &tm, bool bHeld, bool bRele
int iStepSearchRows;
static const float StepSearchDistance = GetMaxStepDistanceSeconds();
vector<int> nerv = GAMESTATE->m_pCurSteps[pn]->GetNonEmptyRowVector();
int skipstart = nerv[10]; // this is not robust need to come up with something better later - Mina

if (iSongRow < 100 || iSongRow > nerv.size() -10 ) {
if (iSongRow < skipstart || iSongRow > nerv.size() -10 ) {
iStepSearchRows = max(BeatToNoteRow(m_Timing->GetBeatFromElapsedTime(m_pPlayerState->m_Position.m_fMusicSeconds + StepSearchDistance)) - iSongRow,
iSongRow - BeatToNoteRow(m_Timing->GetBeatFromElapsedTime(m_pPlayerState->m_Position.m_fMusicSeconds - StepSearchDistance))) + ROWS_PER_BEAT;
}
@@ -2127,12 +2129,12 @@ void Player::Step( int col, int row, const RageTimer &tm, bool bHeld, bool bRele

size_t SearchIndexBehind = nervpos;
size_t SearchIndexAhead = nervpos;
float SearchBeginTime = GAMESTATE->WhereUAtBro(pn, nerv[nervpos]);
float SearchBeginTime = m_Timing->WhereUAtBro(nerv[nervpos]);

while (SearchIndexBehind > 1 && SearchBeginTime - GAMESTATE->WhereUAtBro(pn, nerv[SearchIndexBehind - 1]) < StepSearchDistance)
while (SearchIndexBehind > 1 && SearchBeginTime - m_Timing->WhereUAtBro(nerv[SearchIndexBehind - 1]) < StepSearchDistance)
SearchIndexBehind -= 1;

while (SearchIndexAhead > 1 && SearchIndexAhead + 1 > nerv.size() && GAMESTATE->WhereUAtBro(pn, nerv[SearchIndexAhead + 1]) - SearchBeginTime < StepSearchDistance)
while (SearchIndexAhead > 1 && SearchIndexAhead + 1 > nerv.size() && m_Timing->WhereUAtBro(nerv[SearchIndexAhead + 1]) - SearchBeginTime < StepSearchDistance)
SearchIndexAhead += 1;

int MaxLookBehind = nerv[nervpos] - nerv[SearchIndexBehind];
@@ -2155,7 +2157,7 @@ void Player::Step( int col, int row, const RageTimer &tm, bool bHeld, bool bRele
float fNoteOffset = 0.0f;
// we need this later if we are autosyncing
const float fStepBeat = NoteRowToBeat( iRowOfOverlappingNoteOrRow );
const float fStepSeconds = GAMESTATE->WhereUAtBro(pn, fStepBeat);
const float fStepSeconds = m_Timing->WhereUAtBro(fStepBeat);

if( row == -1 )
{
35 changes: 12 additions & 23 deletions src/Steps.cpp
Original file line number Diff line number Diff line change
@@ -289,7 +289,7 @@ void Steps::TidyUpData()
}

if( GetMeter() < 1) // meter is invalid
SetMeter( int(PredictMeter()) );
SetMeter(static_cast<int>(PredictMeter()) );
}

void Steps::CalculateRadarValues( float fMusicLengthSeconds )
@@ -435,60 +435,49 @@ void Steps::Decompress()

/* Piggy backing off this function to generate stuff that should only be generated once per song caching
This includes a vector for note rows that are not empty, a vector for elapsed time at each note row and
the chart key generated on song load. -Mina */
the chart key generated on song load. Also this totally needs to be redone and split up into the appropriate
places now that I understand the system better. - Mina */

NoteData nd = Steps::GetNoteData();
if (nd.GetLastRow() > size_t(500000)) // Ignore really long stuff for the moment
return;

NonEmptyRowVector = nd.LogNonEmptyRows();
// don't care about anything with under 4 rows of taps
if (NonEmptyRowVector.size() <= 4 || nd.IsEmpty())
// don't care about anything with under 10 rows of taps
if (NonEmptyRowVector.size() <= 10 || nd.IsEmpty())
return;

vector<float> etar;
vector<float> etat;

TimingData *td = Steps::GetTimingData();
for (int i = 0; i < nd.GetLastRow(); i++)
etar.push_back(td->GetElapsedTimeFromBeatNoOffset(NoteRowToBeat(i)));

for (size_t i = 0; i < NonEmptyRowVector.size(); i++) {
etat.push_back(td->GetElapsedTimeFromBeatNoOffset(NoteRowToBeat(NonEmptyRowVector[i])));
}

SetElapsedTimesAtAllRows(etar);
SetElapsedTimesAtTapRows(etat);

ChartKey = GenerateChartKey(nd, etar);
}

RString Steps::GenerateChartKey(NoteData nd, vector<float> etar)
{
RString k = "";
RString o = "";
int m = 10000;
int sr = nd.GetFirstRow();
float fso = etar[sr]*m;
int row;
int m = 1000;
float fso = etar[nd.GetFirstRow()] * m;
int et = 0;
for (size_t r = 0; r < NonEmptyRowVector.size(); r++)

for (size_t r = 0; r < NonEmptyRowVector.size(); r++)
{
row = NonEmptyRowVector[r];
int row = NonEmptyRowVector[r];
for (int t = 0; t < nd.GetNumTracks(); ++t)
{
const TapNote &tn = nd.GetTapNote(t, row);
k.append(to_string(tn.type));
}
k.append(";");
k.append(to_string(et));
et = lround(etar[row] * m - fso);
k.append(" ");
}

ChartKeyRecord = k;

//ChartKeyRecord = k;
o.append("X"); // I was thinking of using "C" to indicate chart.. however.. X is cooler... - Mina
o.append(BinaryToHex(CryptManager::GetSHA1ForString(k)));

@@ -619,7 +608,7 @@ void Steps::SetChartStyle( RString sChartStyle )

bool Steps::MakeValidEditDescription( RString &sPreferredDescription )
{
if( int(sPreferredDescription.size()) > MAX_STEPS_DESCRIPTION_LENGTH )
if( static_cast<int>(sPreferredDescription.size()) > MAX_STEPS_DESCRIPTION_LENGTH )
{
sPreferredDescription = sPreferredDescription.Left( MAX_STEPS_DESCRIPTION_LENGTH );
return true;
2 changes: 1 addition & 1 deletion src/Steps.h
Original file line number Diff line number Diff line change
@@ -171,7 +171,7 @@ class Steps
/* Needs to be generated with timingdata and stored in timingdata - Mina */

vector<float> ElapsedTimesAtAllRows;
size_t GetElapsedTimesAtAllRows() { return ElapsedTimesAtAllRows.size(); };
vector<float> GetElapsedTimesAtAllRows() { return ElapsedTimesAtAllRows; };
void SetElapsedTimesAtAllRows(vector<float> etar) { ElapsedTimesAtAllRows = etar; };

vector<float> ElapsedTimesAtTapRows;
30 changes: 30 additions & 0 deletions src/TimingData.cpp
Original file line number Diff line number Diff line change
@@ -1354,6 +1354,36 @@ void TimingSegmentSetToLuaTable(TimingData* td, TimingSegmentType tst, lua_State
}
}


float TimingData::WhereUAtBro(float beat) {
if (beat < 0) return 0;
size_t row = BeatToNoteRow(beat);

if ( ValidSequentialAssumption && row < ElapsedTimesAtAllRows.size() )
return ElapsedTimesAtAllRows[row] - GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * PREFSMAN->m_fGlobalOffsetSeconds;

return GetElapsedTimeFromBeat(beat);
}

float TimingData::WhereUAtBro(float beat) const {
if (beat < 0) return 0;
size_t row = BeatToNoteRow(beat);

if ( ValidSequentialAssumption && row < ElapsedTimesAtAllRows.size() )
return ElapsedTimesAtAllRows[row] - GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * PREFSMAN->m_fGlobalOffsetSeconds;

return GetElapsedTimeFromBeat(beat);
}

float TimingData::WhereUAtBro(int row) {
if (row < 0) return 0;

if ( ValidSequentialAssumption && static_cast<size_t>(row) < ElapsedTimesAtAllRows.size() )
return ElapsedTimesAtAllRows[row] - GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate * PREFSMAN->m_fGlobalOffsetSeconds;

return GetElapsedTimeFromBeat(NoteRowToBeat(row));
}

/** @brief Allow Lua to have access to the TimingData. */
class LunaTimingData: public Luna<TimingData>
{
23 changes: 21 additions & 2 deletions src/TimingData.h
Original file line number Diff line number Diff line change
@@ -462,12 +462,31 @@ class TimingData
// XXX: this breaks encapsulation. get rid of it ASAP
vector<RString> ToVectorString(TimingSegmentType tst, int dec = 6) const;

// Wow it's almost like this should have been done a decade ago. - Mina.
/* Wow it's almost like this should have been done a decade ago. Essentially what's happening
here is the results of getelapsedtimeat(row) are pre-calculated and stored in a vector that can
be simply subset rather than values being recalculated millions of times per file. This only
applies however to files for which there can be made an assumption of sequential execution
I don't actually know for sure if any of negative bpms/stops/warps do this, or if mod maps have
the power to fundamentally change timing data. If they don't then I suppose all of these checks
aren't needed at all :/. Not my responsibility to investigate, though. - Mina.*/

vector<float> ElapsedTimesAtAllRows;
void SetElapsedTimesAtAllRows(vector<float> etar) { ElapsedTimesAtAllRows = etar; };

float WhereUAtBro(float beat) const;
float WhereUAtBro(float beat);
float WhereUAtBro(int row);

bool ValidSequentialAssumption = true;
void InvalidateSequentialAssmption() { ValidSequentialAssumption = false;};
void InvalidateSequentialAssmption() { ValidSequentialAssumption = false; };
bool IsSequentialAssumptionValid() { return ValidSequentialAssumption; }

void TimingData::NegStopAndBPMCheck() {
if (HasWarps()) {
ValidSequentialAssumption = false;
return;
}

vector<TimingSegment *> &bpms = m_avpTimingSegments[SEGMENT_BPM];
vector<TimingSegment *> &stops = m_avpTimingSegments[SEGMENT_STOP];

0 comments on commit ddf6bc6

Please sign in to comment.