Decompiled source of TootTallyDiffCalcLibs v1.0.7

plugins/TootTallyDiffCalcLibs.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
using BaboonAPI.Hooks.Initializer;
using BaboonAPI.Hooks.Tracks;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TootTallyCore;
using TootTallyCore.Utils.TootTallyModules;
using TrombLoader.CustomTracks;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("TootTallyDiffCalcLibs")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("TootTally Module Template")]
[assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: AssemblyInformationalVersion("1.0.7")]
[assembly: AssemblyProduct("TootTallyDiffCalcLibs")]
[assembly: AssemblyTitle("TootTallyDiffCalcLibs")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.7.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 TootTallyDiffCalcLibs
{
	public struct Chart : IDisposable
	{
		public class Lyrics
		{
			public string bar;

			public string text;
		}

		public class LengthAccPair
		{
			public float length;

			public float acc;

			public LengthAccPair(float length, float acc)
			{
				this.length = length;
				this.acc = acc;
			}
		}

		public float[][] notes;

		public string[][] bgdata;

		public Dictionary<float, List<Note>> notesDict;

		public List<string> note_color_start;

		public List<string> note_color_end;

		public float endpoint;

		public float savednotespacing;

		public float tempo;

		public string timesig;

		public string trackRef;

		public string name;

		public string shortName;

		public string author;

		public string genre;

		public string description;

		public string difficulty;

		public string year;

		public int maxScore;

		public int gameMaxScore;

		public Dictionary<int, int> indexToMaxScoreDict;

		public Dictionary<int, int> indexToNoteCountDict;

		public ChartPerformances performances;

		public TimeSpan calculationTime;

		public int sliderCount;

		public float songLength;

		public float songLengthMult;

		public void ProcessLite()
		{
			notesDict = new Dictionary<float, List<Note>>();
			CreateNotes(0, 1f);
			songLengthMult = GetSongLengthMult(notesDict[0f]);
			sliderCount = GetNoteCount();
			performances = new ChartPerformances(notesDict[0f].Count, sliderCount);
			performances.Calculate(0, notesDict[0f], songLengthMult);
		}

		public void Process()
		{
			notesDict = new Dictionary<float, List<Note>>();
			for (int i = 0; i < Utils.GAME_SPEED.Length; i++)
			{
				CreateNotes(i, Utils.GAME_SPEED[i]);
			}
			songLengthMult = GetSongLengthMult(notesDict[2f]);
			sliderCount = GetNoteCount();
			performances = new ChartPerformances(notesDict[0f].Count, sliderCount);
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			for (int j = 0; j < Utils.GAME_SPEED.Length; j++)
			{
				performances.Calculate(j, notesDict[j], songLengthMult);
			}
			stopwatch.Stop();
			calculationTime = stopwatch.Elapsed;
			CalcScores();
		}

		private void CreateNotes(int i, float gamespeed)
		{
			float bpm = tempo * gamespeed;
			int num = 1;
			notesDict[i] = new List<Note>(notes.Length)
			{
				new Note(0, 0f, 0.015f, 0f, 0f, 0f, isSlider: false)
			};
			float[][] array = notes.OrderBy((float[] x) => x[0]).ToArray();
			for (int j = 0; j < array.Length; j++)
			{
				float num2 = array[j][1];
				if (num2 <= 0f)
				{
					num2 = 0.015f;
				}
				bool isSlider = ((i <= 0) ? (j + 1 < array.Length && IsSlider(array[j], array[j + 1])) : notesDict[0f][j + 1].isSlider);
				notesDict[i].Add(new Note(num, BeatToSeconds2(array[j][0], bpm), BeatToSeconds2(num2, bpm), array[j][2], array[j][3], array[j][4], isSlider));
				num++;
			}
		}

		private float GetSongLengthMult(List<Note> notes)
		{
			if (notes.Count > 2)
			{
				songLength = notes.Last().position - notes[1].position;
			}
			if (songLength < 1f)
			{
				songLength = 1f;
			}
			return Mathf.Pow(songLength / 15f, (float)Math.E * -4f / 25f) + 0.475f;
		}

		public static float GetLength(float length)
		{
			return Mathf.Clamp(length, 0.2f, 5f) * 8f + 10f;
		}

		public int GetNoteCount()
		{
			int num = 0;
			for (int i = 0; i < notes.Length; i++)
			{
				for (; i + 1 < notes.Length && IsSlider(notes[i], notes[i + 1]); i++)
				{
				}
				num++;
			}
			return num;
		}

		public void CalcScores()
		{
			maxScore = 0;
			gameMaxScore = 0;
			indexToMaxScoreDict = new Dictionary<int, int>();
			indexToNoteCountDict = new Dictionary<int, int>();
			int num = 0;
			for (int i = 0; i < notes.Length; i++)
			{
				float num2 = notes[i][1];
				for (; i + 1 < notes.Length && notes[i][0] + notes[i][1] + 0.025f >= notes[i + 1][0]; i++)
				{
					num2 += notes[i + 1][1];
				}
				double num3 = ((num > 23) ? 1.5 : 0.0);
				double num4 = ((double)Math.Min(num, 10) + num3) * 0.1 + 1.0;
				float length = GetLength(num2);
				int num5 = (int)(Math.Floor((float)((double)length * 100.0 * num4)) * 10.0);
				maxScore += num5;
				gameMaxScore += (int)Math.Floor(Math.Floor(length * 100f * 1.315f) * 10.0);
				indexToMaxScoreDict.Add(i, maxScore);
				num++;
				indexToNoteCountDict.Add(i, num);
			}
		}

		public float GetBaseTT(float speed)
		{
			return Utils.CalculateBaseTT(GetDiffRating(Mathf.Clamp(speed, 0.5f, 2f)));
		}

		public float GetDiffRating(float speed)
		{
			return performances.GetDiffRating(Mathf.Clamp(speed, 0.5f, 2f));
		}

		public float GetDynamicDiffRating(float speed, float percent, string[] modifiers = null)
		{
			return performances.GetDynamicDiffRating(percent, speed, modifiers);
		}

		public float GetLerpedStarRating(float speed)
		{
			return performances.GetDiffRating(Mathf.Clamp(speed, 0.5f, 2f));
		}

		public float GetAimPerformance(float speed)
		{
			return performances.aimAnalyticsDict[SpeedToIndex(speed)].perfWeightedAverage;
		}

		public float GetTapPerformance(float speed)
		{
			return performances.tapAnalyticsDict[SpeedToIndex(speed)].perfWeightedAverage;
		}

		public float GetStarRating(float speed)
		{
			return performances.starRatingDict[SpeedToIndex(speed)];
		}

		public int SpeedToIndex(float speed)
		{
			return (int)((Mathf.Clamp(speed, 0.5f, 2f) - 0.5f) / 0.25f);
		}

		public static float BeatToSeconds2(float beat, float bpm)
		{
			return 60f / bpm * beat;
		}

		public static bool IsSlider(float[] currNote, float[] nextNote)
		{
			return currNote[0] + currNote[1] + 0.025f >= nextNote[0];
		}

		public static float GetHealthDiff(float acc)
		{
			return Mathf.Clamp((acc - 79f) * 0.2193f, -15f, 4.34f);
		}

		public static int GetScore(float acc, float totalLength, float mult, bool champ)
		{
			float num = Mathf.Clamp(totalLength, 0.2f, 5f) * 8f + 10f;
			return (int)Math.Floor(num * acc * ((mult + (champ ? 1.5f : 0f)) * 0.1f + 1f)) * 10;
		}

		public void Dispose()
		{
			notes = null;
			bgdata = null;
			notesDict?.Clear();
			performances.Dispose();
			indexToMaxScoreDict?.Clear();
			indexToNoteCountDict?.Clear();
		}
	}
	public struct ChartPerformances : IDisposable
	{
		public struct DataVector
		{
			public float performance;

			public float endurance;

			public float time;

			public float weight;

			public DataVector(float time, float performance, float endurance, float weight)
			{
				this.time = time;
				this.endurance = endurance;
				this.performance = performance;
				this.weight = weight;
			}
		}

		public struct DataVectorAnalytics
		{
			public float perfMax;

			public float perfWeightedAverage;

			public float weightSum;

			public DataVectorAnalytics(List<DataVector> dataVectorList, float songLengthMult)
			{
				perfMax = (perfWeightedAverage = 0f);
				weightSum = 1f;
				if (dataVectorList.Count > 0)
				{
					CalculateWeightSum(dataVectorList, songLengthMult);
					CalculateData(dataVectorList);
				}
			}

			public void CalculateWeightSum(List<DataVector> dataVectorList, float songLengthMult)
			{
				for (int i = 0; i < dataVectorList.Count; i++)
				{
					weightSum += dataVectorList[i].weight;
				}
				weightSum *= songLengthMult;
			}

			public void CalculateData(List<DataVector> dataVectorList)
			{
				for (int i = 0; i < dataVectorList.Count; i++)
				{
					if (dataVectorList[i].performance > perfMax)
					{
						perfMax = dataVectorList[i].performance;
					}
					perfWeightedAverage += (dataVectorList[i].performance + dataVectorList[i].endurance) * (dataVectorList[i].weight / weightSum);
				}
			}
		}

		public static readonly float[] weights = new float[65]
		{
			1f, 0.92f, 0.8464f, 0.7787f, 0.7164f, 0.6591f, 0.6064f, 0.5578f, 0.5132f, 0.4722f,
			0.4344f, 0.3996f, 0.3677f, 0.3383f, 0.3112f, 0.2863f, 0.2634f, 0.2423f, 0.2229f, 0.2051f,
			0.1887f, 0.1736f, 0.1597f, 0.1469f, 0.1352f, 0.1244f, 0.1144f, 0.1053f, 0.0968f, 0.0891f,
			0.082f, 0.0754f, 0.0694f, 0.0638f, 0.0587f, 0.054f, 0.0497f, 0.0457f, 0.0421f, 0.0387f,
			0.0356f, 0.0328f, 0.0301f, 0.0277f, 0.0255f, 0.0235f, 0.0216f, 0.0199f, 0.0183f, 0.0168f,
			0.0155f, 0.0142f, 0.0131f, 0.012f, 0.0111f, 0.0102f, 0.0094f, 0.0086f, 0.0079f, 0.0073f,
			0.0067f, 0.0062f, 0.0057f, 0.0052f, 0.0048f
		};

		public const float CHEESABLE_THRESHOLD = 34.375f;

		public List<DataVector>[] aimPerfDict;

		public List<DataVector>[] sortedAimPerfDict;

		public DataVectorAnalytics[] aimAnalyticsDict;

		public List<DataVector>[] tapPerfDict;

		public List<DataVector>[] sortedTapPerfDict;

		public DataVectorAnalytics[] tapAnalyticsDict;

		public float[] aimRatingDict;

		public float[] tapRatingDict;

		public float[] starRatingDict;

		private readonly int NOTE_COUNT;

		public const float AIM_DIV = 375f;

		public const float TAP_DIV = 200f;

		public const float ACC_DIV = 375f;

		public const float AIM_END = 750f;

		public const float TAP_END = 15f;

		public const float ACC_END = 900f;

		public const float MUL_END = 50f;

		public const float MAX_DIST = 8f;

		private const float a = -40f;

		public const float BIAS = 0.75f;

		public const float MAP = 0.05f;

		public const float MACC = 0.5f;

		public const float AIM_WEIGHT = 1.25f;

		public const float TAP_WEIGHT = 1.12f;

		public static readonly float[] HDWeights = new float[2] { 0.34f, 0.02f };

		public static readonly float[] FLWeights = new float[2] { 0.55f, 0.02f };

		public static readonly float[] EZWeights = new float[2] { -0.4f, -0.02f };

		public ChartPerformances(int noteCount, int sliderCount)
		{
			aimPerfDict = new List<DataVector>[7];
			sortedAimPerfDict = new List<DataVector>[7];
			tapPerfDict = new List<DataVector>[7];
			sortedTapPerfDict = new List<DataVector>[7];
			aimRatingDict = new float[7];
			tapRatingDict = new float[7];
			starRatingDict = new float[7];
			aimAnalyticsDict = new DataVectorAnalytics[7];
			tapAnalyticsDict = new DataVectorAnalytics[7];
			for (int i = 0; i < Utils.GAME_SPEED.Length; i++)
			{
				aimPerfDict[i] = new List<DataVector>(sliderCount);
				tapPerfDict[i] = new List<DataVector>(sliderCount);
			}
			NOTE_COUNT = noteCount;
		}

		public void CalculatePerformances(int speedIndex, List<Note> noteList)
		{
			float endurance = 0f;
			float endurance2 = 0f;
			for (int i = 0; i < NOTE_COUNT; i++)
			{
				Note note = noteList[i];
				int num = 0;
				float num2 = 0f;
				float num3 = 0f;
				float num4 = 0f;
				int num5 = i - 1;
				while (num5 >= 0 && num < 64 && (Mathf.Abs(note.position - noteList[num5].position) <= 8f || i - num5 <= 2))
				{
					Note note2 = noteList[num5];
					Note note3 = noteList[num5 + 1];
					if (note2.position >= note3.position)
					{
						break;
					}
					float num6 = weights[num];
					num++;
					num2 += num6;
					float num7 = note2.length;
					float num8 = Mathf.Abs(note2.pitchDelta);
					if (num8 <= 34.375f)
					{
						num8 *= 0.35f;
					}
					while (note2.isSlider && num5-- > 0)
					{
						note2 = noteList[num5];
						note3 = noteList[num5 + 1];
						if (note2.pitchDelta == 0f)
						{
							num7 += note2.length * 0.85f;
							continue;
						}
						float num9 = Mathf.Abs(note2.pitchDelta);
						num7 += note2.length;
						if (num9 <= 34.375f)
						{
							num9 *= 0.25f;
						}
						num8 += num9;
					}
					float deltaTime = note3.position - note2.position;
					if (num8 != 0f)
					{
						num3 += ComputeStrain(CalcAccStrain(num7, num8, num6)) / 375f;
						endurance += CalcAccEndurance(num7, num8, num6);
					}
					float num10 = Mathf.Abs(note3.pitchStart - note2.pitchEnd);
					if (num10 != 0f || num8 != 0f)
					{
						num3 += ComputeStrain(CalcAimStrain(num10, num6, deltaTime)) / 375f;
						endurance += CalcAimEndurance(num10, num6, deltaTime);
					}
					float tapDelta = note3.position - note2.position;
					num4 += ComputeStrain(CalcTapStrain(tapDelta, num6, num10)) / 200f;
					endurance2 += CalcTapEndurance(tapDelta, num6, num10);
					num5--;
				}
				if (i > 0)
				{
					float num11 = 61f - Mathf.Min(note.position - noteList[i - 1].position, 5f) * 12f;
					float num12 = Mathf.Pow(num3, 1.08f) * 1.2f;
					float num13 = Mathf.Pow(num4, 1.08f) * 1.2f;
					if (endurance >= num12)
					{
						ComputeEnduranceDecay(ref endurance, (endurance - num12) / num11);
					}
					if (endurance2 >= num13)
					{
						ComputeEnduranceDecay(ref endurance2, (endurance2 - num13) / num11);
					}
				}
				aimPerfDict[speedIndex].Add(new DataVector(note.position, num3, endurance, num2));
				tapPerfDict[speedIndex].Add(new DataVector(note.position, num4, endurance2, num2));
			}
			sortedAimPerfDict[speedIndex] = aimPerfDict[speedIndex].OrderBy((DataVector x) => x.performance + x.endurance).ToList();
			sortedTapPerfDict[speedIndex] = tapPerfDict[speedIndex].OrderBy((DataVector x) => x.performance + x.endurance).ToList();
		}

		public static float ComputeStrain(float strain)
		{
			return -40f * Mathf.Pow(strain + 1f, -0.04349251f) - -40f - 5f * strain / -40f;
		}

		public static void ComputeEnduranceDecay(ref float endurance, float distanceFromLastNote)
		{
			endurance /= 1f + 0.2f * distanceFromLastNote;
		}

		public static float CalcAimStrain(float distance, float weight, float deltaTime)
		{
			float num = distance * 0.85f / Mathf.Pow(deltaTime, 1.35f);
			return num * weight;
		}

		public static float CalcAimEndurance(float distance, float weight, float deltaTime)
		{
			float num = distance * 0.25f / Mathf.Pow(deltaTime, 1.15f) / 37500f;
			return num * weight;
		}

		public static float CalcTapStrain(float tapDelta, float weight, float aimDistance)
		{
			float num = Mathf.Min(Utils.Lerp(8f, 16f, aimDistance / 103.125f), 20f);
			return num / Mathf.Pow(tapDelta, 1.35f) * weight;
		}

		public static float CalcTapEndurance(float tapDelta, float weight, float aimDistance)
		{
			float num = Mathf.Min(Utils.Lerp(0.15f, 0.35f, aimDistance / 103.125f), 0.5f);
			return num / Mathf.Pow(tapDelta, 1.3f) / 750f * weight;
		}

		public static float CalcAccStrain(float lengthSum, float slideDelta, float weight)
		{
			float num = slideDelta / Mathf.Pow(lengthSum, 1.18f);
			return num * weight;
		}

		public float CalcAccEndurance(float lengthSum, float slideDelta, float weight)
		{
			float num = slideDelta / Mathf.Pow(lengthSum, 1.08f) / 45000f;
			return num * weight;
		}

		public void Calculate(int speedIndex, List<Note> noteList, float songLengthMult)
		{
			CalculatePerformances(speedIndex, noteList);
			CalculateAnalytics(speedIndex, songLengthMult);
			CalculateRatings(speedIndex);
		}

		public void CalculateAnalytics(int speedIndex, float songLengthMult = 1f)
		{
			tapAnalyticsDict[speedIndex] = new DataVectorAnalytics(tapPerfDict[speedIndex], songLengthMult);
			aimAnalyticsDict[speedIndex] = new DataVectorAnalytics(aimPerfDict[speedIndex], songLengthMult);
		}

		public void CalculateRatings(int speedIndex)
		{
			float num = (aimRatingDict[speedIndex] = aimAnalyticsDict[speedIndex].perfWeightedAverage + 0.01f);
			float num2 = (tapRatingDict[speedIndex] = tapAnalyticsDict[speedIndex].perfWeightedAverage + 0.01f);
			if (num != 0f && num2 != 0f)
			{
				float num3 = num + num2;
				float num4 = num / num3;
				float num5 = num2 / num3;
				float num6 = (num4 + 0.75f) * 1.25f;
				float num7 = (num5 + 0.75f) * 1.12f;
				float num8 = num6 + num7;
				starRatingDict[speedIndex] = (num * num6 + num2 * num7) / num8;
			}
			else
			{
				starRatingDict[speedIndex] = 0f;
			}
		}

		public float GetDynamicAimRating(float percent, float speed)
		{
			return GetDynamicSkillRating(percent, speed, sortedAimPerfDict);
		}

		public float GetDynamicTapRating(float percent, float speed)
		{
			return GetDynamicSkillRating(percent, speed, sortedTapPerfDict);
		}

		private float GetDynamicSkillRating(float percent, float speed, List<DataVector>[] skillRatingMatrix)
		{
			int num = (int)((speed - 0.5f) / 0.25f);
			if (skillRatingMatrix[num].Count <= 1 || percent <= 0f)
			{
				return 0f;
			}
			if (speed % 0.25f == 0f)
			{
				return CalcSkillRating(percent, skillRatingMatrix[num]);
			}
			float firstFloat = CalcSkillRating(percent, skillRatingMatrix[num]);
			float secondFloat = CalcSkillRating(percent, skillRatingMatrix[num + 1]);
			float num2 = Utils.GAME_SPEED[num];
			float num3 = Utils.GAME_SPEED[num + 1];
			float by = (speed - num2) / (num3 - num2);
			return Utils.Lerp(firstFloat, secondFloat, by);
		}

		private float CalcSkillRating(float percent, List<DataVector> skillRatingArray)
		{
			int count = ((!(percent <= 0.5f)) ? ((int)Mathf.Clamp((float)skillRatingArray.Count * ((percent - 0.5f) * 1.9f + 0.05f), 1f, (float)skillRatingArray.Count)) : ((int)Mathf.Clamp((float)skillRatingArray.Count * (percent * 0.1f), 1f, (float)skillRatingArray.Count)));
			List<DataVector> range = skillRatingArray.GetRange(0, count);
			return new DataVectorAnalytics(range, DiffCalcGlobals.selectedChart.songLengthMult).perfWeightedAverage + 0.01f;
		}

		public float GetDynamicDiffRating(float percent, float gamespeed, string[] modifiers = null)
		{
			float num = GetDynamicAimRating(percent, gamespeed);
			float num2 = GetDynamicTapRating(percent, gamespeed);
			if (num == 0f && num2 == 0f)
			{
				return 0f;
			}
			if (modifiers != null)
			{
				float num3 = 1f;
				float num4 = 1f;
				bool flag = modifiers.Contains("EZ");
				float num5 = (flag ? 0.5f : 1f);
				if (modifiers.Contains("HD"))
				{
					num3 += HDWeights[0] * num5;
					num4 += HDWeights[1] * num5;
				}
				if (modifiers.Contains("FL"))
				{
					num3 += FLWeights[0] * num5;
					num4 += FLWeights[1] * num5;
				}
				if (flag)
				{
					num3 += EZWeights[0];
					num4 += EZWeights[1];
				}
				if (num3 <= 0f)
				{
					num3 = 0.01f;
				}
				if (num4 <= 0f)
				{
					num4 = 0.01f;
				}
				num *= num3;
				num2 *= num4;
			}
			float num6 = num + num2;
			float num7 = num / num6;
			float num8 = num2 / num6;
			float num9 = (num7 + 0.75f) * 1.25f;
			float num10 = (num8 + 0.75f) * 1.12f;
			float num11 = num9 + num10;
			return (num * num9 + num2 * num10) / num11;
		}

		public void Dispose()
		{
			aimPerfDict = null;
			sortedAimPerfDict = null;
			aimAnalyticsDict = null;
			aimRatingDict = null;
			tapPerfDict = null;
			sortedTapPerfDict = null;
			tapAnalyticsDict = null;
			tapRatingDict = null;
			starRatingDict = null;
		}

		public float GetDiffRating(float speed)
		{
			int num = (int)((speed - 0.5f) / 0.25f);
			if (speed % 0.25f == 0f)
			{
				return starRatingDict[num];
			}
			float num2 = Utils.GAME_SPEED[num];
			float num3 = Utils.GAME_SPEED[num + 1];
			float by = (speed - num2) / (num3 - num2);
			return Utils.Lerp(starRatingDict[num], starRatingDict[num + 1], by);
		}

		public static float BeatToSeconds2(float beat, float bpm)
		{
			return 60f / bpm * beat;
		}
	}
	public static class ChartReader
	{
		private static List<Chart> _allChartList = new List<Chart>();

		private static readonly string TrackassetDir = Application.streamingAssetsPath + "/trackassets";

		public static void AddChartToList(string path)
		{
			_allChartList.Add(LoadChart(path));
		}

		public static Chart ReadBaseGame(string trackRef)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			Chart result = default(Chart);
			string path = TrackassetDir + "/" + trackRef + "/metadata_en.tmb";
			using (FileStream serializationStream = File.Open(path, FileMode.Open))
			{
				SavedLevelMetadata val = (SavedLevelMetadata)binaryFormatter.Deserialize(serializationStream);
				result.name = val.trackname_long;
				result.shortName = val.trackname_short;
				result.trackRef = trackRef;
				result.author = val.artist;
				result.genre = val.genre;
				result.description = val.description;
				result.difficulty = val.difficulty.ToString();
				result.year = val.year;
			}
			string path2 = TrackassetDir + "/" + trackRef + "/trackdata.tmb";
			using FileStream serializationStream2 = File.Open(path2, FileMode.Open);
			SavedLevel val2 = (SavedLevel)binaryFormatter.Deserialize(serializationStream2);
			result.savednotespacing = val2.savednotespacing;
			result.endpoint = val2.endpoint;
			result.timesig = val2.timesig.ToString();
			result.tempo = val2.tempo;
			result.notes = val2.savedleveldata.ToArray();
			return result;
		}

		public static Chart LoadBaseGame(string trackRef)
		{
			Chart result = ReadBaseGame(trackRef);
			result.Process();
			return result;
		}

		public static Chart ReadCustomChart(string path)
		{
			using StreamReader streamReader = new StreamReader(path);
			string text = streamReader.ReadToEnd();
			return JsonConvert.DeserializeObject<Chart>(text);
		}

		public static Chart LoadChart(string path)
		{
			Chart result = ReadCustomChart(path);
			result.Process();
			return result;
		}

		public static Chart LoadChartFromJson(string json)
		{
			Chart result = JsonConvert.DeserializeObject<Chart>(json);
			result.Process();
			return result;
		}

		public static string CalcSHA256Hash(byte[] data)
		{
			using SHA256 sHA = SHA256.Create();
			string text = "";
			byte[] array = sHA.ComputeHash(data);
			byte[] array2 = array;
			foreach (byte b in array2)
			{
				text += $"{b:x2}";
			}
			return text;
		}

		public static void SaveChartData(string path, string json)
		{
			StreamWriter streamWriter = new StreamWriter(path);
			streamWriter.WriteLine(json);
			streamWriter.Close();
		}
	}
	public static class DiffCalcGlobals
	{
		public static Chart selectedChart;

		public static Action<Chart> OnSelectedChartSetEvent;
	}
	public struct Note
	{
		public int count;

		public float pitchStart;

		public float pitchDelta;

		public float pitchEnd;

		public float position;

		public float length;

		public bool isSlider;

		public Note(int count, float position, float length, float pitchStart, float pitchDelta, float pitchEnd, bool isSlider)
		{
			this.count = count;
			this.position = position;
			this.length = length;
			this.pitchStart = pitchStart;
			this.pitchDelta = pitchDelta;
			this.pitchEnd = pitchEnd;
			this.isSlider = isSlider;
		}
	}
	[BepInPlugin("TootTallyDiffCalcLibs", "TootTallyDiffCalcLibs", "1.0.7")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin, ITootTallyModule
	{
		public static class DiffCalcPatches
		{
			private static CancellationTokenSource _cancellationToken;

			private static string _lastTrackref;

			[HarmonyPatch(typeof(LoadController), "Start")]
			[HarmonyPostfix]
			public static void ProcessChartBackup()
			{
				if (!(DiffCalcGlobals.selectedChart.trackRef == GlobalVariables.chosen_track_data.trackref))
				{
					string path = GetSongTMBPath(GlobalVariables.chosen_track_data.trackref);
					_cancellationToken?.Cancel();
					_cancellationToken = new CancellationTokenSource();
					bool isBaseGame = path == GlobalVariables.chosen_track_data.trackref;
					Task.Run(delegate
					{
						ProcessChart(path, isBaseGame, _cancellationToken);
					}, _cancellationToken.Token);
				}
			}

			[HarmonyPatch(typeof(LevelSelectController), "advanceSongs")]
			[HarmonyPostfix]
			public static void OnSongChangeProcessChartAsync(List<SingleTrackData> ___alltrackslist, int ___songindex)
			{
				string trackref = ___alltrackslist[___songindex].trackref;
				if (DiffCalcGlobals.selectedChart.trackRef == trackref || _lastTrackref == trackref)
				{
					LogInfo(DiffCalcGlobals.selectedChart.trackRef + " - " + trackref + " - trackref was the same.");
					return;
				}
				string path = GetSongTMBPath(trackref);
				_lastTrackref = trackref;
				_cancellationToken?.Cancel();
				_cancellationToken = new CancellationTokenSource();
				bool isBaseGame = path == trackref;
				Task.Run(delegate
				{
					ProcessChart(path, isBaseGame, _cancellationToken);
				}, _cancellationToken.Token);
			}

			[HarmonyPatch(typeof(LevelSelectController), "Start")]
			[HarmonyPostfix]
			public static void ProcessFirstChart(List<SingleTrackData> ___alltrackslist, int ___songindex)
			{
				OnSongChangeProcessChartAsync(___alltrackslist, ___songindex);
			}

			private static async void ProcessChart(string path, bool isBaseGame, CancellationTokenSource source)
			{
				if (isBaseGame)
				{
					LogInfo("Trying to get base game chart: " + path);
				}
				Chart chart = (isBaseGame ? ChartReader.LoadBaseGame(path) : ChartReader.LoadChart(path));
				if (source.IsCancellationRequested)
				{
					LogInfo("Disposing of " + chart.shortName);
					chart.Dispose();
					return;
				}
				LogInfo($"Song {chart.shortName} processed in {chart.calculationTime.TotalSeconds}s");
				DiffCalcGlobals.selectedChart.Dispose();
				DiffCalcGlobals.selectedChart = chart;
				DiffCalcGlobals.OnSelectedChartSetEvent?.Invoke(chart);
				_cancellationToken = null;
				await Task.Yield();
			}

			public static string GetSongTMBPath(string trackref)
			{
				TromboneTrack val = TrackLookup.lookup(trackref);
				CustomTrack val2 = (CustomTrack)(object)((val is CustomTrack) ? val : null);
				if (val2 != null)
				{
					string text = val2.folderPath + "/song.tmb";
					if (File.Exists(text))
					{
						return text;
					}
				}
				return trackref;
			}
		}

		public static Plugin Instance;

		private const string CONFIG_NAME = "TootTallyDiffCalcLibs.cfg";

		private Harmony _harmony;

		public ConfigEntry<bool> ModuleConfigEnabled { get; set; }

		public bool IsConfigInitialized { get; set; }

		public string Name
		{
			get
			{
				return "TootTallyDiffCalcLibs";
			}
			set
			{
				Name = value;
			}
		}

		public static void LogInfo(string msg)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
		}

		public static void LogError(string msg)
		{
			((BaseUnityPlugin)Instance).Logger.LogError((object)msg);
		}

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				Instance = this;
				_harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				GameInitializationEvent.Register(((BaseUnityPlugin)this).Info, (Action)TryInitialize);
			}
		}

		private void TryInitialize()
		{
			ModuleConfigEnabled = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Modules", "DiffCalcLibs", true, "Library to locally calculate the difficulty of charts.");
			TootTallyModuleManager.AddModule((ITootTallyModule)(object)this);
		}

		public void LoadModule()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			string text = Path.Combine(Paths.BepInExRootPath, "config/");
			ConfigFile val = new ConfigFile(text + "TootTallyDiffCalcLibs.cfg", true)
			{
				SaveOnConfigSet = true
			};
			_harmony.PatchAll(typeof(DiffCalcPatches));
			LogInfo("Module loaded!");
		}

		public void UnloadModule()
		{
			_harmony.UnpatchSelf();
			LogInfo("Module unloaded!");
		}
	}
	public static class Utils
	{
		public static readonly float[] GAME_SPEED = new float[7] { 0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f };

		public static readonly Dictionary<float, float> accToMultDict = new Dictionary<float, float>
		{
			{ 1f, 40.2f },
			{ 0.999f, 32.4f },
			{ 0.996f, 27.2f },
			{ 0.993f, 23.2f },
			{ 0.99f, 20.5f },
			{ 0.985f, 18.1f },
			{ 0.98f, 16.1f },
			{ 0.97f, 13.8f },
			{ 0.96f, 11.8f },
			{ 0.95f, 10.8f },
			{ 0.925f, 9.2f },
			{ 0.9f, 8.2f },
			{ 0.875f, 7.5f },
			{ 0.85f, 7f },
			{ 0.8f, 6f },
			{ 0.7f, 4f },
			{ 0.6f, 2.2f },
			{ 0.5f, 0.65f },
			{ 0.25f, 0.2f },
			{ 0f, 0f }
		};

		public static readonly Dictionary<float, float> ezAccToMultDict = new Dictionary<float, float>
		{
			{ 1f, 15.4f },
			{ 0.999f, 12.6f },
			{ 0.996f, 11.6f },
			{ 0.993f, 11f },
			{ 0.99f, 10.6f },
			{ 0.985f, 10f },
			{ 0.98f, 9.6f },
			{ 0.97f, 9f },
			{ 0.96f, 8.6f },
			{ 0.95f, 8.3f },
			{ 0.925f, 7.6f },
			{ 0.9f, 6.8f },
			{ 0.875f, 6.2f },
			{ 0.85f, 5.6f },
			{ 0.8f, 4.6f },
			{ 0.7f, 2.5f },
			{ 0.6f, 1.12f },
			{ 0.5f, 0.22f },
			{ 0.25f, 0.03f },
			{ 0f, 0f }
		};

		public static float Lerp(float firstFloat, float secondFloat, float by)
		{
			return firstFloat + (secondFloat - firstFloat) * by;
		}

		public static float FastPow(double num, int exp)
		{
			double num2 = 1.0;
			while (exp > 0)
			{
				if (exp % 2 == 1)
				{
					num2 *= num;
				}
				exp >>= 1;
				num *= num;
			}
			return (float)num2;
		}

		public static float CalculateBaseTT(float starRating)
		{
			return 0.5f * FastPow(starRating, 2) + 7f * starRating + 0.05f;
		}

		public static float CalculateScoreTT(Chart chart, float replaySpeed, int hitCount, int noteCount, float percent, string[] modifiers = null)
		{
			return CalculateBaseTT(chart.GetDynamicDiffRating(replaySpeed, (float)hitCount / (float)noteCount, modifiers)) * GetMultiplier(percent, modifiers);
		}

		public static float CalculateScoreTT(float[] diffRatings, float replaySpeed, float percent, string[] modifiers = null)
		{
			return CalculateBaseTT(LerpDiff(diffRatings, replaySpeed)) * GetMultiplier(percent, modifiers);
		}

		public static float GetMultiplier(float percent, string[] modifiers = null)
		{
			Dictionary<float, float> dictionary = ((modifiers != null && modifiers.Contains("EZ")) ? ezAccToMultDict : accToMultDict);
			int i;
			for (i = 1; i < dictionary.Count && dictionary.Keys.ElementAt(i) > percent; i++)
			{
			}
			float num = dictionary.Keys.ElementAt(i);
			float num2 = dictionary.Keys.ElementAt(i - 1);
			float by = (percent - num2) / (num - num2);
			return Lerp(dictionary[num2], dictionary[num], by);
		}

		public static float LerpDiff(float[] diffRatings, float speed)
		{
			int num = (int)((speed - 0.5f) / 0.25f);
			if (speed % 0.25f == 0f)
			{
				return diffRatings[num];
			}
			float num2 = GAME_SPEED[num];
			float num3 = GAME_SPEED[num + 1];
			float by = (speed - num2) / (num3 - num2);
			return Lerp(diffRatings[num], diffRatings[num + 1], by);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "TootTallyDiffCalcLibs";

		public const string PLUGIN_NAME = "TootTallyDiffCalcLibs";

		public const string PLUGIN_VERSION = "1.0.7";
	}
}