From dc55f1391a7cbfb56d5a5a273412ceae2a7037b5 Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Wed, 23 Jul 2014 05:34:23 -0600 Subject: [PATCH] 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. --- src/NoteData.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++- src/NoteData.h | 35 +++++++++++- src/NoteDataUtil.cpp | 33 ++++++++++- 3 files changed, 194 insertions(+), 5 deletions(-) diff --git a/src/NoteData.cpp b/src/NoteData.cpp index 24bb051fea..52a1daf4ac 100644 --- a/src/NoteData.cpp +++ b/src/NoteData.cpp @@ -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::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::iterator pos= m_const_atis.find(iter); + if(pos != m_const_atis.end()) + { + m_const_atis.erase(pos); + } +} + +void NoteData::RevalidateATIs(vector const& added_or_removed_tracks, bool added) +{ + for(set::iterator cur= m_atis.begin(); + cur != m_atis.end(); ++cur) + { + (*cur)->Revalidate(this, added_or_removed_tracks, added); + } + for(set::iterator cur= m_const_atis.begin(); + cur != m_const_atis.end(); ++cur) + { + (*cur)->Revalidate(this, added_or_removed_tracks, added); + } +} + template void NoteData::_all_tracks_iterator::Find( bool bReverse ) { @@ -1213,14 +1255,18 @@ void NoteData::_all_tracks_iterator::Find( bool bReverse ) } template -NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive ) : + NoteData::_all_tracks_iterator::_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::_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::_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::_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 + NoteData::_all_tracks_iterator::~_all_tracks_iterator() +{ + if(m_pNoteData != NULL) + { + m_pNoteData->RemoveATIFromList(this); + } } template NoteData::_all_tracks_iterator &NoteData::_all_tracks_iterator::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 NoteData::_all_tracks_iterator + void NoteData::_all_tracks_iterator::Revalidate( + ND* notedata, vector 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 diff --git a/src/NoteData.h b/src/NoteData.h index 6a7b4bf1d0..40033f1a2f 100644 --- a/src/NoteData.h +++ b/src/NoteData.h @@ -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 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 const& added_or_removed_tracks, bool added); }; typedef _all_tracks_iterator all_tracks_iterator; typedef _all_tracks_iterator 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; + friend class _all_tracks_iterator; 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 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 m_atis; + mutable set 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 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, diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 8ad1e123da..b521f84125 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -261,6 +261,7 @@ static void LoadFromSMNoteDataStringWithPlayer( NoteData& out, const RString &sS begin = next; } } + out.RevalidateATIs(vector(), 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(), false); } void NoteDataUtil::InsertHoldTails( NoteData &inout ) @@ -487,6 +489,7 @@ void NoteDataUtil::CombineCompositeNoteData( NoteData &out, const vector(), false); } @@ -557,6 +560,7 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o out.SetTapNote( iNewTrack, r, tn ); } } + out.RevalidateATIs(vector(), 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(), 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(), 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(), 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(), 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(), 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(), 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(), false); } void NoteDataUtil::RemoveAllButPlayer( NoteData &inout, PlayerNumber pn ) @@ -1126,6 +1137,7 @@ void NoteDataUtil::RemoveAllButPlayer( NoteData &inout, PlayerNumber pn ) ++i; } } + inout.RevalidateATIs(vector(), 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(), false); } void NoteDataUtil::Backwards( NoteData &inout ) @@ -1560,6 +1573,7 @@ void NoteDataUtil::Backwards( NoteData &inout ) } inout.swap( out ); + inout.RevalidateATIs(vector(), 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(), 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(), 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(), 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(), false); } #if 0 class TrackIterator @@ -1873,6 +1891,7 @@ void NoteDataUtil::AddMines( NoteData &inout, int iStartIndex, int iEndIndex ) iRowCount = 0; } } + inout.RevalidateATIs(vector(), 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(), false); } void NoteDataUtil::Planted( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1999,7 +2019,7 @@ void NoteDataUtil::ConvertTapsToHolds( NoteData &inout, int iSimultaneousHolds, } } } - + inout.RevalidateATIs(vector(), 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(), 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(), false); } @@ -2254,6 +2276,7 @@ void NoteDataUtil::RemoveStretch( NoteData &inout, StepsType st, int iStartIndex if( !bPassedOneMask ) RemoveAllButOneTap( inout, r ); } + inout.RevalidateATIs(vector(), 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(), 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(), 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(), 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(), 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(), 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(), 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(), false); } void NoteDataUtil::RemoveAllTapsExceptForType( NoteData& ndInOut, TapNote::Type typeToKeep ) @@ -2485,6 +2515,7 @@ void NoteDataUtil::RemoveAllTapsExceptForType( NoteData& ndInOut, TapNote::Type ++iter; } } + ndInOut.RevalidateATIs(vector(), false); } int NoteDataUtil::GetMaxNonEmptyTrack( const NoteData& in )