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

Port MBMasher's PP changes #142

Merged
merged 2 commits into from
Oct 5, 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
6 changes: 3 additions & 3 deletions include/pp/performance/Beatmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Beatmap
Strain,
HitWindow300,
ScoreMultiplier,
Flashlight,

NumTypes,
};
Expand Down Expand Up @@ -55,7 +56,7 @@ class Beatmap
void SetNumSpinners(s32 numSpinners) { _numSpinners = numSpinners; }
void SetDifficultyAttribute(EMods mods, EDifficultyAttributeType type, f32 value);

static EDifficultyAttributeType DifficultyAttributeFromName(const std::string& difficultyAttributeName)
static EDifficultyAttributeType DifficultyAttributeFromName(const std::string &difficultyAttributeName)
{
return s_difficultyAttributes.at(difficultyAttributeName);
}
Expand All @@ -70,8 +71,7 @@ class Beatmap
// Calculated difficulty
using difficulty_t = std::unordered_map<
std::underlying_type_t<EMods>,
std::array<f32, NumTypes>
>;
std::array<f32, NumTypes>>;

difficulty_t _difficulty;

Expand Down
14 changes: 7 additions & 7 deletions include/pp/performance/osu/OsuScore.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ PP_NAMESPACE_BEGIN
class OsuScore : public Score
{
public:

OsuScore(
s64 scoreId,
EGamemode mode,
Expand All @@ -23,8 +22,7 @@ class OsuScore : public Score
s32 numGeki,
s32 numKatu,
EMods mods,
const Beatmap& beatmap
);
const Beatmap &beatmap);

f32 TotalValue() const override;
f32 Accuracy() const override;
Expand All @@ -35,13 +33,15 @@ class OsuScore : public Score
f32 _aimValue;
f32 _speedValue;
f32 _accValue;
f32 _flashlightValue;

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

void computeAimValue(const Beatmap& beatmap);
void computeSpeedValue(const Beatmap& beatmap);
void computeAccValue(const Beatmap& beatmap);
void computeAimValue(const Beatmap &beatmap);
void computeSpeedValue(const Beatmap &beatmap);
void computeAccValue(const Beatmap &beatmap);
void computeFlashlightValue(const Beatmap &beatmap);
};

PP_NAMESPACE_END
17 changes: 9 additions & 8 deletions src/performance/Beatmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
PP_NAMESPACE_BEGIN

const std::unordered_map<std::string, Beatmap::EDifficultyAttributeType> Beatmap::s_difficultyAttributes{
{"Aim", Aim},
{"Speed", Speed},
{"OD", OD},
{"AR", AR},
{"Max combo", MaxCombo},
{"Strain", Strain},
{"Hit window 300", HitWindow300},
{"Aim", Aim},
{"Speed", Speed},
{"OD", OD},
{"AR", AR},
{"Max combo", MaxCombo},
{"Strain", Strain},
{"Hit window 300", HitWindow300},
{"Score multiplier", ScoreMultiplier},
{"Flashlight", Flashlight},
};

Beatmap::Beatmap(s32 id)
: _id{id}
: _id{id}
{
}

Expand Down
77 changes: 55 additions & 22 deletions src/performance/osu/OsuScore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ OsuScore::OsuScore(
computeAimValue(beatmap);
computeSpeedValue(beatmap);
computeAccValue(beatmap);
computeFlashlightValue(beatmap);

computeTotalValue(beatmap);
}
Expand Down Expand Up @@ -62,7 +63,7 @@ void OsuScore::computeTotalValue(const Beatmap &beatmap)
}

// Custom multipliers for NoFail and SpunOut.
f32 multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
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);
Expand All @@ -75,7 +76,8 @@ void OsuScore::computeTotalValue(const Beatmap &beatmap)
std::pow(
std::pow(_aimValue, 1.1f) +
std::pow(_speedValue, 1.1f) +
std::pow(_accValue, 1.1f),
std::pow(_accValue, 1.1f) +
std::pow(_flashlightValue, 1.1),
1.0f / 1.1f) *
multiplier;
}
Expand All @@ -91,7 +93,7 @@ void OsuScore::computeAimValue(const Beatmap &beatmap)

int numTotalHits = TotalHits();

// Longer maps are worth more
// Longer maps are worth more.
f32 LengthBonus = 0.95f + 0.4f * std::min(1.0f, static_cast<f32>(numTotalHits) / 2000.0f) +
(numTotalHits > 2000 ? log10(static_cast<f32>(numTotalHits) / 2000.0f) * 0.5f : 0.0f);

Expand All @@ -101,7 +103,7 @@ void OsuScore::computeAimValue(const Beatmap &beatmap)
if (_numMiss > 0)
_aimValue *= 0.97f * std::pow(1.0f - std::pow(_numMiss / static_cast<f32>(numTotalHits), 0.775f), _numMiss);

// Combo scaling
// Combo scaling.
float maxCombo = beatmap.DifficultyAttribute(_mods, Beatmap::MaxCombo);
if (maxCombo > 0)
_aimValue *= std::min(static_cast<f32>(pow(_maxCombo, 0.8f) / pow(maxCombo, 0.8f)), 1.0f);
Expand All @@ -121,19 +123,11 @@ void OsuScore::computeAimValue(const Beatmap &beatmap)
if ((_mods & EMods::Hidden) > 0)
_aimValue *= 1.0f + 0.04f * (12.0f - approachRate);

