Skip to content

Commit 75db75e

Browse files
committed
Account for dropped & completed holds in Replay precalculations
1 parent d7e2c08 commit 75db75e

File tree

2 files changed

+70
-19
lines changed

2 files changed

+70
-19
lines changed

src/Etterna/Models/Misc/PlayerAI.cpp

+63-17
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ PlayerAI::SetScoreData(HighScore* pHighScore, int firstRow, NoteData* pNoteData)
126126

127127
// Generate vectors made of pregenerated HoldReplayResults referenced by the
128128
// song row in a map
129+
// Only present in replays with column data.
129130
for (size_t i = 0; i < replayHoldVector.size(); i++) {
130131
if (replayHoldVector[i].row < firstRow)
131132
continue;
@@ -151,7 +152,9 @@ PlayerAI::SetScoreData(HighScore* pHighScore, int firstRow, NoteData* pNoteData)
151152
// We leave out misses in this section because they aren't in the Replay
152153
// Data
153154
int tempJudgments[NUM_TapNoteScore] = { 0 };
154-
int holdsDropped = 0;
155+
int tempHNS[NUM_HoldNoteScore] = { 0 };
156+
157+
// Iterate over all the noterows we know are in the Replay Data
155158
for (auto r = validNoterows.begin(); r != validNoterows.end(); r++) {
156159
// Check for taps and mines
157160
if (m_ReplayTapMap.count(*r) != 0) {
@@ -173,21 +176,24 @@ PlayerAI::SetScoreData(HighScore* pHighScore, int firstRow, NoteData* pNoteData)
173176
for (auto instance = m_ReplayHoldMap[*r].begin();
174177
instance != m_ReplayHoldMap[*r].end();
175178
instance++) {
176-
holdsDropped++;
179+
tempHNS[HNS_LetGo]++;
177180
}
178181
}
179182

180183
// Make the struct and cram it in there
181184
ReplaySnapshot rs;
182185
FOREACH_ENUM(TapNoteScore, tns)
183-
{
184-
rs.judgments[tns] = tempJudgments[tns];
185-
}
186-
rs.holdsDropped = holdsDropped;
186+
rs.judgments[tns] = tempJudgments[tns];
187+
FOREACH_ENUM(HoldNoteScore, hns)
188+
rs.hns[hns] = tempHNS[hns];
187189
m_ReplaySnapshotMap[*r] = rs;
188190
}
189191

190-
// Now handle misses.
192+
// map tracks to rows that begin a hold
193+
vector<int> tempHoldsByTrack;
194+
tempHoldsByTrack.reserve(pNoteData->GetNumTracks());
195+
196+
// Now handle misses and holds.
191197
// For every row in notedata...
192198
FOREACH_NONEMPTY_ROW_ALL_TRACKS(*pNoteData, row)
193199
{
@@ -200,6 +206,18 @@ PlayerAI::SetScoreData(HighScore* pHighScore, int firstRow, NoteData* pNoteData)
200206
pTN = &iter->second;
201207

202208
if (iter != pNoteData->end(track)) {
209+
// Deal with holds here
210+
if (pTN->type == TapNoteType_HoldTail) {
211+
int startrow = tempHoldsByTrack.at(track);
212+
if (IsHoldDroppedInRowRangeForTrack(startrow, row, track)) {
213+
tempHNS[HNS_LetGo]++;
214+
} else {
215+
tempHNS[HNS_Held]++;
216+
}
217+
} else if (pTN->type == TapNoteType_HoldHead) {
218+
tempHoldsByTrack.at(track) = row;
219+
}
220+
203221
// It is impossible to "miss" these notes
204222
if (pTN->type == TapNoteType_Mine ||
205223
pTN->type == TapNoteType_Fake ||
@@ -222,21 +240,22 @@ PlayerAI::SetScoreData(HighScore* pHighScore, int firstRow, NoteData* pNoteData)
222240
}
223241
}
224242
}
225-
// We have to update every single row with the new miss counts.
243+
// We have to update every single row with the new miss & hns counts.
226244
// This unfortunately takes more time.
227245
// If current row is recorded in the snapshots, update the miss count
228246
if (m_ReplaySnapshotMap.count(row) != 0) {
229247
m_ReplaySnapshotMap[row].judgments[TNS_Miss] =
230248
tempJudgments[TNS_Miss];
249+
FOREACH_ENUM(HoldNoteScore, hns)
250+
m_ReplaySnapshotMap[row].hns[hns] = tempHNS[hns];
231251
} else {
232252
// If the current row is after the last recorded row, make a new one
233253
if (m_ReplaySnapshotMap.rbegin()->first < row) {
234254
ReplaySnapshot rs;
235255
FOREACH_ENUM(TapNoteScore, tns)
236-
{
237-
rs.judgments[tns] = tempJudgments[tns];
238-
}
239-
rs.holdsDropped = holdsDropped;
256+
rs.judgments[tns] = tempJudgments[tns];
257+
FOREACH_ENUM(HoldNoteScore, hns)
258+
rs.hns[hns] = tempHNS[hns];
240259
m_ReplaySnapshotMap[row] = rs;
241260
}
242261
// If the current row is before the earliest recorded row, make a
@@ -251,11 +270,9 @@ PlayerAI::SetScoreData(HighScore* pHighScore, int firstRow, NoteData* pNoteData)
251270
ReplaySnapshot rs;
252271
const int prev = m_ReplaySnapshotMap.lower_bound(row)->first;
253272
FOREACH_ENUM(TapNoteScore, tns)
254-
{
255-
rs.judgments[tns] =
256-
m_ReplaySnapshotMap[prev].judgments[tns];
257-
}
258-
rs.holdsDropped = m_ReplaySnapshotMap[prev].holdsDropped;
273+
rs.judgments[tns] = m_ReplaySnapshotMap[prev].judgments[tns];
274+
FOREACH_ENUM(HoldNoteScore, hns)
275+
rs.hns[hns] = m_ReplaySnapshotMap[prev].hns[hns];
259276
m_ReplaySnapshotMap[row] = rs;
260277
}
261278
}
@@ -391,6 +408,35 @@ PlayerAI::DetermineIfHoldDropped(int noteRow, int col)
391408
return false;
392409
}
393410

