From 2ee7d1346b218f658f5df8d71cfe739c6dd8d280 Mon Sep 17 00:00:00 2001 From: Arti Kearney Date: Sun, 26 Aug 2018 16:00:01 -0700 Subject: [PATCH] Add "format" display mode, judgments for swing segments --- HitScoreVisualizer/Config.cs | 197 +++++++++++++++++- ...fterCutSwingRatingCounterDidChangeEvent.cs | 2 +- .../FlyingScoreTextEffectInitAndPresent.cs | 2 +- HitScoreVisualizer/Plugin.cs | 6 +- 4 files changed, 191 insertions(+), 16 deletions(-) diff --git a/HitScoreVisualizer/Config.cs b/HitScoreVisualizer/Config.cs index 578de74..5fbfd34 100644 --- a/HitScoreVisualizer/Config.cs +++ b/HitScoreVisualizer/Config.cs @@ -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"": ""Excellent"", + ""text"": ""Excellent%n%s%n%B %C %A"", ""color"": [ 0.0, 1.0, @@ -100,7 +131,7 @@ namespace HitScoreVisualizer }, { ""threshold"": 90, - ""text"": ""Great"", + ""text"": ""Great%n%s%n%B %C %A"", ""color"": [ 1.0, 0.980392158, @@ -110,7 +141,7 @@ namespace HitScoreVisualizer }, { ""threshold"": 80, - ""text"": ""Good"", + ""text"": ""Good%n%s%n%B %C %A"", ""color"": [ 1.0, 0.6, @@ -121,7 +152,7 @@ namespace HitScoreVisualizer }, { ""threshold"": 60, - ""text"": ""Decent"", + ""text"": ""Decent%n%s%n%B %C %A"", ""color"": [ 1.0, 0.0, @@ -131,7 +162,7 @@ namespace HitScoreVisualizer ""fade"": true }, { - ""text"": ""Way Off"", + ""text"": ""Way Off%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(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 ""; + } } } diff --git a/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectHandleSaberAfterCutSwingRatingCounterDidChangeEvent.cs b/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectHandleSaberAfterCutSwingRatingCounterDidChangeEvent.cs index 4a45ec0..37fcec3 100644 --- a/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectHandleSaberAfterCutSwingRatingCounterDidChangeEvent.cs +++ b/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectHandleSaberAfterCutSwingRatingCounterDidChangeEvent.cs @@ -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; } } diff --git a/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectInitAndPresent.cs b/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectInitAndPresent.cs index 92184f0..159fea0 100644 --- a/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectInitAndPresent.cs +++ b/HitScoreVisualizer/Harmony Patches/FlyingScoreTextEffectInitAndPresent.cs @@ -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); } } } diff --git a/HitScoreVisualizer/Plugin.cs b/HitScoreVisualizer/Plugin.cs index 650b301..71e327b 100644 --- a/HitScoreVisualizer/Plugin.cs +++ b/HitScoreVisualizer/Plugin.cs @@ -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() {