Added revalidation scheme to NoteData's all_tracks_iterator so that it can be made valid again after the NoteData is transformed by something adding or removing steps. This fixes the crash on courses that use transform mods on the second song. ITG2's Getting Started is an example.

This commit is contained in:
Kyzentun
2014-07-23 05:34:23 -06:00
parent 84766a7cff
commit dc55f1391a
3 changed files with 194 additions and 5 deletions
+129 -2
View File
@@ -1176,6 +1176,48 @@ void NoteData::LoadFromNode( const XNode* pNode )
FAIL_M("NoteData::LoadFromNode() not implemented");
}
void NoteData::AddATIToList(all_tracks_iterator* iter) const
{
m_atis.insert(iter);
}
void NoteData::AddATIToList(all_tracks_const_iterator* iter) const
{
m_const_atis.insert(iter);
}
void NoteData::RemoveATIFromList(all_tracks_iterator* iter) const
{
set<all_tracks_iterator*>::iterator pos= m_atis.find(iter);
if(pos != m_atis.end())
{
m_atis.erase(pos);
}
}
void NoteData::RemoveATIFromList(all_tracks_const_iterator* iter) const
{
set<all_tracks_const_iterator*>::iterator pos= m_const_atis.find(iter);
if(pos != m_const_atis.end())
{
m_const_atis.erase(pos);
}
}
void NoteData::RevalidateATIs(vector<int> const& added_or_removed_tracks, bool added)
{
for(set<all_tracks_iterator*>::iterator cur= m_atis.begin();
cur != m_atis.end(); ++cur)
{
(*cur)->Revalidate(this, added_or_removed_tracks, added);
}
for(set<all_tracks_const_iterator*>::iterator cur= m_const_atis.begin();
cur != m_const_atis.end(); ++cur)
{
(*cur)->Revalidate(this, added_or_removed_tracks, added);
}
}
template<typename ND, typename iter, typename TN>
void NoteData::_all_tracks_iterator<ND, iter, TN>::Find( bool bReverse )
{
@@ -1213,14 +1255,18 @@ void NoteData::_all_tracks_iterator<ND, iter, TN>::Find( bool bReverse )
}
template<typename ND, typename iter, typename TN>
NoteData::_all_tracks_iterator<ND, iter, TN>::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive ) :
NoteData::_all_tracks_iterator<ND, iter, TN>::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive ) :
m_pNoteData(&nd), m_iTrack(0), m_bReverse(bReverse)
{
ASSERT( m_pNoteData->GetNumTracks() > 0 );
m_StartRow= iStartRow;
m_EndRow= iEndRow;
for( int iTrack = 0; iTrack < m_pNoteData->GetNumTracks(); ++iTrack )
{
iter begin, end;
m_Inclusive= bInclusive;
if( bInclusive )
m_pNoteData->GetTapNoteRangeInclusive( iTrack, iStartRow, iEndRow, begin, end );
else
@@ -1228,6 +1274,7 @@ NoteData::_all_tracks_iterator<ND, iter, TN>::_all_tracks_iterator( ND &nd, int
m_vBeginIters.push_back( begin );
m_vEndIters.push_back( end );
m_PrevCurrentRows.push_back(0);
iter cur;
if( m_bReverse )
@@ -1242,6 +1289,7 @@ NoteData::_all_tracks_iterator<ND, iter, TN>::_all_tracks_iterator( ND &nd, int
}
m_vCurrentIters.push_back( cur );
}
m_pNoteData->AddATIToList(this);
Find( bReverse );
}
@@ -1254,14 +1302,28 @@ NoteData::_all_tracks_iterator<ND, iter, TN>::_all_tracks_iterator( const _all_t
COPY_OTHER( m_vCurrentIters ),
COPY_OTHER( m_vEndIters ),
COPY_OTHER( m_iTrack ),
COPY_OTHER( m_bReverse )
COPY_OTHER( m_bReverse ),
COPY_OTHER( m_PrevCurrentRows ),
COPY_OTHER( m_StartRow ),
COPY_OTHER( m_EndRow )
#undef COPY_OTHER
{
m_pNoteData->AddATIToList(this);
}
template<typename ND, typename iter, typename TN>
NoteData::_all_tracks_iterator<ND, iter, TN>::~_all_tracks_iterator()
{
if(m_pNoteData != NULL)
{
m_pNoteData->RemoveATIFromList(this);
}
}
template<typename ND, typename iter, typename TN>
NoteData::_all_tracks_iterator<ND, iter, TN> &NoteData::_all_tracks_iterator<ND, iter, TN>::operator++() // preincrement
{
m_PrevCurrentRows[m_iTrack]= Row();
if( m_bReverse )
{
if( m_vCurrentIters[m_iTrack] == m_vBeginIters[m_iTrack] )
@@ -1284,6 +1346,71 @@ NoteData::_all_tracks_iterator<ND, iter, TN> NoteData::_all_tracks_iterator<ND,
operator++();
return ret;
}
template<typename ND, typename iter, typename TN>
void NoteData::_all_tracks_iterator<ND, iter, TN>::Revalidate(
ND* notedata, vector<int> const& added_or_removed_tracks, bool added)
{
m_pNoteData= notedata;
ASSERT( m_pNoteData->GetNumTracks() > 0 );
if(!added_or_removed_tracks.empty())
{
if(added)
{
int avg_row= 0;
for(size_t p= 0; p < m_PrevCurrentRows.size(); ++p)
{
avg_row+= m_PrevCurrentRows[p];
}
avg_row/= m_PrevCurrentRows.size();
for(size_t a= 0; a < added_or_removed_tracks.size(); ++a)
{
int track_id= added_or_removed_tracks[a];
m_PrevCurrentRows.insert(m_PrevCurrentRows.begin()+track_id, avg_row);
}
m_vBeginIters.resize(m_pNoteData->GetNumTracks());
m_vCurrentIters.resize(m_pNoteData->GetNumTracks());
m_vEndIters.resize(m_pNoteData->GetNumTracks());
}
else
{
for(size_t a= 0; a < added_or_removed_tracks.size(); ++a)
{
int track_id= added_or_removed_tracks[a];
m_PrevCurrentRows.erase(m_PrevCurrentRows.begin()+track_id);
}
m_vBeginIters.resize(m_pNoteData->GetNumTracks());
m_vCurrentIters.resize(m_pNoteData->GetNumTracks());
m_vEndIters.resize(m_pNoteData->GetNumTracks());
}
}
for(int track= 0; track < m_pNoteData->GetNumTracks(); ++track)
{
iter begin, end;
if(m_Inclusive)
{
m_pNoteData->GetTapNoteRangeInclusive(track, m_StartRow, m_EndRow, begin, end);
}
else
{
m_pNoteData->GetTapNoteRange(track, m_StartRow, m_EndRow, begin, end);
}
m_vBeginIters[track]= begin;
m_vEndIters[track]= end;
iter cur;
if(m_bReverse)
{
cur= m_pNoteData->upper_bound(track, m_PrevCurrentRows[track]);
}
else
{
cur= m_pNoteData->lower_bound(track, m_PrevCurrentRows[track]);
}
m_vCurrentIters[track]= cur;
}
Find(m_bReverse);
}
/* XXX: This doesn't satisfy the requirements that ++iter; --iter; is a no-op so it cannot be bidirectional for now. */
#if 0
template<typename ND, typename iter, typename TN>
+33 -2
View File
@@ -47,7 +47,12 @@ public:
const_iterator lower_bound( int iTrack, int iRow ) const { return m_TapNotes[iTrack].lower_bound( iRow ); }
iterator upper_bound( int iTrack, int iRow ) { return m_TapNotes[iTrack].upper_bound( iRow ); }
const_iterator upper_bound( int iTrack, int iRow ) const { return m_TapNotes[iTrack].upper_bound( iRow ); }
void swap( NoteData &nd ) { m_TapNotes.swap( nd.m_TapNotes ); }
void swap( NoteData &nd )
{
m_TapNotes.swap(nd.m_TapNotes);
m_atis.swap(nd.m_atis);
m_const_atis.swap(nd.m_const_atis);
}
// This is ugly to make it templated but I don't want to have to write the same class twice.
@@ -65,10 +70,18 @@ public:
int m_iTrack;
bool m_bReverse;
// These exist so that the iterator can be revalidated if the NoteData is
// transformed during this iterator's lifetime.
vector<int> m_PrevCurrentRows;
bool m_Inclusive;
int m_StartRow;
int m_EndRow;
void Find( bool bReverse );
public:
_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive );
_all_tracks_iterator( const _all_tracks_iterator &other );
~_all_tracks_iterator();
_all_tracks_iterator &operator++(); // preincrement
_all_tracks_iterator operator++( int dummy ); // postincrement
//_all_tracks_iterator &operator--(); // predecrement
@@ -81,11 +94,15 @@ public:
inline TN *operator->() { DEBUG_ASSERT( !IsAtEnd() ); return &m_vCurrentIters[m_iTrack]->second; }
inline const TN &operator*() const { DEBUG_ASSERT( !IsAtEnd() ); return m_vCurrentIters[m_iTrack]->second; }
inline const TN *operator->() const { DEBUG_ASSERT( !IsAtEnd() ); return &m_vCurrentIters[m_iTrack]->second; }
// Use when transforming the NoteData.
void Revalidate(ND* notedata, vector<int> const& added_or_removed_tracks, bool added);
};
typedef _all_tracks_iterator<NoteData, NoteData::iterator, TapNote> all_tracks_iterator;
typedef _all_tracks_iterator<const NoteData, NoteData::const_iterator, const TapNote> all_tracks_const_iterator;
typedef all_tracks_iterator all_tracks_reverse_iterator;
typedef all_tracks_const_iterator all_tracks_const_reverse_iterator;
friend class _all_tracks_iterator<NoteData, NoteData::iterator, TapNote>;
friend class _all_tracks_iterator<const NoteData, NoteData::const_iterator, const TapNote>;
private:
// There's no point in inserting empty notes into the map.
// Any blank space in the map is defined to be empty.
@@ -129,7 +146,17 @@ private:
pair<int, int> GetNumRowsWithSimultaneousTapsTwoPlayer(int minTaps = 2,
int startRow = 0,
int endRow = MAX_NOTE_ROW) const;
// These exist so that they can be revalidated when something that transforms
// the NoteData occurs. -Kyz
mutable set<all_tracks_iterator*> m_atis;
mutable set<all_tracks_const_iterator*> m_const_atis;
void AddATIToList(all_tracks_iterator* iter) const;
void AddATIToList(all_tracks_const_iterator* iter) const;
void RemoveATIFromList(all_tracks_iterator* iter) const;
void RemoveATIFromList(all_tracks_const_iterator* iter) const;
public:
void Init();
@@ -196,6 +223,10 @@ public:
return all_tracks_const_iterator(*this, iStartRow, iEndRow, true, bInclusive );
}
// Call this after using any transform that changes the NoteData.
void RevalidateATIs(vector<int> const& added_or_removed_tracks, bool added);
void TransferATIs(NoteData& to);
/* Return an iterator range include iStartRow to iEndRow. Extend the range to include
* hold notes overlapping the boundary. */
void GetTapNoteRangeInclusive(int iTrack, int iStartRow, int iEndRow,
+32 -1
View File
@@ -261,6 +261,7 @@ static void LoadFromSMNoteDataStringWithPlayer( NoteData& out, const RString &sS
begin = next;
}
}
out.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, const RString &sSMNoteData_, bool bComposite )
@@ -311,6 +312,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, const RString &sSMNo
LoadFromSMNoteDataStringWithPlayer( nd, sSMNoteData, start, size, pn, iNumTracks );
}
CombineCompositeNoteData( out, vParts );
out.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::InsertHoldTails( NoteData &inout )
@@ -487,6 +489,7 @@ void NoteDataUtil::CombineCompositeNoteData( NoteData &out, const vector<NoteDat
}
}
}
out.RevalidateATIs(vector<int>(), false);
}
@@ -557,6 +560,7 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o
out.SetTapNote( iNewTrack, r, tn );
}
}
out.RevalidateATIs(vector<int>(), false);
}
void PlaceAutoKeysound( NoteData &out, int row, TapNote akTap )
@@ -672,6 +676,7 @@ void NoteDataUtil::LoadOverlapped( const NoteData &in, NoteData &out, int iNewNu
PlaceAutoKeysound( out, row, tnFrom );
}
}
out.RevalidateATIs(vector<int>(), false);
}
int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow )
@@ -981,6 +986,7 @@ void NoteDataUtil::RemoveHoldNotes( NoteData &in, int iStartIndex, int iEndIndex
begin->second.type = TapNote::tap;
}
}
in.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::ChangeRollsToHolds( NoteData &in, int iStartIndex, int iEndIndex )
@@ -997,6 +1003,7 @@ void NoteDataUtil::ChangeRollsToHolds( NoteData &in, int iStartIndex, int iEndIn
begin->second.subType = TapNote::hold_head_hold;
}
}
in.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::ChangeHoldsToRolls( NoteData &in, int iStartIndex, int iEndIndex )
@@ -1013,6 +1020,7 @@ void NoteDataUtil::ChangeHoldsToRolls( NoteData &in, int iStartIndex, int iEndIn
begin->second.subType = TapNote::hold_head_roll;
}
}
in.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::RemoveSimultaneousNotes( NoteData &in, int iMaxSimultaneous, int iStartIndex, int iEndIndex )
@@ -1051,6 +1059,7 @@ void NoteDataUtil::RemoveSimultaneousNotes( NoteData &in, int iMaxSimultaneous,
}
}
}
in.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::RemoveJumps( NoteData &inout, int iStartIndex, int iEndIndex )
@@ -1074,6 +1083,7 @@ void NoteDataUtil::RemoveSpecificTapNotes( NoteData &inout, TapNote::Type tn, in
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( inout, t, r, iStartIndex, iEndIndex )
if( inout.GetTapNote(t,r).type == tn )
inout.SetTapNote( t, r, TAP_EMPTY );
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::RemoveMines( NoteData &inout, int iStartIndex, int iEndIndex )
@@ -1110,6 +1120,7 @@ void NoteDataUtil::RemoveAllButOneTap( NoteData &inout, int row )
if( iter != inout.end(track) && iter->second.type == TapNote::tap )
inout.RemoveTapNote( track, iter );
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::RemoveAllButPlayer( NoteData &inout, PlayerNumber pn )
@@ -1126,6 +1137,7 @@ void NoteDataUtil::RemoveAllButPlayer( NoteData &inout, PlayerNumber pn )
++i;
}
}
inout.RevalidateATIs(vector<int>(), false);
}
// TODO: Perform appropriate matrix calculations for everything instead.
@@ -1536,6 +1548,7 @@ void NoteDataUtil::Turn( NoteData &inout, StepsType st, TrackMapping tt, int iSt
SuperShuffleTaps( tempNoteData, iStartIndex, iEndIndex );
inout.CopyAll( tempNoteData );
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Backwards( NoteData &inout )
@@ -1560,6 +1573,7 @@ void NoteDataUtil::Backwards( NoteData &inout )
}
inout.swap( out );
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::SwapSides( NoteData &inout )
@@ -1575,6 +1589,7 @@ void NoteDataUtil::SwapSides( NoteData &inout )
NoteData orig( inout );
inout.LoadTransformed( orig, orig.GetNumTracks(), iOriginalTrackToTakeFrom );
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Little( NoteData &inout, int iStartIndex, int iEndIndex )
@@ -1589,6 +1604,7 @@ void NoteDataUtil::Little( NoteData &inout, int iStartIndex, int iEndIndex )
inout.SetTapNote( t, i, TAP_EMPTY );
}
}
inout.RevalidateATIs(vector<int>(), false);
}
// Make all quarter notes into jumps.
@@ -1641,6 +1657,7 @@ void NoteDataUtil::Wide( NoteData &inout, int iStartIndex, int iEndIndex )
}
inout.SetTapNote(iTrackToAdd, i, TAP_ADDITION_TAP);
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Big( NoteData &inout, int iStartIndex, int iEndIndex )
@@ -1747,6 +1764,7 @@ void NoteDataUtil::InsertIntelligentTaps(
inout.SetTapNote(iTrackOfNoteToAdd, iRowToAdd, TAP_ADDITION_TAP);
}
inout.RevalidateATIs(vector<int>(), false);
}
#if 0
class TrackIterator
@@ -1873,6 +1891,7 @@ void NoteDataUtil::AddMines( NoteData &inout, int iStartIndex, int iEndIndex )
iRowCount = 0;
}
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex )
@@ -1927,6 +1946,7 @@ void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex )
inout.SetTapNote( iEchoTrack, iRowEcho, TAP_ADDITION_TAP );
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Planted( NoteData &inout, int iStartIndex, int iEndIndex )
@@ -1999,7 +2019,7 @@ void NoteDataUtil::ConvertTapsToHolds( NoteData &inout, int iSimultaneousHolds,
}
}
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Stomp( NoteData &inout, StepsType st, int iStartIndex, int iEndIndex )
@@ -2042,6 +2062,7 @@ void NoteDataUtil::Stomp( NoteData &inout, StepsType st, int iStartIndex, int iE
}
}
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::SnapToNearestNoteType( NoteData &inout, NoteType nt1, NoteType nt2, int iStartIndex, int iEndIndex )
@@ -2088,6 +2109,7 @@ void NoteDataUtil::SnapToNearestNoteType( NoteData &inout, NoteType nt1, NoteTyp
inout.SetTapNote( c, iNewIndex, tnNew );
}
}
inout.RevalidateATIs(vector<int>(), false);
}
@@ -2254,6 +2276,7 @@ void NoteDataUtil::RemoveStretch( NoteData &inout, StepsType st, int iStartIndex
if( !bPassedOneMask )
RemoveAllButOneTap( inout, r );
}
inout.RevalidateATIs(vector<int>(), false);
}
bool NoteDataUtil::RowPassesValidMask( NoteData &inout, int row, const bool bValidMask[] )
@@ -2277,6 +2300,7 @@ void NoteDataUtil::ConvertAdditionsToRegular( NoteData &inout )
tn.source = TapNote::original;
inout.SetTapNote( t, r, tn );
}
inout.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::TransformNoteData( NoteData &nd, const AttackArray &aa, StepsType st, Song* pSong )
@@ -2373,6 +2397,7 @@ void NoteDataUtil::AddTapAttacks( NoteData &nd, Song* pSong )
-1 );
nd.SetTapNote( iTrack, BeatToNoteRow(fBeat), tn );
}
nd.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::Scale( NoteData &nd, float fScale )
@@ -2395,6 +2420,7 @@ void NoteDataUtil::Scale( NoteData &nd, float fScale )
}
nd.swap( ndOut );
nd.RevalidateATIs(vector<int>(), false);
}
/* XXX: move this to an appropriate place, same place as NoteRowToBeat perhaps? */
@@ -2430,6 +2456,7 @@ void NoteDataUtil::ScaleRegion( NoteData &nd, float fScale, int iStartIndex, int
}
nd.swap( ndOut );
nd.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::InsertRows( NoteData &nd, int iStartIndex, int iRowsToAdd )
@@ -2441,6 +2468,7 @@ void NoteDataUtil::InsertRows( NoteData &nd, int iStartIndex, int iRowsToAdd )
temp.CopyRange( nd, iStartIndex, MAX_NOTE_ROW );
nd.ClearRange( iStartIndex, MAX_NOTE_ROW );
nd.CopyRange( temp, 0, MAX_NOTE_ROW, iStartIndex + iRowsToAdd );
nd.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::DeleteRows( NoteData &nd, int iStartIndex, int iRowsToDelete )
@@ -2452,6 +2480,7 @@ void NoteDataUtil::DeleteRows( NoteData &nd, int iStartIndex, int iRowsToDelete
temp.CopyRange( nd, iStartIndex + iRowsToDelete, MAX_NOTE_ROW );
nd.ClearRange( iStartIndex, MAX_NOTE_ROW );
nd.CopyRange( temp, 0, MAX_NOTE_ROW, iStartIndex );
nd.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::RemoveAllTapsOfType( NoteData& ndInOut, TapNote::Type typeToRemove )
@@ -2470,6 +2499,7 @@ void NoteDataUtil::RemoveAllTapsOfType( NoteData& ndInOut, TapNote::Type typeToR
++iter;
}
}
ndInOut.RevalidateATIs(vector<int>(), false);
}
void NoteDataUtil::RemoveAllTapsExceptForType( NoteData& ndInOut, TapNote::Type typeToKeep )
@@ -2485,6 +2515,7 @@ void NoteDataUtil::RemoveAllTapsExceptForType( NoteData& ndInOut, TapNote::Type
++iter;
}
}
ndInOut.RevalidateATIs(vector<int>(), false);
}
int NoteDataUtil::GetMaxNonEmptyTrack( const NoteData& in )