411+
bool
412+
PlayerAI::IsHoldDroppedInRowRangeForTrack(int firstRow, int endRow, int track)
413+
{
414+
// 2 is a replay with column data
415+
if (pScoreData->GetReplayType() == 2) {
416+
// Go over all holds in Replay Data
417+
for (auto hiter = m_ReplayHoldMap.lower_bound(firstRow);
418+
hiter != m_ReplayHoldMap.end();
419+
hiter++) {
420+
// If this row is before the start, skip it
421+
if (hiter->first < firstRow)
422+
continue;
423+
// If this row is after the end, skip it
424+
else if (hiter->first > endRow)
425+
return false;
426+
// This row might work. Check what tracks might have dropped.
427+
for (auto hrr : hiter->second) {
428+
if (hrr.track == track)
429+
return true;
430+
}
431+
}
432+
// Iteration finished without finding a drop.
433+
return false;
434+
} else {
435+
// Replay Data doesn't contain hold data.
436+
return false;
437+
}
438+
}
439+
394440
bool
395441
PlayerAI::TapExistsAtThisRow(int noteRow)
396442
{

src/Etterna/Models/Misc/PlayerAI.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ struct ReplaySnapshot
1717
{
1818
// Contains Marv->Miss and Mines Hit
1919
int judgments[NUM_TapNoteScore] = { 0 };
20-
// Holds dropped
21-
int holdsDropped = 0;
20+
// Hold note scores
21+
int hns[NUM_HoldNoteScore] = { 0 };
2222
};
2323

2424
// also known as ReplayManager
@@ -63,6 +63,11 @@ class PlayerAI
6363
const PlayerState* pPlayerState,
6464
float fNoteOffset);
6565
static bool DetermineIfHoldDropped(int noteRow, int col);
66+
// Returns true or false if the given range contains a dropped hold on the
67+
// track
68+
static bool IsHoldDroppedInRowRangeForTrack(int firstRow,
69+
int endRow,
70+
int track);
6671
// Returns the column that needs to be tapped.
6772
// Returns -1 if no column needs to be tapped.
6873
static int DetermineNextTapColumn(int noteRow,

0 commit comments

Comments
 (0)