diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
index 388858a337..2193184355 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
@@ -1,5 +1,4 @@
using System;
-using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
@@ -67,16 +66,5 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
}
}
}
-
- public static double EvaluateDifficultyOf(DifficultyHitObject current)
- {
- TaikoDifficultyHitObject? taikoObject = current as TaikoDifficultyHitObject;
- if (taikoObject != null && taikoObject.Colour != null)
- {
- return taikoObject.Colour.EvaluatedDifficulty;
- }
-
- return 0;
- }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
index 6889f0f5e9..e47e131350 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
@@ -16,8 +16,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
/// The interval between the current and previous note hit using the same key.
private static double speedBonus(double interval)
{
+ // Cap to 300bpm 1/4, 50ms note interval, 100ms key interval
+ // This is a temporary measure to prevent absurdly high speed mono convert maps being rated too high
+ // There is a plan to replace this with detecting mono that can be hit by special techniques, and this will
+ // be removed when that is implemented.
+ interval = Math.Max(interval, 100);
+
// return 15 / Math.Pow(interval, 0.6);
- return Math.Pow(0.2, interval / 1000);
+ // return Math.Pow(0.2, interval / 1000);
+ return 30 / interval;
}
///
@@ -41,8 +48,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
return 0.0;
}
- double objectStrain = 1;
- objectStrain *= speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime);
+ double objectStrain = 0.5; // Add a base strain to all objects
+ // double objectStrain = 0;
+ objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime);
return objectStrain;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs
index 18f9d4cf7d..052af7a2d1 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs
@@ -1,43 +1,38 @@
using System.Collections.Generic;
-using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
{
+ ///
+ /// Encodes a list of s.
+ /// s with the same are grouped together.
+ ///
public class ColourEncoding
{
+ ///
+ /// s that are grouped together within this .
+ ///
public List Payload { get; private set; } = new List();
+ ///
+ /// Determine if this is a repetition of another . This
+ /// is a strict comparison and is true if and only if the colour sequence is exactly the same.
+ /// This does not require the s to have the same amount of s.
+ ///
public bool isRepetitionOf(ColourEncoding other)
{
return hasIdenticalMonoLength(other) &&
other.Payload.Count == Payload.Count &&
- other.Payload[0].EncodedData[0].HitType == Payload[0].EncodedData[0].HitType;
+ (other.Payload[0].EncodedData[0].BaseObject as Hit)?.Type ==
+ (Payload[0].EncodedData[0].BaseObject as Hit)?.Type;
}
+ ///
+ /// Determine if this has the same mono length of another .
+ ///
public bool hasIdenticalMonoLength(ColourEncoding other)
{
return other.Payload[0].RunLength == Payload[0].RunLength;
}
-
- public static List Encode(List data)
- {
- // Compute encoding lengths
- List encoded = new List();
- ColourEncoding? lastEncoded = null;
- for (int i = 0; i < data.Count; i++)
- {
- if (i == 0 || lastEncoded == null || data[i].RunLength != data[i - 1].RunLength)
- {
- lastEncoded = new ColourEncoding();
- lastEncoded.Payload.Add(data[i]);
- encoded.Add(lastEncoded);
- continue;
- }
-
- lastEncoded.Payload.Add(data[i]);
- }
-
- return encoded;
- }
}
}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs
index 83fd75efa0..85a5f14a5d 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs
@@ -1,78 +1,35 @@
using System;
using System.Collections.Generic;
-using osu.Game.Rulesets.Difficulty.Preprocessing;
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
{
+ ///
+ /// Encodes a list of s, grouped together by back and forth repetition of the same
+ /// . Also stores the repetition interval between this and the previous .
+ ///
public class CoupledColourEncoding
{
+ ///
+ /// Maximum amount of s to look back to find a repetition.
+ ///
private const int max_repetition_interval = 16;
+ ///
+ /// The s that are grouped together within this .
+ ///
public List Payload = new List();
- public CoupledColourEncoding? Previous { get; private set; } = null;
+ ///
+ /// The previous . This is used to determine the repetition interval.
+ ///
+ public CoupledColourEncoding? Previous = null;
///
- /// How many notes between the current and previous identical .
- /// Negative number means that there is no repetition in range.
+ /// How many between the current and previous identical .
/// If no repetition is found this will have a value of + 1.
///
public int RepetitionInterval { get; private set; } = max_repetition_interval + 1;
- public static List Encode(List data)
- {
- List firstPass = MonoEncoding.Encode(data);
- List secondPass = ColourEncoding.Encode(firstPass);
- List thirdPass = CoupledColourEncoding.Encode(secondPass);
-
- return thirdPass;
- }
-
- public static List Encode(List data)
- {
- List encoded = new List();
-
- CoupledColourEncoding? lastEncoded = null;
- for (int i = 0; i < data.Count; i++)
- {
- lastEncoded = new CoupledColourEncoding()
- {
- Previous = lastEncoded
- };
-
- bool isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]);
- if (!isCoupled)
- {
- lastEncoded.Payload.Add(data[i]);
- }
- else
- {
- while (isCoupled)
- {
- lastEncoded.Payload.Add(data[i]);
- i++;
-
- isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]);
- }
-
- // Skip over peeked data and add the rest to the payload
- lastEncoded.Payload.Add(data[i]);
- lastEncoded.Payload.Add(data[i + 1]);
- i++;
- }
-
- encoded.Add(lastEncoded);
- }
-
- // Final pass to find repetition interval
- for (int i = 0; i < encoded.Count; i++)
- {
- encoded[i].FindRepetitionInterval();
- }
-
- return encoded;
- }
-
///
/// Returns true if other is considered a repetition of this encoding. This is true if other's first two payload
/// identical mono lengths.
@@ -90,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
}
///
- /// Finds the closest previous that has the identical .
+ /// Finds the closest previous that has the identical .
/// Interval is defined as the amount of chunks between the current and repeated encoding.
///
public void FindRepetitionInterval()
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs
index 92cdb0667b..98d66f0aa2 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs
@@ -1,40 +1,22 @@
using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Taiko.Objects;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
{
+ ///
+ /// Encode colour information for a sequence of s. Consecutive s
+ /// of the same are encoded within the same .
+ ///
public class MonoEncoding
{
+ ///
+ /// List of s that are encoded within this .
+ /// This is not declared as to avoid circular dependencies.
+ /// TODO: Review this, are circular dependencies within data-only classes are acceptable?
+ ///
public List EncodedData { get; private set; } = new List();
public int RunLength => EncodedData.Count;
-
- public static List Encode(List data)
- {
- List encoded = new List();
-
- MonoEncoding? lastEncoded = null;
- for (int i = 0; i < data.Count; i++)
- {
- TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i];
- // This ignores all non-note objects, which may or may not be the desired behaviour
- TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0);
-
- if (
- previousObject == null ||
- lastEncoded == null ||
- taikoObject.HitType != previousObject.HitType)
- {
- lastEncoded = new MonoEncoding();
- lastEncoded.EncodedData.Add(taikoObject);
- encoded.Add(lastEncoded);
- continue;
- }
-
- lastEncoded.EncodedData.Add(taikoObject);
- }
-
- return encoded;
- }
}
}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs
new file mode 100644
index 0000000000..17337281e2
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs
@@ -0,0 +1,170 @@
+using System.Collections.Generic;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
+using osu.Game.Rulesets.Taiko.Objects;
+
+namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
+{
+ ///
+ /// Utility class to perform various encodings. This is separated out from the encoding classes to prevent circular
+ /// dependencies.
+ ///
+ public class TaikoColourDifficultyPreprocessor
+ {
+ ///
+ /// Process and encode a list of s into a list of s,
+ /// assign the appropriate s to each ,
+ /// and preevaluate colour difficulty of each .
+ ///
+ public static List ProcessAndAssign(List hitObjects)
+ {
+ List colours = new List();
+ List encodings = Encode(hitObjects);
+
+ // Assign colour to objects
+ encodings.ForEach(coupledEncoding =>
+ {
+ coupledEncoding.Payload.ForEach(encoding =>
+ {
+ encoding.Payload.ForEach(mono =>
+ {
+ mono.EncodedData.ForEach(hitObject =>
+ {
+ hitObject.Colour = new TaikoDifficultyHitObjectColour(coupledEncoding);
+ });
+ });
+ });
+
+ // Preevaluate and assign difficulty values
+ ColourEvaluator.PreEvaluateDifficulties(coupledEncoding);
+ });
+
+ return colours;
+ }
+
+ ///
+ /// Encodes a list of s into a list of s.
+ ///
+ public static List EncodeMono(List data)
+ {
+ List encoded = new List();
+
+ MonoEncoding? lastEncoded = null;
+ for (int i = 0; i < data.Count; i++)
+ {
+ TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i];
+ // This ignores all non-note objects, which may or may not be the desired behaviour
+ TaikoDifficultyHitObject previousObject = taikoObject.PreviousNote(0);
+
+ // If the colour changed, or if this is the first object in the run, create a new mono encoding
+ if (
+ previousObject == null || // First object in the list
+ (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type)
+ {
+ lastEncoded = new MonoEncoding();
+ lastEncoded.EncodedData.Add(taikoObject);
+ encoded.Add(lastEncoded);
+ continue;
+ }
+
+ // If we're here, we're in the same encoding as the previous object, thus lastEncoded is not null. Add
+ // the current object to the encoded payload.
+ lastEncoded!.EncodedData.Add(taikoObject);
+ }
+
+ return encoded;
+ }
+
+ ///
+ /// Encodes a list of s into a list of s.
+ ///
+ public static List EncodeColour(List data)
+ {
+ List encoded = new List();
+ ColourEncoding? lastEncoded = null;
+ for (int i = 0; i < data.Count; i++)
+ {
+ // Starts a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is
+ // the first MonoEncoding in the list.
+ if (lastEncoded == null || data[i].RunLength != data[i - 1].RunLength)
+ {
+ lastEncoded = new ColourEncoding();
+ lastEncoded.Payload.Add(data[i]);
+ encoded.Add(lastEncoded);
+ continue;
+ }
+
+ // If we're here, we're in the same encoding as the previous object. Add the current MonoEncoding to the
+ // encoded payload.
+ lastEncoded.Payload.Add(data[i]);
+ }
+
+ return encoded;
+ }
+
+ ///
+ /// Encodes a list of s into a list of s.
+ ///
+ public static List Encode(List data)
+ {
+ List firstPass = EncodeMono(data);
+ List secondPass = EncodeColour(firstPass);
+ List thirdPass = EncodeCoupledColour(secondPass);
+
+ return thirdPass;
+ }
+
+ ///
+ /// Encodes a list of s into a list of s.
+ ///
+ public static List EncodeCoupledColour(List data)
+ {
+ List encoded = new List();
+ CoupledColourEncoding? lastEncoded = null;
+ for (int i = 0; i < data.Count; i++)
+ {
+ // Starts a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled
+ // later within this loop.
+ lastEncoded = new CoupledColourEncoding()
+ {
+ Previous = lastEncoded
+ };
+
+ // Determine if future ColourEncodings should be grouped.
+ bool isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]);
+ if (!isCoupled)
+ {
+ // If not, add the current ColourEncoding to the encoded payload and continue.
+ lastEncoded.Payload.Add(data[i]);
+ }
+ else
+ {
+ // If so, add the current ColourEncoding to the encoded payload and start repeatedly checking if
+ // subsequent ColourEncodings should be grouped by increasing i and doing the appropriate isCoupled
+ // check;
+ while (isCoupled)
+ {
+ lastEncoded.Payload.Add(data[i]);
+ i++;
+ isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]);
+ }
+
+ // Skip over peeked data and add the rest to the payload
+ lastEncoded.Payload.Add(data[i]);
+ lastEncoded.Payload.Add(data[i + 1]);
+ i++;
+ }
+
+ encoded.Add(lastEncoded);
+ }
+
+ // Final pass to find repetition intervals
+ for (int i = 0; i < encoded.Count; i++)
+ {
+ encoded[i].FindRepetitionInterval();
+ }
+
+ return encoded;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs
index 7dfd0fdbd4..9c2e0cc206 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs
@@ -1,8 +1,3 @@
-using System;
-using System.Collections.Generic;
-using osu.Game.Rulesets.Difficulty.Preprocessing;
-using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
-
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
{
///
@@ -15,36 +10,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour
public double EvaluatedDifficulty = 0;
- private TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding)
+ public TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding)
{
Encoding = encoding;
}
-
- // TODO: Might wanna move this somewhere else as it is introducing circular references
- public static List EncodeAndAssign(List hitObjects)
- {
- List colours = new List();
- List encodings = CoupledColourEncoding.Encode(hitObjects);
-
- // Assign colour to objects
- encodings.ForEach(coupledEncoding =>
- {
- coupledEncoding.Payload.ForEach(encoding =>
- {
- encoding.Payload.ForEach(mono =>
- {
- mono.EncodedData.ForEach(hitObject =>
- {
- hitObject.Colour = new TaikoDifficultyHitObjectColour(coupledEncoding);
- });
- });
- });
-
- // Preevaluate and assign difficulty values
- ColourEvaluator.PreEvaluateDifficulties(coupledEncoding);
- });
-
- return colours;
- }
}
}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs
index 919770afc8..e490d310fd 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs
@@ -4,12 +4,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
-using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
{
@@ -35,40 +33,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
///
public TaikoDifficultyHitObjectColour? Colour;
- ///
- /// The hit type of this hit object.
- ///
- public readonly HitType? HitType;
-
- ///
- /// Creates a list of s from a s.
- /// TODO: Review this - this is moved here from TaikoDifficultyCalculator so that TaikoDifficultyCalculator can
- /// have less knowledge of implementation details (i.e. creating all the different hitObject lists, and
- /// calling FindRepetitionInterval for the final object). The down side of this is
- /// TaikoDifficultyHitObejct.CreateDifficultyHitObjects is now pretty much a proxy for this.
- ///
- /// The beatmap from which the list of is created.
- /// The rate at which the gameplay clock is run at.
- public static List Create(IBeatmap beatmap, double clockRate)
- {
- List difficultyHitObjects = new List();
- List centreObjects = new List();
- List rimObjects = new List();
- List noteObjects = new List();
-
- for (int i = 2; i < beatmap.HitObjects.Count; i++)
- {
- difficultyHitObjects.Add(
- new TaikoDifficultyHitObject(
- beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects,
- centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count)
- );
- }
- var encoded = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects);
-
- return difficultyHitObjects;
- }
-
///
/// Creates a new difficulty hit object.
///
@@ -81,10 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
/// The list of rim (kat) s in the current beatmap.
/// The list of s that is a hit (i.e. not a slider or spinner) in the current beatmap.
/// The position of this in the list.
- ///
- /// TODO: This argument list is getting long, we might want to refactor this into a static method that create
- /// all s from a .
- private TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate,
+ public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate,
List objects,
List centreHitObjects,
List rimHitObjects,
@@ -95,15 +56,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
this.noteObjects = noteObjects;
Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate);
- HitType = currentHit?.Type;
+ HitType? hitType = currentHit?.Type;
- if (HitType == Objects.HitType.Centre)
+ if (hitType == Objects.HitType.Centre)
{
MonoIndex = centreHitObjects.Count;
centreHitObjects.Add(this);
monoDifficultyHitObjects = centreHitObjects;
}
- else if (HitType == Objects.HitType.Rim)
+ else if (hitType == Objects.HitType.Rim)
{
MonoIndex = rimHitObjects.Count;
rimHitObjects.Add(this);
@@ -111,7 +72,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
}
// Need to be done after HitType is set.
- if (HitType == null) return;
+ if (hitType == null) return;
NoteIndex = noteObjects.Count;
noteObjects.Add(this);
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs
new file mode 100644
index 0000000000..e37690d7e8
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
+
+namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
+{
+ public class TaikoDifficultyPreprocessor
+ {
+ ///
+ /// Creates a list of s from a s.
+ /// This is placed here in a separate class to avoid having to know
+ /// too much implementation details of the preprocessing, and avoid
+ /// having circular dependencies with various preprocessing and evaluator classes.
+ ///
+ /// The beatmap from which the list of is created.
+ /// The rate at which the gameplay clock is run at.
+ public static List CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
+ {
+ List difficultyHitObjects = new List();
+ List centreObjects = new List();
+ List rimObjects = new List();
+ List noteObjects = new List();
+
+ for (int i = 2; i < beatmap.HitObjects.Count; i++)
+ {
+ difficultyHitObjects.Add(
+ new TaikoDifficultyHitObject(
+ beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects,
+ centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count)
+ );
+ }
+ var encoded = TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects);
+
+ return difficultyHitObjects;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
index d8f445f37c..e2147fdd85 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
@@ -2,10 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Collections.Generic;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
+using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
@@ -15,16 +17,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
public class Colour : StrainDecaySkill
{
protected override double SkillMultiplier => 0.12;
- protected override double StrainDecayBase => 0.8;
- ///
- /// Applies a speed bonus dependent on the time since the last hit.
- ///
- /// The interval between the current and previous note hit using the same key.
- private static double speedBonus(double interval)
- {
- return Math.Pow(0.4, interval / 1000);
- }
+ // This is set to decay slower than other skills, due to the fact that only the first note of each Mono/Colour/Coupled
+ // encoding having any difficulty values, and we want to allow colour difficulty to be able to build up even on
+ // slower maps.
+ protected override double StrainDecayBase => 0.8;
public Colour(Mod[] mods)
: base(mods)
@@ -33,38 +30,37 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
protected override double StrainValueOf(DifficultyHitObject current)
{
- double difficulty = ColourEvaluator.EvaluateDifficultyOf(current);
+ double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0;
return difficulty;
}
// TODO: Remove before pr
- // public static String GetDebugHeaderLabels()
- // {
- // return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)";
- // }
+ public static String GetDebugHeaderLabels()
+ {
+ return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)";
+ }
- // // TODO: Remove before pr
- // public string GetDebugString(DifficultyHitObject current)
- // {
- // double difficulty = ColourEvaluator.EvaluateDifficultyOf(current);
- // difficulty *= speedBonus(current.DeltaTime);
- // TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current;
- // TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour;
- // if (taikoCurrent != null && colour != null)
- // {
- // List payload = colour.Encoding.Payload;
- // string payloadDisplay = "";
- // for (int i = 0; i < payload.Count; ++i)
- // {
- // payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})";
- // }
+ // TODO: Remove before pr
+ public string GetDebugString(DifficultyHitObject current)
+ {
+ double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0;
+ TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current;
+ TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour;
+ if (taikoCurrent != null && colour != null)
+ {
+ List payload = colour.Encoding.Payload;
+ string payloadDisplay = "";
+ for (int i = 0; i < payload.Count; ++i)
+ {
+ payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})";
+ }
- // return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}";
- // }
- // else
- // {
- // return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0";
- // }
- // }
+ return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}";
+ }
+ else
+ {
+ return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0";
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs
index 09d9720a4f..18200fe1bb 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs
@@ -26,8 +26,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier;
// TODO: remove before pr
- // private StreamWriter? colourDebugOutput;
- // bool debugColour = false;
+ private StreamWriter? colourDebugOutput;
+ bool debugColour = false;
+ private StreamWriter? strainPeakDebugOutput;
+ bool debugStrain = false;
public Peaks(Mod[] mods, IBeatmap beatmap)
: base(mods)
@@ -36,14 +38,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
colour = new Colour(mods);
stamina = new Stamina(mods);
- // if (debugColour)
- // {
- // String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv";
- // filename = filename.Replace('/', '_');
- // colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}"));
- // colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels());
- // }
-
+ if (debugColour)
+ {
+ String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv";
+ filename = filename.Replace('/', '_');
+ colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}"));
+ colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels());
+ }
+ if (debugStrain)
+ {
+ String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv";
+ filename = filename.Replace('/', '_');
+ strainPeakDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/strain-debug/{filename}"));
+ strainPeakDebugOutput.WriteLine("Colour,Stamina,Rhythm,Combined");
+ }
}
///
@@ -90,6 +98,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
double peak = norm(1.5, colourPeak, staminaPeak);
peak = norm(2, peak, rhythmPeak);
+ if (debugStrain && strainPeakDebugOutput != null)
+ {
+ strainPeakDebugOutput.WriteLine($"{colourPeak},{staminaPeak},{rhythmPeak},{peak}");
+ }
+
// Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
// These sections will not contribute to the difficulty.
if (peak > 0)
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
index 2982861e0b..195ec92835 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
{
- return TaikoDifficultyHitObject.Create(beatmap, clockRate);
+ return TaikoDifficultyPreprocessor.CreateDifficultyHitObjects(beatmap, clockRate);
}
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)