using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Infoholic.MonoBehaviours;
using Microsoft.CodeAnalysis;
using ReadableNumbers.Formatters;
using ReadableNumbers.Patches.Compatibility;
using TabInfo.Utils;
using UnboundLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.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 ReadableNumbers
{
[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.aalund13.rounds.readable_numbers", "Readable Numbers", "1.1.0")]
[BepInProcess("Rounds.exe")]
public class ReadableNumbers : BaseUnityPlugin
{
internal const string modId = "com.aalund13.rounds.readable_numbers";
internal const string ModName = "Readable Numbers";
internal const string modInitials = "RN";
internal static ReadableNumbers instance;
internal static AssetBundle assets;
internal static ManualLogSource ModLogger { get; private set; }
internal static Harmony Harmony { get; private set; }
private void Awake()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
instance = this;
ModLogger = ((BaseUnityPlugin)this).Logger;
Harmony = new Harmony("com.aalund13.rounds.readable_numbers");
Harmony.PatchAll();
((Component)this).gameObject.AddComponent<NumberDisplayController>();
List<BaseUnityPlugin> obj = (List<BaseUnityPlugin>)typeof(Chainloader).GetField("_plugins", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
if (obj.Exists((BaseUnityPlugin plugin) => plugin.Info.Metadata.GUID == "com.penial.rounds.Infoholic"))
{
InfoholicGameStatusUpdatePatch.Patch(Harmony);
}
if (obj.Exists((BaseUnityPlugin plugin) => plugin.Info.Metadata.GUID == "Systems.R00t.RSUI"))
{
RootStatUIStatDesplyerPatch.Patch(Harmony);
}
Unbound.RegisterClientSideMod("com.aalund13.rounds.readable_numbers");
Debug.Log("Readable Numbers loaded!");
}
private void Start()
{
Debug.Log("Readable Numbers started!");
if (((List<BaseUnityPlugin>)typeof(Chainloader).GetField("_plugins", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null)).Exists((BaseUnityPlugin plugin) => plugin.Info.Metadata.GUID == "com.willuwontu.rounds.tabinfo"))
{
ExtensionMethods.ExecuteAfterFrames((MonoBehaviour)(object)this, 5, (Action)delegate
{
TabInfoManagerPatch.PatchAllDisplayValue(Harmony);
});
}
}
}
public enum DisplayType
{
None,
Name,
Suffix
}
public interface INumberFormatter
{
string DisplayNumber(float number, DisplayType displayType, string format = null);
string DisplayNumber(int number, DisplayType displayType, string format = null);
}
public class NumberDisplayController : MonoBehaviour
{
private static DisplayType currentDisplayType = DisplayType.Suffix;
public static bool isDisable { get; private set; } = false;
public static DisplayType CurrentDisplayType
{
get
{
if (isDisable)
{
return DisplayType.None;
}
return currentDisplayType;
}
}
public void Update()
{
if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)105))
{
CycleDisplayType();
}
if (Input.GetKeyDown((KeyCode)305))
{
isDisable = true;
}
else if (Input.GetKeyUp((KeyCode)305))
{
isDisable = false;
}
}
private void CycleDisplayType()
{
switch (currentDisplayType)
{
case DisplayType.Suffix:
currentDisplayType = DisplayType.Name;
break;
case DisplayType.Name:
currentDisplayType = DisplayType.Suffix;
break;
default:
currentDisplayType = DisplayType.Suffix;
break;
}
}
public static string DisplayNumber(float number, string format = null)
{
return NumberFormatters.NormalNumberFormatter.DisplayNumber(number, CurrentDisplayType, format);
}
public static string DisplayNumber(int number, string format = null)
{
return NumberFormatters.NormalNumberFormatter.DisplayNumber(number, CurrentDisplayType, format);
}
public static string DisplayTime(float time, string format = null)
{
return NumberFormatters.TimeNumberFormatter.DisplayNumber(time, CurrentDisplayType, format);
}
public static string DisplayTime(int seconds, string format = null)
{
return NumberFormatters.TimeNumberFormatter.DisplayNumber(seconds, CurrentDisplayType, format);
}
}
public static class NumberFormatters
{
public static readonly TimeNumberFormatter TimeNumberFormatter = new TimeNumberFormatter();
public static readonly NormalNumberFormatter NormalNumberFormatter = new NormalNumberFormatter();
}
}
namespace ReadableNumbers.Patches.Compatibility
{
internal class InfoholicGameStatusUpdatePatch
{
public static Regex Regex = new Regex("\\{\\d+:([^}]+)\\}");
public static void Patch(Harmony harmony)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(GameStatusUpdate), "Update", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(InfoholicGameStatusUpdatePatch), "Transpiler", (Type[])null, (Type[])null);
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null);
}
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_040d: Unknown result type (might be due to invalid IL or missing references)
//IL_0417: Expected O, but got Unknown
//IL_0454: Unknown result type (might be due to invalid IL or missing references)
//IL_045e: Expected O, but got Unknown
//IL_042b: Unknown result type (might be due to invalid IL or missing references)
//IL_0435: Expected O, but got Unknown
//IL_0472: Unknown result type (might be due to invalid IL or missing references)
//IL_047c: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
MethodInfo methodInfo = AccessTools.Method(typeof(string), "Format", new Type[2]
{
typeof(string),
typeof(object)
}, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(string), "Format", new Type[3]
{
typeof(string),
typeof(object),
typeof(object)
}, (Type[])null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(string), "Format", new Type[4]
{
typeof(string),
typeof(object),
typeof(object),
typeof(object)
}, (Type[])null);
MethodInfo methodInfo4 = AccessTools.Method(typeof(NumberDisplayController), "DisplayNumber", new Type[2]
{
typeof(float),
typeof(string)
}, (Type[])null);
MethodInfo methodInfo5 = AccessTools.Method(typeof(NumberDisplayController), "DisplayNumber", new Type[2]
{
typeof(int),
typeof(string)
}, (Type[])null);
MethodInfo methodInfo6 = AccessTools.Method(typeof(NumberDisplayController), "DisplayTime", new Type[2]
{
typeof(float),
typeof(string)
}, (Type[])null);
MethodInfo methodInfo7 = AccessTools.Method(typeof(NumberDisplayController), "DisplayTime", new Type[2]
{
typeof(int),
typeof(string)
}, (Type[])null);
List<int> list2 = new List<int>();
for (int num = list.Count - 1; num >= 0; num--)
{
if (CodeInstructionExtensions.Calls(list[num], methodInfo) || CodeInstructionExtensions.Calls(list[num], methodInfo2) || CodeInstructionExtensions.Calls(list[num], methodInfo3))
{
list2.Add(num);
}
}
foreach (int item in list2)
{
int num2 = 0;
CodeInstruction val = list[item];
if (CodeInstructionExtensions.Calls(val, methodInfo))
{
num2 = 1;
}
else if (CodeInstructionExtensions.Calls(val, methodInfo2))
{
num2 = 2;
}
else if (CodeInstructionExtensions.Calls(val, methodInfo3))
{
num2 = 3;
}
ReadableNumbers.ModLogger.LogInfo((object)$"Found string.Format call at index {item} with {num2} argument(s)");
string text = "";
bool flag = false;
for (int num3 = item - 1; num3 >= 0; num3--)
{
if (list[num3].opcode == OpCodes.Ldstr && list[num3 + 1].opcode == OpCodes.Ldarg_1)
{
text = list[num3].operand.ToString();
if (text.EndsWith("s", StringComparison.OrdinalIgnoreCase))
{
list[num3].operand = text.Substring(0, text.Length - 1);
flag = true;
}
ReadableNumbers.ModLogger.LogInfo((object)("Format: " + list[num3].operand.ToString()));
break;
}
}
bool flag2 = false;
if (text.StartsWith("DMG: ") || text.StartsWith("HP: "))
{
flag2 = true;
}
string[] array = (from Match m in Regex.Matches(text)
select m.Groups[1].Value).ToArray();
int num4 = 0;
int num5 = item - 1;
while (num5 >= item - num2 * 5 && num5 >= 0)
{
if (list[num5].opcode == OpCodes.Box)
{
Type type = list[num5].operand as Type;
string text2 = ((array.Length > num4 && !flag2) ? array[num4] : "");
if (type == typeof(float))
{
list[num5] = new CodeInstruction(OpCodes.Ldstr, (object)text2);
list.Insert(num5 + 1, new CodeInstruction(OpCodes.Call, (object)(flag ? methodInfo6 : methodInfo4)));
}
else if (type == typeof(int))
{
list[num5] = new CodeInstruction(OpCodes.Ldstr, (object)text2);
list.Insert(num5 + 1, new CodeInstruction(OpCodes.Call, (object)(flag ? methodInfo7 : methodInfo5)));
}
num4++;
}
num5--;
}
}
return list.AsEnumerable();
}
}
public class RootStatUIStatDesplyerPatch
{
public static void Patch(Harmony harmony)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(StatDesplyer), "Format", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(RootStatUIStatDesplyerPatch), "FormatPrefix", (Type[])null, (Type[])null);
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
public static bool FormatPrefix(ref string __result, float value)
{
if (!NumberDisplayController.isDisable)
{
__result = NumberFormatters.NormalNumberFormatter.DisplayNumber(value, DisplayType.Suffix);
}
return NumberDisplayController.isDisable;
}
}
public class TabInfoManagerPatch
{
public static Regex Regex = new Regex("\\{\\d+:([^}]+)\\}");
public static void PatchAllDisplayValue(Harmony harmony)
{
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
foreach (StatCategory value in TabInfoManager.Categories.Values)
{
foreach (Stat value2 in value.Stats.Values)
{
Func<Player, string> displayValue = value2.displayValue;
MethodInfo method = displayValue.Method;
if (value2.name == "Damage")
{
value2.displayValue = (Player player) => NumberDisplayController.DisplayNumber(float.Parse(displayValue(player)));
continue;
}
if (value2.name == "HP")
{
value2.displayValue = (Player player) => NumberDisplayController.DisplayNumber(player.data.health) + "/" + NumberDisplayController.DisplayNumber(player.data.maxHealth);
continue;
}
MethodInfo methodInfo = AccessTools.Method(typeof(TabInfoManagerPatch), "PatchTranspiler", (Type[])null, (Type[])null);
harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null);
ReadableNumbers.ModLogger.LogInfo((object)("Patched the \"" + value2.name + "\" display value method from the \"" + value.name + "\" category"));
}
}
}
public static IEnumerable<CodeInstruction> PatchTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
//IL_03f1: Expected O, but got Unknown
//IL_042e: Unknown result type (might be due to invalid IL or missing references)
//IL_0438: Expected O, but got Unknown
//IL_0405: Unknown result type (might be due to invalid IL or missing references)
//IL_040f: Expected O, but got Unknown
//IL_044c: Unknown result type (might be due to invalid IL or missing references)
//IL_0456: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
MethodInfo methodInfo = AccessTools.Method(typeof(string), "Format", new Type[2]
{
typeof(string),
typeof(object)
}, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(string), "Format", new Type[3]
{
typeof(string),
typeof(object),
typeof(object)
}, (Type[])null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(string), "Format", new Type[4]
{
typeof(string),
typeof(object),
typeof(object),
typeof(object)
}, (Type[])null);
MethodInfo methodInfo4 = AccessTools.Method(typeof(NumberDisplayController), "DisplayNumber", new Type[2]
{
typeof(float),
typeof(string)
}, (Type[])null);
MethodInfo methodInfo5 = AccessTools.Method(typeof(NumberDisplayController), "DisplayNumber", new Type[2]
{
typeof(int),
typeof(string)
}, (Type[])null);
MethodInfo methodInfo6 = AccessTools.Method(typeof(NumberDisplayController), "DisplayTime", new Type[2]
{
typeof(float),
typeof(string)
}, (Type[])null);
MethodInfo methodInfo7 = AccessTools.Method(typeof(NumberDisplayController), "DisplayTime", new Type[2]
{
typeof(int),
typeof(string)
}, (Type[])null);
List<int> list2 = new List<int>();
for (int num = list.Count - 1; num >= 0; num--)
{
if (CodeInstructionExtensions.Calls(list[num], methodInfo) || CodeInstructionExtensions.Calls(list[num], methodInfo2) || CodeInstructionExtensions.Calls(list[num], methodInfo3))
{
list2.Add(num);
}
}
foreach (int item in list2)
{
int num2 = 0;
CodeInstruction val = list[item];
if (CodeInstructionExtensions.Calls(val, methodInfo))
{
num2 = 1;
}
else if (CodeInstructionExtensions.Calls(val, methodInfo2))
{
num2 = 2;
}
else if (CodeInstructionExtensions.Calls(val, methodInfo3))
{
num2 = 3;
}
ReadableNumbers.ModLogger.LogInfo((object)$"Found string.Format call at index {item} with {num2} argument(s)");
string text = "";
bool flag = false;
for (int num3 = item - 1; num3 >= 0; num3--)
{
if (list[num3].opcode == OpCodes.Ldstr && list[num3 + 1].opcode == OpCodes.Ldarg_1)
{
text = list[num3].operand.ToString();
if (text.EndsWith("s", StringComparison.OrdinalIgnoreCase))
{
list[num3].operand = text.Substring(0, text.Length - 1);
flag = true;
}
ReadableNumbers.ModLogger.LogInfo((object)("Format: " + list[num3].operand.ToString()));
break;
}
}
string[] array = (from Match m in Regex.Matches(text)
select m.Groups[1].Value).ToArray();
int num4 = 0;
int num5 = item - 1;
while (num5 >= item - num2 * 5 && num5 >= 0)
{
if (list[num5].opcode == OpCodes.Box)
{
Type type = list[num5].operand as Type;
string text2 = ((array.Length > num4) ? array[num4] : "");
if (type == typeof(float))
{
list[num5] = new CodeInstruction(OpCodes.Ldstr, (object)text2);
list.Insert(num5 + 1, new CodeInstruction(OpCodes.Call, (object)(flag ? methodInfo6 : methodInfo4)));
}
else if (type == typeof(int))
{
list[num5] = new CodeInstruction(OpCodes.Ldstr, (object)text2);
list.Insert(num5 + 1, new CodeInstruction(OpCodes.Call, (object)(flag ? methodInfo7 : methodInfo5)));
}
num4++;
}
num5--;
}
}
return list.AsEnumerable();
}
}
}
namespace ReadableNumbers.Formatters
{
public struct NormalNumberSuffix
{
public string Suffix { get; private set; }
public string Name { get; private set; }
public NormalNumberSuffix(string suffix, string name)
{
Suffix = suffix;
Name = name;
}
}
public class NormalNumberFormatter : INumberFormatter
{
public readonly NormalNumberSuffix[] suffixes = new NormalNumberSuffix[12]
{
new NormalNumberSuffix("K", "Thousand"),
new NormalNumberSuffix("M", "Million"),
new NormalNumberSuffix("B", "Billion"),
new NormalNumberSuffix("T", "Trillion"),
new NormalNumberSuffix("Qa", "Quadrillion"),
new NormalNumberSuffix("Qi", "Quintillion"),
new NormalNumberSuffix("Sx", "Sextillion"),
new NormalNumberSuffix("Sp", "Septillion"),
new NormalNumberSuffix("Oc", "Octillion"),
new NormalNumberSuffix("No", "Nonillion"),
new NormalNumberSuffix("Dc", "Decillion"),
new NormalNumberSuffix("Ud", "Undecillion")
};
public string DisplayNumber(float number, DisplayType displayType, string format = null)
{
bool flag = number < 0f;
float num = Mathf.Abs(number);
if (num == 0f)
{
if (format == null)
{
return number.ToString();
}
return number.ToString(format);
}
int num2 = Mathf.FloorToInt(Mathf.Log10(num) / 3f);
float num3 = num / Mathf.Pow(10f, (float)(num2 * 3));
int num4 = 1 + Mathf.FloorToInt(Mathf.Log10(num3));
int num5 = (int)Mathf.Pow(10f, (float)(4 - num4));
num3 = Mathf.Floor(num3 * (float)num5) / (float)num5;
string text = ((format != null) ? num3.ToString(format) : num3.ToString());
string text2 = ((format != null) ? num.ToString(format) : num.ToString());
if (flag)
{
text = "-" + text;
text2 = "-" + text2;
}
if (num2 <= 0)
{
return number.ToString("0." + new string('#', Mathf.Max(0, 4 - num4)), CultureInfo.InvariantCulture);
}
return displayType switch
{
DisplayType.None => number.ToString("0.##", CultureInfo.InvariantCulture),
DisplayType.Name => text + " " + suffixes[num2 - 1].Name,
_ => text + suffixes[num2 - 1].Suffix,
};
}
public string DisplayNumber(int number, DisplayType displayType, string format = null)
{
return DisplayNumber((float)number, displayType, (string)null);
}
}
public struct TimeNumberSuffix
{
public float Unit { get; private set; }
public string Suffix { get; private set; }
public string Name { get; private set; }
public TimeNumberSuffix(float unit, string suffix, string name)
{
Unit = unit;
Suffix = suffix;
Name = name;
}
}
public class TimeNumberFormatter : INumberFormatter
{
public readonly TimeNumberSuffix[] Suffixes = new TimeNumberSuffix[6]
{
new TimeNumberSuffix(0.001f, "ms", "Millisecond"),
new TimeNumberSuffix(1f, "s", "Second"),
new TimeNumberSuffix(60f, "min", "Minute"),
new TimeNumberSuffix(3600f, "h", "Hour"),
new TimeNumberSuffix(86400f, "d", "Day"),
new TimeNumberSuffix(604800f, "wk", "Week")
};
public string DisplayNumber(float number, DisplayType displayType, string format = null)
{
if (number <= 0f)
{
return displayType switch
{
DisplayType.Suffix => "0ms",
DisplayType.Name => "0 Milliseconds",
_ => "0",
};
}
int num = 0;
for (int num2 = Suffixes.Length - 1; num2 >= 0; num2--)
{
if (number >= Suffixes[num2].Unit)
{
num = num2;
break;
}
}
float num3 = number / Suffixes[num].Unit;
TimeNumberSuffix timeNumberSuffix = Suffixes[num];
string text = (string.IsNullOrEmpty(format) ? "0.##" : format);
string text2 = num3.ToString(text);
switch (displayType)
{
case DisplayType.None:
return text2;
case DisplayType.Suffix:
return text2 + timeNumberSuffix.Suffix;
case DisplayType.Name:
{
string text3 = ((num3 == 1f) ? timeNumberSuffix.Name : (timeNumberSuffix.Name + "s"));
return text2 + " " + text3;
}
default:
return text2;
}
}
public string DisplayNumber(int number, DisplayType displayType, string format = null)
{
return DisplayNumber((float)number, displayType, format);
}
}
}