Skip to content
This repository has been archived by the owner on Oct 8, 2024. It is now read-only.

[osu!std] Approximate amount of misses + sliderbreaks in a play #131

Merged
merged 7 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/pp/performance/Beatmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ class Beatmap
ERankedStatus RankedStatus() const { return _rankedStatus; }
EScoreVersion ScoreVersion() const { return _scoreVersion; }
s32 NumHitCircles() const { return _numHitCircles; }
s32 NumSliders() const { return _numSliders; }
s32 NumSpinners() const { return _numSpinners; }
f32 DifficultyAttribute(EMods mods, EDifficultyAttributeType type) const;

void SetRankedStatus(ERankedStatus rankedStatus) { _rankedStatus = rankedStatus; }
void SetScoreVersion(EScoreVersion scoreVersion) { _scoreVersion = scoreVersion; }
void SetNumHitCircles(s32 numHitCircles) { _numHitCircles = numHitCircles; }
void SetNumSliders(s32 numSliders) { _numSliders = numSliders; }
void SetNumSpinners(s32 numSpinners) { _numSpinners = numSpinners; }
void SetDifficultyAttribute(EMods mods, EDifficultyAttributeType type, f32 value);

Expand All @@ -79,6 +81,7 @@ class Beatmap
ERankedStatus _rankedStatus;
EScoreVersion _scoreVersion;
s32 _numHitCircles = 0;
s32 _numSliders = 0;
s32 _numSpinners = 0;
};

Expand Down
2 changes: 2 additions & 0 deletions include/pp/performance/osu/OsuScore.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ class OsuScore : public Score
f32 _speedValue;
f32 _accValue;
f32 _flashlightValue;
s32 _effectiveMissCount;

void computeTotalValue(const Beatmap &beatmap);
f32 _totalValue;

