mirror of
https://github.com/Theaninova/HitScoreVisualizer.git
synced 2025-12-12 19:46:17 +00:00
Add "format" display mode, judgments for swing segments
This commit is contained in:
@@ -43,6 +43,17 @@ namespace HitScoreVisualizer
|
||||
public bool fade;
|
||||
}
|
||||
|
||||
// Judgments for individual parts of the swing (angle before, angle after, accuracy).
|
||||
public struct SegmentJudgment
|
||||
{
|
||||
// This judgment will be applied only when the appropriate part of the swing contributes score >= this number.
|
||||
// If no judgment can be applied, the judgment for this segment will be "" (the empty string).
|
||||
[DefaultValue(0)]
|
||||
public int threshold;
|
||||
// The text to replace the appropriate judgment specifier with (%B, %C, %A) when this judgment applies.
|
||||
public string text;
|
||||
}
|
||||
|
||||
// If the version number (excluding patch version) of the config is higher than that of the plugin,
|
||||
// the config will not be loaded. If the version number of the config is lower than that of the
|
||||
// plugin, the file will be automatically converted. Conversion is not guaranteed to occur, or be
|
||||
@@ -58,6 +69,15 @@ namespace HitScoreVisualizer
|
||||
// update rather than being converted.
|
||||
public bool isDefaultConfig;
|
||||
|
||||
// If set to "format", displays the judgment text, with the following format specifiers allowed:
|
||||
// - %b: The score contributed by the part of the swing before cutting the block.
|
||||
// - %c: The score contributed by the accuracy of the cut.
|
||||
// - %a: The score contributed by the part of the swing after cutting the block.
|
||||
// - %B, %C, %A: As above, except using the appropriate judgment from that part of the swing (as configured for "beforeCutAngleJudgments", "accuracyJudgments", or "afterCutAngleJudgments").
|
||||
// - %s: The total score for the cut.
|
||||
// - %%: A literal percent symbol.
|
||||
// - %n: A newline.
|
||||
//
|
||||
// If set to "numeric", displays only the note score.
|
||||
// If set to "textOnly", displays only the judgment text.
|
||||
// If set to "scoreOnTop", displays both (numeric score above judgment text).
|
||||
@@ -68,19 +88,30 @@ namespace HitScoreVisualizer
|
||||
// Order from highest threshold to lowest; the first matching judgment will be applied
|
||||
public Judgment[] judgments;
|
||||
|
||||
// Judgments for the part of the swing before cutting the block (score is from 0-70).
|
||||
// Format specifier: %B
|
||||
public SegmentJudgment[] beforeCutAngleJudgments;
|
||||
|
||||
// Judgments for the accuracy of the cut (how close to the center of the block the cut was, score is from 0-10).
|
||||
// Format specifier: %C
|
||||
public SegmentJudgment[] accuracyJudgments;
|
||||
|
||||
// Judgments for the part of the swing after cutting the block (score is from 0-30).
|
||||
// Format specifier: %A
|
||||
public SegmentJudgment[] afterCutAngleJudgments;
|
||||
|
||||
// path to where the config is saved
|
||||
private const string FILE_PATH = "/UserData/HitScoreVisualizerConfig.json";
|
||||
|
||||
private const string DEFAULT_JSON = @"{
|
||||
""majorVersion"": 2,
|
||||
""minorVersion"": 0,
|
||||
""patchVersion"": 2,
|
||||
""isDefaultConfig"": true,
|
||||
""displayMode"": ""textOnTop"",
|
||||
""minorVersion"": 1,
|
||||
""patchVersion"": 0,
|
||||
""displayMode"": ""format"",
|
||||
""judgments"": [
|
||||
{
|
||||
""threshold"": 110,
|
||||
""text"": ""Fantastic"",
|
||||
""text"": ""Fantastic%n%s%n%B %C %A"",
|
||||
""color"": [
|
||||
1.0,
|
||||
1.0,
|
||||
@@ -90,7 +121,7 @@ namespace HitScoreVisualizer
|
||||
},
|
||||
{
|
||||
""threshold"": 101,
|
||||
""text"": ""<size=80%>Excellent</size>"",
|
||||
""text"": ""<size=80%>Excellent</size>%n%s%n%B %C %A"",
|
||||
""color"": [
|
||||
0.0,
|
||||
1.0,
|
||||
@@ -100,7 +131,7 @@ namespace HitScoreVisualizer
|
||||
},
|
||||
{
|
||||
""threshold"": 90,
|
||||
""text"": ""<size=80%>Great</size>"",
|
||||
""text"": ""<size=80%>Great</size>%n%s%n%B %C %A"",
|
||||
""color"": [
|
||||
1.0,
|
||||
0.980392158,
|
||||
@@ -110,7 +141,7 @@ namespace HitScoreVisualizer
|
||||
},
|
||||
{
|
||||
""threshold"": 80,
|
||||
""text"": ""<size=80%>Good</size>"",
|
||||
""text"": ""<size=80%>Good</size>%n%s%n%B %C %A"",
|
||||
""color"": [
|
||||
1.0,
|
||||
0.6,
|
||||
@@ -121,7 +152,7 @@ namespace HitScoreVisualizer
|
||||
},
|
||||
{
|
||||
""threshold"": 60,
|
||||
""text"": ""<size=80%>Decent</size>"",
|
||||
""text"": ""<size=80%>Decent</size>%n%s%n%B %C %A"",
|
||||
""color"": [
|
||||
1.0,
|
||||
0.0,
|
||||
@@ -131,7 +162,7 @@ namespace HitScoreVisualizer
|
||||
""fade"": true
|
||||
},
|
||||
{
|
||||
""text"": ""<size=80%>Way Off</size>"",
|
||||
""text"": ""<size=80%>Way Off</size>%n%s%n%B %C %A"",
|
||||
""color"": [
|
||||
0.5,
|
||||
0.0,
|
||||
@@ -140,6 +171,48 @@ namespace HitScoreVisualizer
|
||||
],
|
||||
""fade"": true
|
||||
}
|
||||
],
|
||||
""beforeCutAngleJudgments"": [
|
||||
{
|
||||
""threshold"": 70,
|
||||
""text"": ""+""
|
||||
},
|
||||
{
|
||||
""threshold"": 35,
|
||||
""text"": "" ""
|
||||
},
|
||||
{
|
||||
""threshold"": 0,
|
||||
""text"": ""-""
|
||||
}
|
||||
],
|
||||
""accuracyJudgments"": [
|
||||
{
|
||||
""threshold"": 10,
|
||||
""text"": ""+""
|
||||
},
|
||||
{
|
||||
""threshold"": 5,
|
||||
""text"": "" ""
|
||||
},
|
||||
{
|
||||
""threshold"": 0,
|
||||
""text"": ""-""
|
||||
}
|
||||
],
|
||||
""afterCutAngleJudgments"": [
|
||||
{
|
||||
""threshold"": 30,
|
||||
""text"": ""+""
|
||||
},
|
||||
{
|
||||
""threshold"": 15,
|
||||
""text"": "" ""
|
||||
},
|
||||
{
|
||||
""threshold"": 0,
|
||||
""text"": ""-""
|
||||
}
|
||||
]
|
||||
}";
|
||||
public static readonly Config DEFAULT_CONFIG = JsonConvert.DeserializeObject<Config>(DEFAULT_JSON,
|
||||
@@ -153,6 +226,12 @@ namespace HitScoreVisualizer
|
||||
fade = false
|
||||
};
|
||||
|
||||
public static readonly SegmentJudgment DEFAULT_SEGMENT_JUDGMENT = new SegmentJudgment
|
||||
{
|
||||
threshold = 0,
|
||||
text = ""
|
||||
};
|
||||
|
||||
public static string fullPath => Environment.CurrentDirectory.Replace('\\', '/') + FILE_PATH;
|
||||
|
||||
public static void load()
|
||||
@@ -180,7 +259,25 @@ namespace HitScoreVisualizer
|
||||
}
|
||||
if (outdated(loaded))
|
||||
{
|
||||
if (loaded.isDefaultConfig)
|
||||
{
|
||||
loaded = DEFAULT_CONFIG;
|
||||
instance = loaded;
|
||||
save();
|
||||
return;
|
||||
}
|
||||
// put config update logic here
|
||||
if (loaded.majorVersion == 2 && loaded.minorVersion == 0)
|
||||
{
|
||||
loaded.beforeCutAngleJudgments = new SegmentJudgment[] { DEFAULT_SEGMENT_JUDGMENT };
|
||||
loaded.accuracyJudgments = new SegmentJudgment[] { DEFAULT_SEGMENT_JUDGMENT };
|
||||
loaded.afterCutAngleJudgments = new SegmentJudgment[] { DEFAULT_SEGMENT_JUDGMENT };
|
||||
loaded.minorVersion = 1;
|
||||
loaded.patchVersion = 0;
|
||||
instance = loaded;
|
||||
save();
|
||||
return;
|
||||
}
|
||||
}
|
||||
instance = loaded;
|
||||
}
|
||||
@@ -242,7 +339,7 @@ namespace HitScoreVisualizer
|
||||
instance = DEFAULT_CONFIG;
|
||||
}
|
||||
|
||||
public static void judge(FlyingScoreTextEffect text, ref Color color, int score)
|
||||
public static void judge(FlyingScoreTextEffect text, NoteCutInfo noteCutInfo, SaberAfterCutSwingRatingCounter saberAfterCutSwingRatingCounter, ref Color color, int score)
|
||||
{
|
||||
Judgment judgment = DEFAULT_JUDGMENT;
|
||||
int index; // save in case we need to fade
|
||||
@@ -268,6 +365,74 @@ namespace HitScoreVisualizer
|
||||
color = toColor(judgment.color);
|
||||
}
|
||||
|
||||
if (instance.displayMode == "format")
|
||||
{
|
||||
int beforeCutScore, accuracyScore, afterCutScore;
|
||||
|
||||
beforeCutScore = Mathf.RoundToInt(70f * noteCutInfo.swingRating);
|
||||
float accuracy = 1f - Mathf.Clamp01(noteCutInfo.cutDistanceToCenter / 0.2f);
|
||||
accuracyScore = Mathf.RoundToInt(10f * accuracy);
|
||||
afterCutScore = 0;
|
||||
if (saberAfterCutSwingRatingCounter != null)
|
||||
{
|
||||
afterCutScore = Mathf.RoundToInt(30f * saberAfterCutSwingRatingCounter.rating);
|
||||
}
|
||||
|
||||
StringBuilder formattedBuilder = new StringBuilder();
|
||||
string formatString = judgment.text;
|
||||
int nextPercentIndex = formatString.IndexOf('%');
|
||||
while (nextPercentIndex != -1)
|
||||
{
|
||||
formattedBuilder.Append(formatString.Substring(0, nextPercentIndex));
|
||||
if (formatString.Length == nextPercentIndex + 1)
|
||||
{
|
||||
formatString += " ";
|
||||
}
|
||||
char specifier = formatString[nextPercentIndex + 1];
|
||||
|
||||
switch (specifier)
|
||||
{
|
||||
case 'b':
|
||||
formattedBuilder.Append(beforeCutScore);
|
||||
break;
|
||||
case 'c':
|
||||
formattedBuilder.Append(accuracyScore);
|
||||
break;
|
||||
case 'a':
|
||||
formattedBuilder.Append(afterCutScore);
|
||||
break;
|
||||
case 'B':
|
||||
formattedBuilder.Append(judgeSegment(beforeCutScore, instance.beforeCutAngleJudgments));
|
||||
break;
|
||||
case 'C':
|
||||
formattedBuilder.Append(judgeSegment(accuracyScore, instance.accuracyJudgments));
|
||||
break;
|
||||
case 'A':
|
||||
formattedBuilder.Append(judgeSegment(afterCutScore, instance.afterCutAngleJudgments));
|
||||
break;
|
||||
case 's':
|
||||
formattedBuilder.Append(score);
|
||||
break;
|
||||
case '%':
|
||||
formattedBuilder.Append("%");
|
||||
break;
|
||||
case 'n':
|
||||
formattedBuilder.Append("\n");
|
||||
break;
|
||||
default:
|
||||
formattedBuilder.Append("%" + specifier);
|
||||
break;
|
||||
}
|
||||
|
||||
formatString = formatString.Remove(0, nextPercentIndex + 2);
|
||||
nextPercentIndex = formatString.IndexOf('%');
|
||||
}
|
||||
formattedBuilder.Append(formatString);
|
||||
|
||||
text.text = formattedBuilder.ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance.displayMode == "textOnly")
|
||||
{
|
||||
text.text = judgment.text;
|
||||
@@ -289,5 +454,15 @@ namespace HitScoreVisualizer
|
||||
{
|
||||
return new Color(rgba[0], rgba[1], rgba[2], rgba[3]);
|
||||
}
|
||||
|
||||
public static string judgeSegment(int scoreForSegment, SegmentJudgment[] judgments)
|
||||
{
|
||||
if (judgments == null) return "";
|
||||
foreach(SegmentJudgment j in judgments)
|
||||
{
|
||||
if (scoreForSegment >= j.threshold) return j.text;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace HitScoreVisualizer.Harmony_Patches
|
||||
{
|
||||
ScoreController.ScoreWithoutMultiplier(____noteCutInfo, afterCutRating, out int before, out int after);
|
||||
int total = before + after;
|
||||
Config.judge(__instance, ref ____color, total);
|
||||
Config.judge(__instance, ____noteCutInfo, afterCutRating, ref ____color, total);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace HitScoreVisualizer.Harmony_Patches
|
||||
{
|
||||
ScoreController.ScoreWithoutMultiplier(noteCutInfo, saberAfterCutSwingRatingCounter, out int before, out int after);
|
||||
int total = before + after;
|
||||
Config.judge(__instance, ref ____color, total);
|
||||
Config.judge(__instance, noteCutInfo, saberAfterCutSwingRatingCounter, ref ____color, total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ namespace HitScoreVisualizer
|
||||
public class Plugin : IPlugin
|
||||
{
|
||||
public string Name => "HitScoreVisualizer";
|
||||
public string Version => "2.0.2";
|
||||
public string Version => "2.1.0";
|
||||
|
||||
internal const int majorVersion = 2;
|
||||
internal const int minorVersion = 0;
|
||||
internal const int patchVersion = 2;
|
||||
internal const int minorVersion = 1;
|
||||
internal const int patchVersion = 0;
|
||||
|
||||
public void OnApplicationStart()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user