-
Notifications
You must be signed in to change notification settings - Fork 37
Add mines #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add mines #200
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces support for mines by adding a new HitObjectType and updating scoring, replay, and hit object management to handle them appropriately.
- Adds a new HitObjectType field and associated logic to differentiate normal notes from mines.
- Updates scoring methods and replay handling to account for mines, including separate tracking and removal of active mines.
- Adjusts replay key press handling and hit object retrieval to integrate the new mine behavior.
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Quaver.Tools/Commands/RecalculateCommand.cs | Updated CalculateScore calls to pass additional parameters. |
| Quaver.API/Replays/Virtual/VirtualReplayPlayer.cs | Added ActiveMines tracking and integrated mine handling logic. |
| Quaver.API/Replays/Replay.cs | Skips mine objects during autoplay key generation. |
| Quaver.API/Maps/Structures/HitObjectInfo.cs | Added Type property and updated judgement count logic. |
| Quaver.API/Maps/Qua.cs | Propagates the new Type and adjusts hit object indexing. |
| Quaver.API/Maps/Processors/Scoring/ScoreProcessorKeys.cs | Overloaded CalculateScore methods with mine support. |
| Quaver.API/Maps/Processors/Scoring/ScoreProcessor.cs | Updated abstract CalculateScore signature for mine handling. |
| Quaver.API/Enums/HitObjectType.cs | Introduces the new HitObjectType enum with Normal and Mine. |
Comments suppressed due to low confidence (2)
Quaver.API/Replays/Virtual/VirtualReplayPlayer.cs:123
- Consider adding a descriptive message to the ArgumentOutOfRangeException to clarify that an unsupported HitObjectType was encountered.
throw new ArgumentOutOfRangeException();
Quaver.API/Replays/Virtual/VirtualReplayPlayer.cs:463
- Update this comment to accurately reflect that a marvelous judgement is applied for mines when not triggered, rather than a miss.
// Add a miss to the score.
…merging shared soon
# Conflicts: # Quaver.API/Replays/Virtual/VirtualReplayPlayer.cs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
Quaver.API/Replays/Replay.cs:347
- This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.
foreach (var hitObject in map.HitObjects)
{
if (hitObject.Type is HitObjectType.Mine)
continue;
// Add key press frame
nonCombined.Add(new ReplayAutoplayFrame(hitObject, ReplayAutoplayFrameType.Press, hitObject.StartTime, KeyLaneToPressState(hitObject.Lane)));
// If LN, add key up state at end time
if (hitObject.IsLongNote)
nonCombined.Add(new ReplayAutoplayFrame(hitObject, ReplayAutoplayFrameType.Release, hitObject.EndTime - 1, KeyLaneToPressState(hitObject.Lane)));
// If not ln, add key up frame 1ms after object.
else
nonCombined.Add(new ReplayAutoplayFrame(hitObject, ReplayAutoplayFrameType.Release, hitObject.StartTime + 30, KeyLaneToPressState(hitObject.Lane)));
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Add a new hit stat to the score processor. | ||
| var stat = new HitStat(HitStatType.Miss, KeyPressType.Press, mine, Time, Judgement.Miss, hitDifference, | ||
| ScoreProcessor.Accuracy, ScoreProcessor.Health); | ||
|
|
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CalculateScore method should be called before adding the HitStat to ScoreProcessor.Stats. This is inconsistent with the pattern used throughout the rest of the code (e.g., lines 156-161, 408-416, 438-445) where CalculateScore is always called first to update the score processor state, and then the stat is added to the Stats list.
| ScoreProcessor.CalculateScore(stat); |
| var stat = new HitStat(HitStatType.Hit, KeyPressType.None, hitObject, hitObject.StartTime, Judgement.Marv, 0, | ||
| ScoreProcessor.Accuracy, ScoreProcessor.Health); | ||
|
|
||
| // Add a miss to the score. |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says "Add a miss to the score" but the code is actually adding a Marvelous judgement (Judgement.Marv), which represents successfully avoiding the mine. The comment should be corrected to reflect that this is awarding a Marvelous for avoiding the mine, not a miss.
| // Add a miss to the score. | |
| // Award a Marvelous for successfully avoiding the mine. |
| .Concat(previousFramePressed.Except(currentFramePressed)) | ||
| .ToList(); | ||
|
|
||
| foreach (var lane in previousFramePressed) |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mine detection logic iterates over previousFramePressed (keys held from the previous frame) instead of newly pressed keys. This means mines won't be triggered when a key is freshly pressed during the current frame - only when a key that was already held continues to be held. According to the PR description, mines should trigger when the player presses on the lane where a mine is present within the timing window. Consider checking against currentFramePressed.Except(previousFramePressed) to detect newly pressed keys instead.
| foreach (var lane in previousFramePressed) | |
| foreach (var lane in currentFramePressed.Except(previousFramePressed)) |
| var hitDifference = | ||
| mine.StartTime - ScoreProcessor.JudgementWindow[Judgement.Marv] > previousFrameTime | ||
| ? (int)ScoreProcessor.JudgementWindow[Judgement.Marv] | ||
| : mine.StartTime - previousFrameTime; |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hitDifference calculation logic seems unusual. When previousFrameTime is before the mine's window start (mine.StartTime - JudgementWindow), it sets hitDifference to JudgementWindow. Otherwise, it sets hitDifference to mine.StartTime - previousFrameTime. This doesn't follow the typical pattern where hitDifference represents the timing offset from when the object should be hit. For consistency with normal hit objects (line 279), consider using a calculation like mine.StartTime - Time or similar to represent the actual timing error.
| var hitDifference = | |
| mine.StartTime - ScoreProcessor.JudgementWindow[Judgement.Marv] > previousFrameTime | |
| ? (int)ScoreProcessor.JudgementWindow[Judgement.Marv] | |
| : mine.StartTime - previousFrameTime; | |
| var hitDifference = mine.StartTime - Time; |
|
requesting support for utils.createhitobject to have a mine parameter |
Adds a field
Type: HitObjectTypethat indicates whether the hit object is aNormalnote or aMine. With this design you would actually be able to make long mines?When the player is pressing on the lane where a mine is present, and the timing falls into the marvelous timing window, then it is considered a miss. If the player does not press the mine and passes the marvelous window of the mine, a marvelous judgement is generated, indicating that the mine is not set off.