void computeEffectiveMissCount(const Beatmap &beatmap);
void computeAimValue(const Beatmap &beatmap);
void computeSpeedValue(const Beatmap &beatmap);
void computeAccValue(const Beatmap &beatmap);
Expand Down
3 changes: 2 additions & 1 deletion src/performance/Processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ void Processor::queryAllBeatmapDifficulties(u32 numThreads)
bool Processor::queryBeatmapDifficulty(DatabaseConnection& dbSlave, s32 startId, s32 endId)
{
std::string query = StrFormat(
"SELECT `osu_beatmaps`.`beatmap_id`,`countNormal`,`mods`,`attrib_id`,`value`,`approved`,`score_version`, `countSpinner` "
"SELECT `osu_beatmaps`.`beatmap_id`,`countNormal`,`mods`,`attrib_id`,`value`,`approved`,`score_version`, `countSpinner`, `countSlider` "
"FROM `osu_beatmaps` "
"JOIN `osu_beatmap_difficulty_attribs` ON `osu_beatmaps`.`beatmap_id` = `osu_beatmap_difficulty_attribs`.`beatmap_id` "
"WHERE (`osu_beatmaps`.`playmode`=0 OR `osu_beatmaps`.`playmode`={0}) AND `osu_beatmap_difficulty_attribs`.`mode`={0} AND `approved` BETWEEN {1} AND {2}",
Expand Down Expand Up @@ -651,6 +651,7 @@ bool Processor::queryBeatmapDifficulty(DatabaseConnection& dbSlave, s32 startId,
beatmap.SetRankedStatus(res[5]);
beatmap.SetScoreVersion(res[6]);
beatmap.SetNumHitCircles(res.IsNull(1) ? 0 : (s32)res[1]);
beatmap.SetNumSliders(res.IsNull(8) ? 0 : (s32)res[8]);
beatmap.SetNumSpinners(res.IsNull(7) ? 0 : (s32)res[7]);
beatmap.SetDifficultyAttribute(res[2], _difficultyAttributes[(s32)res[3]], res[4]);
}
Expand Down
30 changes: 25 additions & 5 deletions src/performance/osu/OsuScore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ OsuScore::OsuScore(
EMods mods,
const Beatmap &beatmap) : Score{scoreId, mode, userId, beatmapId, score, maxCombo, num300, num100, num50, numMiss, numGeki, numKatu, mods}
{
computeEffectiveMissCount(beatmap);

computeAimValue(beatmap);
computeSpeedValue(beatmap);
computeAccValue(beatmap);
Expand Down Expand Up @@ -51,6 +53,24 @@ s32 OsuScore::TotalSuccessfulHits() const
return _num50 + _num100 + _num300;
}

void OsuScore::computeEffectiveMissCount(const Beatmap &beatmap)
{
// guess the number of misses + slider breaks from combo
f32 comboBasedMissCount = 0.0f;
f32 beatmapMaxCombo = beatmap.DifficultyAttribute(_mods, Beatmap::MaxCombo);
if (beatmap.NumSliders() > 0)
{
f32 fullComboThreshold = beatmapMaxCombo - 0.1f * beatmap.NumSliders();
Copy link

@Zyfarok Zyfarok Oct 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be good to have 0.1f as a PSF like SLIDER_END_RATIO or something even more explicit.
Also, 0.1f * beatmap.NumSliders() is used twice and could be stored in a variable ?

(Also, beatmapMaxCombo seems to only be used inside the if, so you might want to move it inside ?)

if (_maxCombo < fullComboThreshold)
comboBasedMissCount = fullComboThreshold / std::max(1, _maxCombo);
}

// we're clamping misscount because since its derived from combo it can be higher than total hits and that breaks some calculations
comboBasedMissCount = std::min(comboBasedMissCount, static_cast<f32>(TotalHits()));

_effectiveMissCount = std::max(_numMiss, static_cast<s32>(std::floor(comboBasedMissCount)));
smoogipoo marked this conversation as resolved.
Show resolved Hide resolved
}

void OsuScore::computeTotalValue(const Beatmap &beatmap)
{
// Don't count scores made with supposedly unranked mods
Expand All @@ -66,7 +86,7 @@ void OsuScore::computeTotalValue(const Beatmap &beatmap)
f32 multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things.

if ((_mods & EMods::NoFail) > 0)
multiplier *= std::max(0.9f, 1.0f - 0.02f * _numMiss);
multiplier *= std::max(0.9f, 1.0f - 0.02f * _effectiveMissCount);

int numTotalHits = TotalHits();
if ((_mods & EMods::SpunOut) > 0)
Expand Down Expand Up @@ -100,8 +120,8 @@ void OsuScore::computeAimValue(const Beatmap &beatmap)
_aimValue *= LengthBonus;

// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
if (_numMiss > 0)
_aimValue *= 0.97f * std::pow(1.0f - std::pow(_numMiss / static_cast<f32>(numTotalHits), 0.775f), _numMiss);
if (_effectiveMissCount > 0)
_aimValue *= 0.97f * std::pow(1.0f - std::pow(_effectiveMissCount / static_cast<f32>(numTotalHits), 0.775f), _effectiveMissCount);

// Combo scaling.
float maxCombo = beatmap.DifficultyAttribute(_mods, Beatmap::MaxCombo);
Expand Down Expand Up @@ -143,8 +163,8 @@ void OsuScore::computeSpeedValue(const Beatmap &beatmap)
_speedValue *= lengthBonus;

// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
if (_numMiss > 0)
_speedValue *= 0.97f * std::pow(1.0f - std::pow(_numMiss / static_cast<f32>(numTotalHits), 0.775f), std::pow(static_cast<f32>(_numMiss), 0.875f));
if (_effectiveMissCount > 0)
_speedValue *= 0.97f * std::pow(1.0f - std::pow(_effectiveMissCount / static_cast<f32>(numTotalHits), 0.775f), std::pow(static_cast<f32>(_effectiveMissCount), 0.875f));

// Combo scaling.
float maxCombo = beatmap.DifficultyAttribute(_mods, Beatmap::MaxCombo);
Expand Down