Decompiled source of HighscoreAccuracy v1.3.7

HighscoreAccuracy.dll

Decompiled 2 months ago
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 Microsoft.FSharp.Core;
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.3.7.0")]
[assembly: AssemblyInformationalVersion("1.3.7")]
[assembly: AssemblyProduct("Highscore Accuracy")]
[assembly: AssemblyTitle("HighscoreAccuracy")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.7.0")]
[module: UnverifiableCode]
namespace HighscoreAccuracy;

public enum AccType
{
	BaseGame,
	Real,
	Decreasing,
	Increasing
}
public class OptionalTootTallySettings
{
	public static object AddNewPage(string pageName, string headerText, float elementSpacing, Color bgColor)
	{
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Type 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.Invoke(type, new object[4] { pageName, headerText, elementSpacing, bgColor });
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)"Exception trying to get config page. Reporting TootTallySettings as not found.");
			Plugin.Log.LogError((object)ex.Message);
			Plugin.Log.LogError((object)ex.StackTrace);
			return null;
		}
	}

	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 float pb;

	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, float pb)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		this.maxScore = maxScore;
		this.scoreLeftover = scoreLeftover;
		this.scoreSums = scoreSums;
		this.pb = pb;
		((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)
	{
		if (scoreLeftover != null && scoreSums != null && maxScore != 0)
		{
			float percent = GetPercent(totalScore, noteIndex);
			if (Plugin.animateCounter.Value)
			{
				timeSinceLastScore = 0f;
				targetAcc = percent;
			}
			else
			{
				UpdateText(percent);
			}
		}
	}

	internal void UpdateText(float percent)
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		string text = percent.FormatDecimals() + "%";
		foregroundText.text = text;
		shadowText.text = text;
		if (percent > pb)
		{
			((Graphic)foregroundText).color = Color.green;
		}
		else if (percent < pb - 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.*/)]
[BepInPlugin("com.hypersonicsharkz.highscoreaccuracy", "Highscore Accuracy", "1.3.7")]
public class Plugin : BaseUnityPlugin
{
	internal static Plugin Instance;

	internal static ManualLogSource Log;

	internal static ConfigEntry<AccType> accType;

	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;

	private void Awake()
	{
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: 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);
		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);
		object obj = OptionalTootTallySettings.AddNewPage("Highscore Accuracy", "Highscore Accuracy", 40f, new Color(0.1f, 0.1f, 0.1f, 0.1f));
		if (obj != null)
		{
			OptionalTootTallySettings.AddLabel(obj, "Accuracy Type *", 24, (TextAlignmentOptions)1025);
			OptionalTootTallySettings.AddDropdown(obj, "Accuracy Type", (ConfigEntryBase)(object)accType);
			OptionalTootTallySettings.AddSlider(obj, "Decimal Places", 0f, 4f, decimals, integerOnly: true);
			OptionalTootTallySettings.AddToggle(obj, "Show Acc Ingame", showAccIngame);
			OptionalTootTallySettings.AddToggle(obj, "Show Letter Rank Ingame", showLetterIngame);
			OptionalTootTallySettings.AddToggle(obj, "Show PB Ingame", showPBIngame);
			OptionalTootTallySettings.AddToggle(obj, "Animate Counter", animateCounter);
			OptionalTootTallySettings.AddLabel(obj, "* Accuracy Type:\n- Base Game: uses the internal calculations for the letter where >100% = S.\n- Real: calculates the actual maximum score for a track.\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- 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%.\n\nIf the dropdown isn't showing up, update TootTally.\nYou can still update accuracy type through the config file, as usual.", 24, (TextAlignmentOptions)257);
		}
		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;
		}
		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++)
		{
			try
			{
				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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		if (__instance.freeplay)
		{
			return;
		}
		float pb = 0f;
		GameObject val = GameObject.Find("ScoreShadow");
		int[] scoreSums = Utils.GetScoreSums(accType.Value, ___leveldata);
		int num = scoreSums[___leveldata.Count - 1];
		if (showPBIngame.Value)
		{
			FSharpOption<SavedTrackScore> val2 = TrackLookup.lookupScore(GlobalVariables.chosen_track);
			int num2 = ((val2 != null) ? ((IEnumerable<int>)val2.Value.highScores).FirstOrDefault() : 0);
			if (num2 > 0)
			{
				GameObject val3 = Object.Instantiate<GameObject>(val, val.transform.parent);
				val3.transform.localScale = Vector3.one;
				RectTransform component = val3.GetComponent<RectTransform>();
				component.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y - 50f);
				Text component2 = ((Component)val3.transform.Find("Score")).GetComponent<Text>();
				Text component3 = val3.GetComponent<Text>();
				float num3 = (float)num2 / (float)num * 100f;
				component2.text = "PB: " + num3.FormatDecimals() + "%";
				component3.text = "PB: " + num3.FormatDecimals() + "%";
				pb = num3;
			}
		}
		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, pb);
		}
		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);
		}
	}
}
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)
	{
		TromboneTrack obj = TrackLookup.lookup(trackRef);
		CustomTrack val = (CustomTrack)(object)((obj is CustomTrack) ? obj : null);
		return val != null && new FileInfo(Path.Combine(val.folderPath, Globals.defaultChartName)).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.3.7";
}