f32 flashlightBonus = 1.0;
if ((_mods & EMods::Flashlight) > 0)
// Apply object-based bonus for flashlight.
flashlightBonus = 1.0f + 0.35f * std::min(1.0f, static_cast<f32>(numTotalHits) / 200.0f) +
(numTotalHits > 200 ? 0.3f * std::min(1.0f, static_cast<f32>(numTotalHits - 200) / 300.0f) +
(numTotalHits > 500 ? static_cast<f32>(numTotalHits - 500) / 1200.0f : 0.0f)
: 0.0f);

_aimValue *= std::max(flashlightBonus, approachRateBonus);
_aimValue *= approachRateBonus;

// Scale the aim value with accuracy _slightly_
// Scale the aim value with accuracy _slightly_.
_aimValue *= 0.5f + Accuracy() / 2.0f;
// It is important to also consider accuracy difficulty when doing that
// It is important to also consider accuracy difficulty when doing that.
_aimValue *= 0.98f + (pow(beatmap.DifficultyAttribute(_mods, Beatmap::OD), 2) / 2500);
}

Expand All @@ -143,7 +137,7 @@ void OsuScore::computeSpeedValue(const Beatmap &beatmap)

int numTotalHits = TotalHits();

// Longer maps are worth more
// Longer maps are worth more.
f32 lengthBonus = 0.95f + 0.4f * std::min(1.0f, static_cast<f32>(numTotalHits) / 2000.0f) +
(numTotalHits > 2000 ? log10(static_cast<f32>(numTotalHits) / 2000.0f) * 0.5f : 0.0f);
_speedValue *= lengthBonus;
Expand All @@ -152,7 +146,7 @@ void OsuScore::computeSpeedValue(const Beatmap &beatmap)
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));

// Combo scaling
// Combo scaling.
float maxCombo = beatmap.DifficultyAttribute(_mods, Beatmap::MaxCombo);
if (maxCombo > 0)
_speedValue *= std::min(static_cast<f32>(pow(_maxCombo, 0.8f) / pow(maxCombo, 0.8f)), 1.0f);
Expand All @@ -170,15 +164,15 @@ void OsuScore::computeSpeedValue(const Beatmap &beatmap)
if ((_mods & EMods::Hidden) > 0)
_speedValue *= 1.0f + 0.04f * (12.0f - approachRate);

// Scale the speed value with accuracy and OD
// Scale the speed value with accuracy and OD.
_speedValue *= (0.95f + std::pow(beatmap.DifficultyAttribute(_mods, Beatmap::OD), 2) / 750) * std::pow(Accuracy(), (14.5f - std::max(beatmap.DifficultyAttribute(_mods, Beatmap::OD), 8.0f)) / 2);
// Scale the speed value with # of 50s to punish doubletapping.
_speedValue *= std::pow(0.98f, _num50 < numTotalHits / 500.0f ? 0.0f : _num50 - numTotalHits / 500.0f);
}

void OsuScore::computeAccValue(const Beatmap &beatmap)
{
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window.
f32 betterAccuracyPercentage;

s32 numHitObjectsWithAccuracy;
Expand All @@ -196,18 +190,18 @@ void OsuScore::computeAccValue(const Beatmap &beatmap)
else
betterAccuracyPercentage = 0;

// It is possible to reach a negative accuracy with this formula. Cap it at zero - zero points
// It is possible to reach a negative accuracy with this formula. Cap it at zero - zero points.
if (betterAccuracyPercentage < 0)
betterAccuracyPercentage = 0;
}

// Lots of arbitrary values from testing.
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution.
_accValue =
pow(1.52163f, beatmap.DifficultyAttribute(_mods, Beatmap::OD)) * pow(betterAccuracyPercentage, 24) *
2.83f;

// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer.
_accValue *= std::min(1.15f, static_cast<f32>(pow(numHitObjectsWithAccuracy / 1000.0f, 0.3f)));

if ((_mods & EMods::Hidden) > 0)
Expand All @@ -217,4 +211,43 @@ void OsuScore::computeAccValue(const Beatmap &beatmap)
_accValue *= 1.02f;
}

void OsuScore::computeFlashlightValue(const Beatmap &beatmap)
{
_flashlightValue = 0.0f;

if ((_mods & EMods::Flashlight) == 0)
return;

f32 rawFlashlight = beatmap.DifficultyAttribute(_mods, Beatmap::Flashlight);

if ((_mods & EMods::TouchDevice) > 0)
rawFlashlight = std::pow(rawFlashlight, 0.8f);

_flashlightValue = std::pow(rawFlashlight, 2.0f) * 25.0f;

// Add an additional bonus for HDFL.
if ((_mods & EMods::Hidden) > 0)
_flashlightValue *= 1.3f;

int numTotalHits = TotalHits();

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

// Combo scaling.
float maxCombo = beatmap.DifficultyAttribute(_mods, Beatmap::MaxCombo);
if (maxCombo > 0)
_flashlightValue *= std::min(static_cast<f32>(pow(_maxCombo, 0.8f) / pow(maxCombo, 0.8f)), 1.0f);

// Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius.
_flashlightValue *= 0.7f + 0.1f * std::min(1.0f, static_cast<f32>(numTotalHits) / 200.0f) +
(numTotalHits > 200 ? 0.2f * std::min(1.0f, (static_cast<f32>(numTotalHits) - 200) / 200.0f) : 0.0f);

// Scale the flashlight value with accuracy _slightly_.
_flashlightValue *= 0.5f + Accuracy() / 2.0f;
// It is important to also consider accuracy difficulty when doing that.
_flashlightValue *= 0.98f + std::pow(beatmap.DifficultyAttribute(_mods, Beatmap::OD), 2.0f) / 2500.0f;
}

PP_NAMESPACE_END