using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BaboonAPI.Hooks.Tracks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HighscoreAccuracy.Enums;
using Microsoft.CodeAnalysis;
using Microsoft.FSharp.Core;
using Newtonsoft.Json;
using TMPro;
using TrombLoader.CustomTracks;
using TrombLoader.Helpers;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("HighscoreAccuracy")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0+f2ffb1a87524a6244d678f04b2393c064b8bafb5")]
[assembly: AssemblyProduct("Highscore Accuracy")]
[assembly: AssemblyTitle("HighscoreAccuracy")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace HighscoreAccuracy
{
public static class FileHelper
{
public static readonly string FILE_PATH_TOOTTALLY_APPDATA = Path.Combine(Application.persistentDataPath, "TootTally");
public static T LoadFromTootTallyAppData<T>(string fileName)
{
string text = Path.Combine(FILE_PATH_TOOTTALLY_APPDATA, fileName);
if (!File.Exists(text))
{
Plugin.Log.LogError((object)("File " + text + " doesnt exist."));
return default(T);
}
try
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(text));
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Couldn't deserialize object: " + ex.Message + " - " + ex.StackTrace));
}
return default(T);
}
public static void SaveToTootTallyAppData<T>(string fileName, T obj, bool saveToBackupIfExists = false)
{
string text = Path.Combine(FILE_PATH_TOOTTALLY_APPDATA, fileName);
try
{
string contents = JsonConvert.SerializeObject((object)obj);
if (File.Exists(text) && saveToBackupIfExists)
{
if (File.Exists(text + ".old"))
{
File.Delete(text + ".old");
}
File.Move(text, text + ".old");
}
File.WriteAllText(text, contents);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Couldn't serialize object: " + ex.Message + " - " + ex.StackTrace));
}
}
}
public static class HighscoreRegistry
{
public readonly struct HighscoreResult
{
public int Score { get; }
public bool ShowAsterisk { get; }
public HighscoreResult(int score, bool showAsterisk)
{
Score = score;
ShowAsterisk = showAsterisk;
}
}
private static Dictionary<string, Dictionary<string, Dictionary<int, int>>> _trackRefToHighscoreDict = new Dictionary<string, Dictionary<string, Dictionary<int, int>>>();
public static void LoadHighscoresFromFile()
{
_trackRefToHighscoreDict = FileHelper.LoadFromTootTallyAppData<Dictionary<string, Dictionary<string, Dictionary<int, int>>>>("HighscoreAccuracyScores.json");
if (_trackRefToHighscoreDict == null)
{
Plugin.Log.LogInfo((object)"Couldn't find highscores file, creating new one!");
_trackRefToHighscoreDict = new Dictionary<string, Dictionary<string, Dictionary<int, int>>>();
FileHelper.SaveToTootTallyAppData("HighscoreAccuracyScores.json", _trackRefToHighscoreDict, saveToBackupIfExists: true);
}
}
public static void CheckNewScore(string trackref, int score, string mods, float gamespeed)
{
if (gamespeed != 0f)
{
mods = SortModsString(mods);
int key = (int)Math.Round(gamespeed * 100f);
if (!_trackRefToHighscoreDict.TryGetValue(trackref, out var value))
{
value = new Dictionary<string, Dictionary<int, int>>();
_trackRefToHighscoreDict[trackref] = value;
}
if (!value.TryGetValue(mods, out var value2))
{
value2 = (value[mods] = new Dictionary<int, int>());
}
if (!value2.TryGetValue(key, out var value3) || score > value3)
{
value2[key] = score;
FileHelper.SaveToTootTallyAppData("HighscoreAccuracyScores.json", _trackRefToHighscoreDict);
}
}
}
public static HighscoreResult GetHighscore(string trackref, string mods, float gamespeed)
{
if (Plugin.useModSpecificHighscores.Value == ModSpecificHighscoreMode.Global)
{
return new HighscoreResult(GetGlobalHighscore(), showAsterisk: false);
}
mods = SortModsString(mods);
int key = (int)Math.Round(gamespeed * 100f);
if (_trackRefToHighscoreDict.TryGetValue(trackref, out var value) && value.TryGetValue(mods, out var value2) && value2.TryGetValue(key, out var value3))
{
return new HighscoreResult(value3, showAsterisk: false);
}
if (Plugin.useModSpecificHighscores.Value == ModSpecificHighscoreMode.Hybrid)
{
return new HighscoreResult(GetGlobalHighscore(), showAsterisk: true);
}
return new HighscoreResult(0, showAsterisk: false);
}
private static int GetGlobalHighscore()
{
FSharpOption<SavedTrackScore> val = TrackLookup.lookupScore(GlobalVariables.chosen_track);
return (val != null) ? ((IEnumerable<int>)val.Value.highScores).FirstOrDefault() : 0;
}
public static string SortModsString(string mods)
{
return string.Join(",", (from m in mods.Split(new char[1] { ',' })
select m.Trim() into m
orderby m
select m).ToArray());
}
}
public class OptionalTootTally
{
public static Type TootTallyGlobalVariables = GetType("TootTallyCore.Utils.TootTallyGlobals.TootTallyGlobalVariables", "TootTallyCore");
private static Type GetType(string fullName, string assembly)
{
try
{
return Type.GetType(fullName + ", " + assembly);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Exception trying to get " + fullName + ". Reporting " + assembly + " as not found."));
Plugin.Log.LogError((object)ex.Message);
Plugin.Log.LogError((object)ex.StackTrace);
return null;
}
}
public static string GetModifiersString()
{
Type type = GetType("TootTallyGameModifiers.GameModifierManager", "TootTallyGameModifiers");
if (type == null)
{
return "";
}
MethodInfo method = type.GetMethod("GetModifiersString");
return (method == null) ? "" : ((string)method.Invoke(type, Array.Empty<object>()));
}
public static float GameSpeedMultiplier()
{
if (TootTallyGlobalVariables == null)
{
return GlobalVariables.turbomode ? 2f : 1f;
}
FieldInfo field = TootTallyGlobalVariables.GetField("gameSpeedMultiplier", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
return (field == null) ? 1f : ((float)field.GetValue(field));
}
public static object AddNewPage(string pageName, string headerText, float elementSpacing, Color bgColor)
{
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
Type type = GetType("TootTallySettings.TootTallySettingsManager", "TootTallySettings");
if (type == null)
{
Plugin.Log.LogDebug((object)"TootTallySettings not found");
return null;
}
MethodInfo method = type.GetMethod("AddNewPage", new Type[4]
{
typeof(string),
typeof(string),
typeof(float),
typeof(Color)
});
return (method == null) ? null : method.Invoke(type, new object[4] { pageName, headerText, elementSpacing, bgColor });
}
public static void AddToggle(object page, string name, ConfigEntry<bool> config)
{
MethodInfo method = page.GetType().GetMethod("AddToggle", new Type[3]
{
typeof(string),
typeof(ConfigEntry<bool>),
typeof(UnityAction<bool>)
});
if (method != null)
{
method.Invoke(page, new object[3] { name, config, null });
}
}
public static void AddSlider(object page, string name, float min, float max, ConfigEntry<float> config, bool integerOnly)
{
MethodInfo method = page.GetType().GetMethod("AddSlider", new Type[5]
{
typeof(string),
typeof(float),
typeof(float),
typeof(ConfigEntry<float>),
typeof(bool)
});
if (method != null)
{
method.Invoke(page, new object[5] { name, min, max, config, integerOnly });
}
}
public static void AddDropdown(object page, string name, ConfigEntryBase config)
{
MethodInfo method = page.GetType().GetMethod("AddDropdown", new Type[2]
{
typeof(string),
typeof(ConfigEntryBase)
});
if (method != null)
{
method.Invoke(page, new object[2] { name, config });
}
}
public static void AddLabel(object page, string label, int fontSize, TextAlignmentOptions textAlignment)
{
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
MethodInfo method = page.GetType().GetMethod("AddLabel", new Type[5]
{
typeof(string),
typeof(string),
typeof(int),
typeof(FontStyles),
typeof(TextAlignmentOptions)
});
if (method != null)
{
method.Invoke(page, new object[5]
{
label,
label,
fontSize,
(object)(FontStyles)0,
textAlignment
});
}
}
}
public class PercentCounter : MonoBehaviour
{
public static Action<int, int> scoreChanged;
private Text foregroundText;
private Text shadowText;
private int pbScore;
private float pbPercent;
private int maxScore;
private int[] scoreLeftover;
private int[] scoreSums;
private float targetAcc;
private float currentAcc;
private float updateTimer;
private float timeSinceLastScore;
public void Init(int maxScore, int[] scoreLeftover, int[] scoreSums, int pbScore, float pbPercent)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
this.maxScore = maxScore;
this.scoreLeftover = scoreLeftover;
this.scoreSums = scoreSums;
this.pbScore = pbScore;
this.pbPercent = pbPercent;
((Component)this).transform.localScale = Vector3.one;
}
private void Start()
{
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
foregroundText = ((Component)((Component)this).transform.Find("Score")).GetComponent<Text>();
shadowText = ((Component)this).GetComponent<Text>();
foregroundText.text = 100.FormatDecimals() + "%";
shadowText.text = 100.FormatDecimals() + "%";
foregroundText.supportRichText = true;
shadowText.supportRichText = true;
targetAcc = (currentAcc = 100f);
updateTimer = (timeSinceLastScore = 0f);
RectTransform component = ((Component)this).GetComponent<RectTransform>();
component.anchoredPosition = new Vector2(component.anchoredPosition.x - 50f, component.anchoredPosition.y - 25f);
scoreChanged = (Action<int, int>)Delegate.Combine(scoreChanged, new Action<int, int>(OnScoreChanged));
}
private void Update()
{
if (Plugin.animateCounter.Value)
{
updateTimer += Time.deltaTime;
timeSinceLastScore += Time.deltaTime;
if (updateTimer > 0.02f && currentAcc != targetAcc)
{
currentAcc = EaseValue(currentAcc, targetAcc - currentAcc, timeSinceLastScore, 0.6f);
UpdateText(currentAcc);
updateTimer = 0f;
}
}
}
private void OnDestroy()
{
scoreChanged = (Action<int, int>)Delegate.Remove(scoreChanged, new Action<int, int>(OnScoreChanged));
}
internal void OnScoreChanged(int totalScore, int noteIndex)
{
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
if (scoreLeftover == null || scoreSums == null || maxScore == 0)
{
return;
}
float percent = GetPercent(totalScore, noteIndex);
if (Plugin.animateCounter.Value)
{
timeSinceLastScore = 0f;
targetAcc = percent;
}
else
{
UpdateText(percent);
}
if (Plugin.colorBehavior.Value != ColorBehavior.PbPossibility && Plugin.colorBehavior.Value != ColorBehavior.Hybrid)
{
return;
}
if (totalScore > pbScore)
{
((Graphic)foregroundText).color = new Color(0f, 0.7f, 0f);
return;
}
if (percent > pbPercent)
{
((Graphic)foregroundText).color = Color.green;
return;
}
float num = scoreLeftover[noteIndex];
if ((float)totalScore + num > (float)pbScore)
{
if (Plugin.colorBehavior.Value == ColorBehavior.Hybrid && percent < pbPercent - 10f)
{
((Graphic)foregroundText).color = new Color(1f, 0.5f, 0f);
}
else
{
((Graphic)foregroundText).color = Color.yellow;
}
}
else
{
((Graphic)foregroundText).color = Color.red;
}
}
internal void UpdateText(float percent)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
string text = percent.FormatDecimals() + "%";
foregroundText.text = text;
shadowText.text = text;
if (Plugin.colorBehavior.Value == ColorBehavior.Closeness)
{
if (percent > pbPercent)
{
((Graphic)foregroundText).color = Color.green;
}
else if (percent < pbPercent - 10f)
{
((Graphic)foregroundText).color = Color.red;
}
else
{
((Graphic)foregroundText).color = Color.yellow;
}
}
}
private float GetPercent(int totalScore, int noteIndex)
{
AccType value = Plugin.accType.Value;
if (1 == 0)
{
}
float result = value switch
{
AccType.Increasing => (float)totalScore / (float)maxScore * 100f,
AccType.Decreasing => (float)(totalScore + scoreLeftover[noteIndex]) / (float)maxScore * 100f,
_ => (float)totalScore / (float)scoreSums[noteIndex] * 100f,
};
if (1 == 0)
{
}
return result;
}
private float EaseValue(float current, float diff, float timeSum, float duration)
{
return Mathf.Max(diff * (0f - Mathf.Pow(2f, -10f * timeSum / duration) + 1f) * 1024f / 1023f + current, 0f);
}
}
[HarmonyPatch]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("com.hypersonicsharkz.highscoreaccuracy", "Highscore Accuracy", "1.4.0")]
public class Plugin : BaseUnityPlugin
{
internal static Plugin Instance;
internal static ManualLogSource Log;
public const string FILE_HIGHSCORES_NAME = "HighscoreAccuracyScores.json";
internal static ConfigEntry<AccType> accType;
internal static ConfigEntry<ColorBehavior> colorBehavior;
internal static ConfigEntry<float> decimals;
internal static ConfigEntry<bool> showAccIngame;
internal static ConfigEntry<bool> showLetterIngame;
internal static ConfigEntry<bool> showPBIngame;
internal static ConfigEntry<bool> animateCounter;
internal static ConfigEntry<ModSpecificHighscoreMode> useModSpecificHighscores;
private void Awake()
{
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0241: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
accType = ((BaseUnityPlugin)this).Config.Bind<AccType>("General", "Acc Type", AccType.Real, (ConfigDescription)null);
colorBehavior = ((BaseUnityPlugin)this).Config.Bind<ColorBehavior>("General", "Color Behavior", ColorBehavior.Hybrid, (ConfigDescription)null);
decimals = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Decimal Places", 2f, (ConfigDescription)null);
showAccIngame = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show acc in track", true, (ConfigDescription)null);
showLetterIngame = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show letter rank in track", false, (ConfigDescription)null);
showPBIngame = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show PB in track", true, (ConfigDescription)null);
animateCounter = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Gradually increase the accuracy.", false, (ConfigDescription)null);
useModSpecificHighscores = ((BaseUnityPlugin)this).Config.Bind<ModSpecificHighscoreMode>("General", "Use Modifier and Game Speed Specific High Scores", ModSpecificHighscoreMode.Hybrid, (ConfigDescription)null);
object obj = OptionalTootTally.AddNewPage("Highscore Accuracy", "Highscore Accuracy", 40f, new Color(0.1f, 0.1f, 0.1f, 0.1f));
if (obj != null)
{
OptionalTootTally.AddLabel(obj, "Accuracy Type", 24, (TextAlignmentOptions)1025);
OptionalTootTally.AddDropdown(obj, "Accuracy Type", (ConfigEntryBase)(object)accType);
OptionalTootTally.AddLabel(obj, "- Base Game: uses the internal calculations for the letter where >100% = S.\n\n- Real: calculates the actual maximum score for a track.\n\n- Decreasing: Uses real accuracy, but your % will always decrease or stay the same.\nFor example, ignoring multipliers, completely missing the first note of a 100 note song will give you 99%.\n\n- Increasing: Uses real accuracy, but your % will always increase or stay the same.\nFor example, ignoring multipliers, perfectly hitting the first note of a 100 note song will give you 1%.", 24, (TextAlignmentOptions)257);
OptionalTootTally.AddLabel(obj, "Color Behavior", 24, (TextAlignmentOptions)1025);
OptionalTootTally.AddDropdown(obj, "Color Behavior", (ConfigEntryBase)(object)colorBehavior);
OptionalTootTally.AddLabel(obj, "- Closeness: Color depends on how close you are to your PB (old Highscore Accuracy behavior)\n - Green: Above PB\n - Yellow: Up to 10% below PB\n - Red: More than 10% below PB\n\n- PB Possibility: Color depends on whether a PB is possible or not\n - Dark green: Above PB and cannot avoid setting a new PB\n - Green: Above PB\n - Yellow: PB is still possible with the remaining notes\n - Red: PB is impossible\n\n- Hybrid: A combination of the above two (adding orange if below 10% of your PB, but a PB is still possible)\n - Dark green: Above PB and cannot avoid setting a new PB\n - Green: Above PB\n - Yellow: PB is still possible with the remaining notes\n - Orange: PB is still possible with the remaining notes, but you're more than 10% below PB\n - Red: PB is impossible", 24, (TextAlignmentOptions)257);
OptionalTootTally.AddSlider(obj, "Decimal Places", 0f, 4f, decimals, integerOnly: true);
OptionalTootTally.AddToggle(obj, "Show Acc Ingame", showAccIngame);
OptionalTootTally.AddToggle(obj, "Show Letter Rank Ingame", showLetterIngame);
OptionalTootTally.AddToggle(obj, "Show PB Ingame", showPBIngame);
OptionalTootTally.AddToggle(obj, "Animate Counter", animateCounter);
OptionalTootTally.AddLabel(obj, "Use Game Speed and Modifier Specific High Scores", 24, (TextAlignmentOptions)1025);
OptionalTootTally.AddDropdown(obj, "Use Modifier and Game Speed Specific High Scores", (ConfigEntryBase)(object)useModSpecificHighscores);
OptionalTootTally.AddLabel(obj, "Modifier and game speed specific high scores set without this version of the mod installed aren't saved and can't be shown.\n \n- Global: The highest score across all modifiers and game speeds is shown. (old Highscore Accuracy behavior)\n\n- ModSpecific: The modifier and game speed specific high score is shown if found.\nOtherwise, no high score is shown.\n \n- Hybrid: The modifier and game speed specific high score is shown if found.\nOtherwise, the highest score across all modifiers and game speeds is shown with an asterisk (*).", 24, (TextAlignmentOptions)257);
}
HighscoreRegistry.LoadHighscoresFromFile();
new Harmony("com.hypersonicsharkz.highscoreaccuracy").PatchAll();
}
[HarmonyPatch(typeof(LevelSelectController), "populateScores")]
private static void Postfix(LevelSelectController __instance, int ___songindex, List<SingleTrackData> ___alltrackslist)
{
string trackref = ___alltrackslist[___songindex].trackref;
if (Utils.SkipHighscore(trackref))
{
return;
}
try
{
List<float[]> levelData = Utils.GetLevelData(trackref);
int maxScore = Utils.GetMaxScore(AccType.BaseGame, levelData);
int maxScore2 = Utils.GetMaxScore(accType.Value, levelData);
for (int i = 0; i < 5; i++)
{
if (float.TryParse(__instance.topscores[i].text, out var result))
{
__instance.topscores[i].fontSize = 19;
string text = Utils.ScoreLetter(result / (float)maxScore);
float num = result / (float)maxScore2;
__instance.topscores[i].text = __instance.topscores[i].text + " " + (100f * num).FormatDecimals() + "% " + text;
}
}
}
catch (Exception ex)
{
Debug.LogError((object)ex.Message);
}
}
[HarmonyPatch(typeof(GameController), "tallyScore")]
private static void Prefix(ref int ___previous_high_score)
{
___previous_high_score = int.MaxValue;
}
[HarmonyPatch(typeof(PointSceneController), "doCoins")]
[HarmonyPriority(600)]
private static void Postfix(PointSceneController __instance)
{
string trackref = GlobalVariables.chosen_track_data.trackref;
if (!Utils.SkipHighscore(trackref))
{
List<float[]> levelData = Utils.GetLevelData(trackref);
int maxScore = Utils.GetMaxScore(accType.Value, levelData);
float number = (float)GlobalVariables.gameplay_scoretotal / (float)maxScore * 100f;
float number2 = float.Parse(__instance.txt_prevhigh.text) / (float)maxScore * 100f;
Text txt_score = __instance.txt_score;
txt_score.text = txt_score.text + " " + number.FormatDecimals() + "%";
__instance.txt_score.horizontalOverflow = (HorizontalWrapMode)1;
Text txt_prevhigh = __instance.txt_prevhigh;
txt_prevhigh.text = txt_prevhigh.text + " " + number2.FormatDecimals() + "%";
__instance.txt_prevhigh.horizontalOverflow = (HorizontalWrapMode)1;
}
}
[HarmonyPatch(typeof(GameController), "Start")]
private static void Postfix(GameController __instance, List<float[]> ___leveldata)
{
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
if (__instance.freeplay)
{
return;
}
float pbPercent = 0f;
int pbScore = 0;
GameObject val = GameObject.Find("ScoreShadow");
int[] scoreSums = Utils.GetScoreSums(accType.Value, ___leveldata);
int num = scoreSums[___leveldata.Count - 1];
if (showPBIngame.Value)
{
HighscoreRegistry.HighscoreResult highscore = HighscoreRegistry.GetHighscore(GlobalVariables.chosen_track, OptionalTootTally.GetModifiersString(), OptionalTootTally.GameSpeedMultiplier());
if (highscore.Score > 0)
{
GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent);
val2.transform.localScale = Vector3.one;
RectTransform component = val2.GetComponent<RectTransform>();
component.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y - 50f);
Text component2 = ((Component)val2.transform.Find("Score")).GetComponent<Text>();
Text component3 = val2.GetComponent<Text>();
float num2 = (float)highscore.Score / (float)num * 100f;
component2.text = "PB: " + num2.FormatDecimals() + "%" + (highscore.ShowAsterisk ? "*" : "");
component3.text = "PB: " + num2.FormatDecimals() + "%" + (highscore.ShowAsterisk ? "*" : "");
pbPercent = num2;
pbScore = highscore.Score;
}
}
int[] array = new int[scoreSums.Length];
for (int i = 0; i < scoreSums.Length; i++)
{
array[i] = num - scoreSums[i];
}
if (showAccIngame.Value)
{
PercentCounter percentCounter = Object.Instantiate<GameObject>(val, val.transform.parent).AddComponent<PercentCounter>();
percentCounter.Init(num, array, scoreSums, pbScore, pbPercent);
}
if (showLetterIngame.Value)
{
ScoreCounter scoreCounter = Object.Instantiate<GameObject>(val, val.transform.parent).AddComponent<ScoreCounter>();
scoreCounter.Init(Utils.GetScoreSums(AccType.BaseGame, ___leveldata));
}
}
[HarmonyPatch(typeof(GameController), "getScoreAverage")]
private static void Postfix(int ___totalscore, int ___currentnoteindex)
{
if (showAccIngame.Value)
{
PercentCounter.scoreChanged(___totalscore, ___currentnoteindex);
}
if (showLetterIngame.Value)
{
ScoreCounter.scoreChanged(___totalscore, ___currentnoteindex);
}
}
[HarmonyPatch(typeof(SaverLoader), "checkForUpdatedScore")]
private static void Prefix(SingleTrackData played_track, int newscore, string newletterscore)
{
HighscoreRegistry.CheckNewScore(played_track.trackref, newscore, OptionalTootTally.GetModifiersString(), OptionalTootTally.GameSpeedMultiplier());
}
}
public class ScoreCounter : MonoBehaviour
{
public static Action<int, int> scoreChanged;
private int[] scoreSums;
private Text foregroundText;
private Text shadowText;
public void Init(int[] scoreSums)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
this.scoreSums = scoreSums;
((Component)this).transform.localScale = Vector3.one;
}
private void Start()
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
foregroundText = ((Component)((Component)this).transform.Find("Score")).GetComponent<Text>();
shadowText = ((Component)this).GetComponent<Text>();
foregroundText.text = "S";
shadowText.text = "S";
RectTransform component = ((Component)this).GetComponent<RectTransform>();
component.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y - 25f);
scoreChanged = (Action<int, int>)Delegate.Combine(scoreChanged, new Action<int, int>(OnScoreChanged));
}
private void OnDestroy()
{
scoreChanged = (Action<int, int>)Delegate.Remove(scoreChanged, new Action<int, int>(OnScoreChanged));
}
internal void OnScoreChanged(int totalScore, int noteIndex)
{
if (scoreSums != null)
{
float num = (float)totalScore / (float)scoreSums[noteIndex];
string text = Utils.ScoreLetter(num);
foregroundText.text = text;
shadowText.text = text;
}
}
}
public static class Utils
{
public static string FormatDecimals<T>(this T _number) where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
return string.Format(new NumberFormatInfo
{
NumberDecimalDigits = (int)Plugin.decimals.Value
}, "{0:F}", _number);
}
public static string ScoreLetter(float num)
{
return (!(num < 1f)) ? "S" : ((!(num < 0.8f)) ? "A" : ((!(num < 0.6f)) ? "B" : ((!(num < 0.4f)) ? "C" : ((num < 0.2f) ? "F" : "D"))));
}
public static int GetMaxScore(AccType accType, List<float[]> levelData)
{
return GetScoreSums(accType, levelData)[levelData.Count - 1];
}
public static int[] GetScoreSums(AccType accType, List<float[]> levelData)
{
int[] array = new int[levelData.Count];
int num = 0;
int num2 = 0;
float num3 = 0.025f;
for (int i = 0; i < levelData.Count; i++)
{
float num4 = levelData[i][1];
for (; i + 1 < levelData.Count && levelData[i][0] + levelData[i][1] + num3 >= levelData[i + 1][0]; i++)
{
num4 += levelData[i + 1][1];
array[i] = num;
}
int num5 = ((accType == AccType.BaseGame) ? GetGameMax(num4) : GetRealMax(num4, num2));
num = (array[i] = num + num5);
num2++;
}
return array;
}
private static int GetRealMax(float length, int noteIndex)
{
double num = ((noteIndex > 23) ? 1.5 : 0.0);
double num2 = ((double)Math.Min(noteIndex, 10) + num) * 0.100000001490116 + 1.0;
length = GetBaseScore(length);
return (int)(Mathf.Floor((float)((double)length * 100.0 * num2)) * 10f);
}
private static int GetGameMax(float length)
{
return (int)Mathf.Floor(Mathf.Floor(GetBaseScore(length) * 100f * 1.315f) * 10f);
}
private static float GetBaseScore(float length)
{
return Mathf.Clamp(length, 0.2f, 5f) * 8f + 10f;
}
public static List<float[]> GetLevelData(string trackRef)
{
return TrackLookup.lookup(trackRef).LoadChart().savedleveldata;
}
public static bool SkipHighscore(string trackRef)
{
if (TrackLookup.tryLookup(trackRef) == null)
{
return true;
}
if (!(TrackLookup.lookup(trackRef) is CustomTrack))
{
return false;
}
TromboneTrack obj = TrackLookup.lookup(trackRef);
CustomTrack val = (CustomTrack)(object)((obj is CustomTrack) ? obj : null);
string text = Path.Combine(val.folderPath, Globals.defaultChartName);
return !File.Exists(text) || new FileInfo(text).Length > 2000000;
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "com.hypersonicsharkz.highscoreaccuracy";
public const string PLUGIN_NAME = "Highscore Accuracy";
public const string PLUGIN_VERSION = "1.4.0";
}
}
namespace HighscoreAccuracy.Enums
{
public enum AccType
{
BaseGame,
Real,
Decreasing,
Increasing
}
public enum ColorBehavior
{
Closeness,
PbPossibility,
Hybrid
}
public enum ModSpecificHighscoreMode
{
Global,
ModSpecific,
Hybrid
}
}