using System; using System.Collections.Concurrent; 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 System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("kossnikita")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.3.0")] [assembly: AssemblyInformationalVersion("1.2.3+f62ca6acd693a1a39864d73f984689ce94e252a9")] [assembly: AssemblyProduct("kztCurrency")] [assembly: AssemblyTitle("kztCurrency")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.3.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 kztCurrency { public static class CurrencyFormatter { private static class RegexCache { public static readonly Regex GroupingChars = new Regex("[ \\u00A0\\.,]", RegexOptions.Compiled); public static readonly Regex GroupingCharsExtended = new Regex("[ \\u00A0\\u202F,\\u2009]", RegexOptions.Compiled); public static readonly Regex NonDigits = new Regex("[^0-9-]", RegexOptions.Compiled); } private const string Nbsp = "\u00a0"; public static readonly string NBSP = "\u00a0"; private static readonly NumberFormatInfo NbspNumberFormat = new NumberFormatInfo { NumberGroupSeparator = "\u00a0", NumberDecimalSeparator = ".", NumberGroupSizes = new int[1] { 3 } }; private static readonly ConcurrentDictionary LastLoggedOutputs = new ConcurrentDictionary(); private static string ApplyTemplate(string template, string formattedValue) { if (string.IsNullOrEmpty(template)) { return formattedValue; } return template.Replace("{value}", formattedValue); } private static void LogFormatCall(string methodName, string input, string output) { try { string text = output ?? string.Empty; if (!LastLoggedOutputs.TryGetValue(methodName, out var value) || !(value == text)) { LastLoggedOutputs[methodName] = text; } } catch (Exception ex) { try { Plugin.Logger.LogWarning((object)("[Formatting] " + methodName + " logging failed: " + ex.Message)); } catch { } } } public static string FormatPlayerUI(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_PlayerUI ?? new Plugin.TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (RegexCache.GroupingChars.IsMatch(value ?? "") ? Math.Max(0L, value2) : (Math.Max(0L, value2) * 1000)).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_PlayerUI ?? templateInfo.Template) : templateInfo.Template, text); } string text2 = FormatNumber(value); return ApplyTemplate((text2 == "0") ? (Plugin.TemplateZero_PlayerUI ?? templateInfo.Template) : templateInfo.Template, text2); } public static string FormatPlayerUICurrency(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_PlayerUI ?? new Plugin.TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false); bool flag = !string.IsNullOrEmpty(value) && value.Contains('.'); bool flag2 = RegexCache.GroupingCharsExtended.IsMatch(value ?? ""); if (templateInfo.MultiplyBy1000 && (flag || flag2)) { if (long.TryParse(RegexCache.NonDigits.Replace(value ?? "", ""), out var result)) { string text = Math.Max(0L, result).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_PlayerUI ?? templateInfo.Template) : templateInfo.Template, text); } string text2 = (value ?? string.Empty).Replace('.', '\u00a0'); return ApplyTemplate((text2 == "0") ? (Plugin.TemplateZero_PlayerUI ?? templateInfo.Template) : templateInfo.Template, text2); } string text3 = FormatNumber(value); return ApplyTemplate((text3 == "0") ? (Plugin.TemplateZero_PlayerUI ?? templateInfo.Template) : templateInfo.Template, text3); } public static string FormatShopCost(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_ItemCost ?? new Plugin.TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (RegexCache.GroupingChars.IsMatch(value ?? "") ? Math.Max(0L, value2) : (Math.Max(0L, value2) * 1000)).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_ItemCost ?? templateInfo.Template) : templateInfo.Template, text); } string text2 = FormatNumber(value); return ApplyTemplate((text2 == "0") ? (Plugin.TemplateZero_ItemCost ?? templateInfo.Template) : templateInfo.Template, text2); } public static string FormatItemCost(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_ItemCost ?? new Plugin.TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (RegexCache.GroupingChars.IsMatch(value ?? "") ? Math.Max(0L, value2) : (Math.Max(0L, value2) * 1000)).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_ItemCost ?? templateInfo.Template) : templateInfo.Template, text); } string text2 = FormatNumber(value); return ApplyTemplate((text2 == "0") ? (Plugin.TemplateZero_ItemCost ?? templateInfo.Template) : templateInfo.Template, text2); } public static string FormatItemCost(int thousands) { Plugin.TemplateInfo templateInfo = Plugin.Template_ItemCost ?? new Plugin.TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false); if (templateInfo.MultiplyBy1000) { int num = thousands * 1000; return templateInfo.Template.Replace("{value}", num.ToString("N0", NbspNumberFormat)); } return ((thousands == 0) ? (Plugin.TemplateZero_ItemCost ?? templateInfo.Template) : templateInfo.Template).Replace("{value}", thousands.ToString()); } public static string FormatItemValue(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_ItemCost ?? new Plugin.TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (RegexCache.GroupingChars.IsMatch(value ?? "") ? Math.Max(0L, value2) : (Math.Max(0L, value2) * 1000)).ToString("N0", NbspNumberFormat); string text2 = ApplyTemplate((text == "0") ? (Plugin.TemplateZero_ItemPickup ?? templateInfo.Template) : templateInfo.Template, text); LogFormatCall("FormatItemValue(string)", value, text2); return text2; } string text3 = FormatNumber(value); string text4 = ApplyTemplate((text3 == "0") ? (Plugin.TemplateZero_ItemPickup ?? templateInfo.Template) : templateInfo.Template, text3); LogFormatCall("FormatItemValue(string)", value, text4); return text4; } public static string FormatItemValue(int units) { Plugin.TemplateInfo templateInfo = Plugin.Template_ItemCost ?? new Plugin.TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false); if (units < 1000) { string text = units + "\u00a0₸"; LogFormatCall("FormatItemValue(int)", units.ToString(), text); return text; } if (templateInfo.MultiplyBy1000) { string text2 = templateInfo.Template.Replace("{value}", units.ToString("N0", NbspNumberFormat)); LogFormatCall("FormatItemValue(int)", units.ToString(), text2); return text2; } int num = units / 1000; string text3 = templateInfo.Template.Replace("{value}", num.ToString()); LogFormatCall("FormatItemValue(int)", units.ToString(), text3); return text3; } public static string FormatBlackbox(long units) { string text = Math.Max(0L, units).ToString("N0", NbspNumberFormat) + "\u00a0₸"; LogFormatCall("FormatBlackbox", units.ToString(), text); return text; } public static string FormatBlackboxDigits(long units) { return Math.Max(0L, units).ToString("N0", NbspNumberFormat); } public static string FormatShoppingListDigits(long units) { string text = Math.Max(0L, units).ToString("N0", NbspNumberFormat); LogFormatCall("FormatShoppingListDigits", units.ToString(), text); return text; } public static string FormatShoppingListUI(long units) { string text = Math.Max(0L, units).ToString("N0", NbspNumberFormat) + "\u00a0₸"; LogFormatCall("FormatShoppingListUI", units.ToString(), text); return text; } public static string FormatHaulUI(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_HaulUI ?? new Plugin.TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (Math.Max(0L, value2) * 1000).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_HaulUI ?? templateInfo.Template) : templateInfo.Template, text); } string text2 = FormatNumber(value); return ApplyTemplate((text2 == "0") ? (Plugin.TemplateZero_HaulUI ?? templateInfo.Template) : templateInfo.Template, text2); } public static string FormatHaulUI(int units) { Plugin.TemplateInfo templateInfo = Plugin.Template_HaulUI ?? new Plugin.TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false); string text = Math.Max(0, units).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_HaulUI ?? templateInfo.Template) : templateInfo.Template, text); } public static string FormatHaul(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_Haul ?? new Plugin.TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (Math.Max(0L, value2) * 1000).ToString("N0", NbspNumberFormat); string text2 = ApplyTemplate((text == "0") ? (Plugin.TemplateZero_Haul ?? templateInfo.Template) : templateInfo.Template, text); LogFormatCall("FormatHaul(string)", value, text2); return text2; } string text3 = FormatNumber(value); string text4 = ApplyTemplate((text3 == "0") ? (Plugin.TemplateZero_Haul ?? templateInfo.Template) : templateInfo.Template, text3); LogFormatCall("FormatHaul(string)", value, text4); return text4; } public static string FormatHaul(int units) { Plugin.TemplateInfo templateInfo = Plugin.Template_Haul ?? new Plugin.TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false); int num = Math.Max(0, units); string text2; if (templateInfo.MultiplyBy1000) { string text = num.ToString("N0", NbspNumberFormat); text2 = ApplyTemplate((text == "0") ? (Plugin.TemplateZero_Haul ?? templateInfo.Template) : templateInfo.Template, text); } else if (num < 1000) { string text3 = num.ToString(); text2 = ApplyTemplate((text3 == "0") ? (Plugin.TemplateZero_Haul ?? templateInfo.Template) : templateInfo.Template, text3); } else { double num2 = (double)num / 1000.0; string text4 = ((Math.Abs(num2 - Math.Truncate(num2)) < 0.001) ? ((int)Math.Truncate(num2)).ToString() : num2.ToString("0.#", CultureInfo.InvariantCulture)); text2 = ApplyTemplate((text4 == "0") ? (Plugin.TemplateZero_Haul ?? templateInfo.Template) : templateInfo.Template, text4); } LogFormatCall("FormatHaul(int)", units.ToString(), text2); return text2; } public static string FormatCart(string value) { Plugin.TemplateInfo templateInfo = Plugin.Template_Cart ?? new Plugin.TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false); if (templateInfo.MultiplyBy1000 && TryParseDigitsToLong(value, out var value2)) { string text = (RegexCache.GroupingChars.IsMatch(value ?? "") ? Math.Max(0L, value2) : (Math.Max(0L, value2) * 1000)).ToString("N0", NbspNumberFormat); return ApplyTemplate((text == "0") ? (Plugin.TemplateZero_Cart ?? templateInfo.Template) : templateInfo.Template, text); } string text2 = FormatNumber(value); return ApplyTemplate((text2 == "0") ? (Plugin.TemplateZero_Cart ?? templateInfo.Template) : templateInfo.Template, text2); } public static string FormatCart(int units) { Plugin.TemplateInfo templateInfo = Plugin.Template_Cart ?? new Plugin.TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false); int num = Math.Max(0, units); string text2; if (templateInfo.MultiplyBy1000) { string text = num.ToString("N0", NbspNumberFormat); text2 = ApplyTemplate((text == "0") ? (Plugin.TemplateZero_Cart ?? templateInfo.Template) : templateInfo.Template, text); } else if (num < 1000) { string formattedValue = num.ToString(); text2 = ApplyTemplate(Plugin.TemplateZero_Cart ?? "{value}\u00a0тг", formattedValue); } else { double num2 = (double)num / 1000.0; string text3 = ((Math.Abs(num2 - Math.Truncate(num2)) < 0.001) ? ((int)Math.Truncate(num2)).ToString() : num2.ToString("0.#", CultureInfo.InvariantCulture)); text2 = ApplyTemplate((text3 == "0") ? (Plugin.TemplateZero_Cart ?? templateInfo.Template) : templateInfo.Template, text3); } LogFormatCall("FormatCart(int)", units.ToString(), text2); return text2; } private static bool TryParseDigitsToLong(string raw, out long value) { value = 0L; if (string.IsNullOrWhiteSpace(raw)) { return false; } string text = RegexCache.NonDigits.Replace(raw, ""); if (string.IsNullOrEmpty(text)) { return false; } return long.TryParse(text, out value); } private static string FormatNumber(string raw) { if (string.IsNullOrWhiteSpace(raw)) { return raw ?? string.Empty; } string text = raw.Trim(); text = text.Replace("\u00a0", ""); text = text.Replace(" ", ""); if (long.TryParse(text, NumberStyles.Integer, NbspNumberFormat, out var result)) { return result.ToString("N0", NbspNumberFormat); } if (decimal.TryParse(text, NumberStyles.Number, NbspNumberFormat, out var result2)) { return result2.ToString("N2", NbspNumberFormat).TrimEnd('0').TrimEnd('.'); } return raw; } } [HarmonyPatch(typeof(HaulUI), "Update")] public class HaulUIPatch { private static string _lastOriginalText; private static string _lastProcessedText; [HarmonyPostfix] public static void UpdatePostfix(HaulUI __instance, TextMeshProUGUI ___Text) { if ((Object)(object)___Text == (Object)null) { return; } string text = ((TMP_Text)___Text).text; if (string.IsNullOrEmpty(text) || text == _lastProcessedText) { return; } try { int units = (((Object)(object)RoundDirector.instance != (Object)null) ? RoundDirector.instance.currentHaul : 0); int units2 = (((Object)(object)RoundDirector.instance != (Object)null) ? RoundDirector.instance.extractionHaulGoal : 0); string text2 = CurrencyFormatter.FormatHaulUI(units); string text3 = CurrencyFormatter.FormatHaulUI(units2); string text4 = "" + text2 + " / " + text3 + ""; _lastOriginalText = text; _lastProcessedText = text4; ((TMP_Text)___Text).text = text4; } catch { } } } [HarmonyPatch] public static class BlackboxInitWatcher { [HarmonyPostfix] [HarmonyPatch(typeof(GameObject), "AddComponent", new Type[] { typeof(Type) })] private static void AddComponent_Postfix(GameObject __instance, Type componentType, Component __result) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown try { if (componentType == null) { return; } string text = componentType.FullName ?? string.Empty; if (!((componentType.Name ?? string.Empty) == "Blackbox") && !text.EndsWith(".Blackbox") && !(text == "Blackbox")) { return; } ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)"[BlackboxInitWatcher] Detected Blackbox component added — applying runtime patches."); } try { if (BlackboxPatches.TryPatchNow(new Harmony("kztCurrency.blackbox"))) { ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogInfo((object)"[BlackboxInitWatcher] Blackbox patches applied successfully on AddComponent"); } } else { ManualLogSource logger3 = Plugin.Logger; if (logger3 != null) { logger3.LogDebug((object)"[BlackboxInitWatcher] Blackbox patches not applied (may already be patched or types not found)"); } } } catch (Exception arg) { ManualLogSource logger4 = Plugin.Logger; if (logger4 != null) { logger4.LogWarning((object)$"[BlackboxInitWatcher] Failed to apply Blackbox patches: {arg}"); } } } catch (Exception arg2) { ManualLogSource logger5 = Plugin.Logger; if (logger5 != null) { logger5.LogWarning((object)$"[BlackboxInitWatcher] unexpected error: {arg2}"); } } } } public static class BlackboxPatches { private static readonly Regex DollarNumberRegex = new Regex("\\$(?:<[^>]+>)*\\s*([0-9][0-9\\.,\\u00A0\\s]*)", RegexOptions.Compiled); internal static string Preview(string s, int max = 120) { if (s == null) { return ""; } if (s.Length > max) { return s.Substring(0, max) + "..."; } return s; } internal static string ReplaceDollarNumbers(string input) { if (string.IsNullOrEmpty(input)) { return input; } int replaced = 0; return DollarNumberRegex.Replace(input, delegate(Match m) { string value = m.Groups[1].Value; string text = Regex.Replace(value, "[^0-9]", ""); if (string.IsNullOrEmpty(text)) { return m.Value; } if (!long.TryParse(text, out var result)) { return m.Value; } string text2 = CurrencyFormatter.FormatBlackbox((int)Math.Min(result, 2147483647L)); string value2 = m.Groups[0].Value; int num = value2.IndexOf(value, StringComparison.Ordinal); if (num < 0) { replaced++; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)("[BlackboxPatches] Unexpected match structure, replacing whole '" + value2 + "' with '" + text2 + "'")); } return text2; } string text3 = value2.Substring(0, num); string text4 = string.Concat(str2: value2.Substring(num + value.Length), str0: text3.Replace("$", ""), str1: text2); replaced++; ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogDebug((object)("[BlackboxPatches] Replaced '" + value2 + "' -> '" + text4 + "' in preview: '" + Preview(input) + "'")); } return text4; }); } public static bool TryPatchNow(Harmony harmony) { int num = 0; try { Type[] array = new Type[3] { typeof(Blackbox_getPostRunStatString_Patch), typeof(ValuableEventTracker_getStatsByPlayerValueLost_Patch), typeof(ValuableEventTracker_getDetailedStatsByValueLost_Patch) }; foreach (Type type in array) { try { List list = harmony.CreateClassProcessor(type).Patch(); if (list != null && list.Count > 0) { num++; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)("[BlackboxPatches] Applied patch: " + type.Name)); } } } catch (Exception ex) { ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogDebug((object)("[BlackboxPatches] Could not apply " + type.Name + ": " + ex.Message)); } } } if (num > 0) { ManualLogSource logger3 = Plugin.Logger; if (logger3 != null) { logger3.LogInfo((object)$"[BlackboxPatches] Successfully applied {num} patch(es)"); } return true; } } catch (Exception arg) { ManualLogSource logger4 = Plugin.Logger; if (logger4 != null) { logger4.LogWarning((object)$"[BlackboxPatches] TryPatchNow failed: {arg}"); } } return false; } } [HarmonyPatch] internal class Blackbox_getPostRunStatString_Patch { private static bool Prepare() { bool flag = AccessTools.TypeByName("Blackbox") != null; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)$"[BlackboxPatches] Prepare Blackbox.getPostRunStatString: {flag}"); } return flag; } private static MethodBase TargetMethod() { return AccessTools.Method("Blackbox:getPostRunStatString", (Type[])null, (Type[])null); } private static void Postfix(ref string __result) { __result = BlackboxPatches.ReplaceDollarNumbers(__result); } } [HarmonyPatch] internal class ValuableEventTracker_getStatsByPlayerValueLost_Patch { private static bool Prepare() { bool flag = AccessTools.TypeByName("ValuableEventTracker") != null; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)$"[BlackboxPatches] Prepare ValuableEventTracker.getStatsByPlayerValueLost: {flag}"); } return flag; } private static MethodBase TargetMethod() { return AccessTools.Method("ValuableEventTracker:getStatsByPlayerValueLost", (Type[])null, (Type[])null); } private static void Postfix(ref string __result) { __result = BlackboxPatches.ReplaceDollarNumbers(__result); } } [HarmonyPatch] internal class ValuableEventTracker_getDetailedStatsByValueLost_Patch { private static bool Prepare() { bool flag = AccessTools.TypeByName("ValuableEventTracker") != null; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)$"[BlackboxPatches] Prepare ValuableEventTracker.getDetailedStatsByValueLost: {flag}"); } return flag; } private static MethodBase TargetMethod() { return AccessTools.Method("ValuableEventTracker:getDetailedStatsByValueLost", (Type[])null, (Type[])null); } private static void Postfix(ref Dictionary __result) { if (__result == null) { return; } foreach (string item in new List(__result.Keys)) { string text = BlackboxPatches.Preview(__result[item]); __result[item] = BlackboxPatches.ReplaceDollarNumbers(__result[item]); string text2 = BlackboxPatches.Preview(__result[item]); if (text != text2) { ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)("[BlackboxPatches] Replaced in key '" + item + "': '" + text + "' -> '" + text2 + "'")); } } } } } internal static class CurrencyUIHelper { public static int ParseThousandsToBase(string valueInThousands) { if (int.TryParse(Regex.Replace(valueInThousands ?? "", "[^0-9]", ""), out var result)) { return result * 1000; } return 0; } } [HarmonyPatch(typeof(CurrencyUI), "Update")] public class CurrencyUIPatch { private static TMP_FontAsset _cachedTengeFont; [HarmonyPostfix] public static void UpdatePostfix(CurrencyUI __instance, TextMeshProUGUI ___Text, ref float ___showTimer, ref int ___currentHaulValue) { if (!(___showTimer > 0f) || !((Object)(object)___Text != (Object)null)) { return; } string text = ((TMP_Text)___Text).text; if (text.StartsWith("$") && text.EndsWith("K")) { int units = CurrencyUIHelper.ParseThousandsToBase(text.Substring(1, text.Length - 2)); if (_cachedTengeFont == null) { _cachedTengeFont = TengeSymbolSupport.GetTengeFallbackFont(); } if ((Object)(object)_cachedTengeFont != (Object)null && (Object)(object)((TMP_Text)___Text).font != (Object)(object)_cachedTengeFont) { TengeSymbolSupport.SetPrimaryFont((TMP_Text)(object)___Text); } string text2 = CurrencyFormatter.FormatHaul(units); ((TMP_Text)___Text).text = text2; } } } [HarmonyPatch(typeof(CurrencyUI), "FetchCurrency")] public class CurrencyUIFetchCurrencyPatch { [HarmonyPostfix] public static void FetchCurrencyPostfix(CurrencyUI __instance, TextMeshProUGUI ___Text) { if ((Object)(object)___Text != (Object)null) { string text = ((TMP_Text)___Text).text; if (text.StartsWith("$") && text.EndsWith("K")) { int units = CurrencyUIHelper.ParseThousandsToBase(text.Substring(1, text.Length - 2)); TengeSymbolSupport.EnsureFallbackFont((TMP_Text)(object)___Text); ((TMP_Text)___Text).text = CurrencyFormatter.FormatHaul(units); } } } } [HarmonyPatch(typeof(ExtractionPoint))] internal class ExtractionPointPatch { private static readonly Regex TagRemoval = new Regex("<.*?>", RegexOptions.Compiled); [HarmonyPatch("SetHaulText")] [HarmonyPostfix] private static void SetHaulTextPostfix(ExtractionPoint __instance, int ___haulCurrent, bool ___isShop) { if ((Object)(object)__instance.haulGoalScreen == (Object)null) { return; } string text = ((TMP_Text)__instance.haulGoalScreen).text; if (string.IsNullOrEmpty(text) || text.Contains("₸") || text.Contains("тг") || text.Contains("KZT")) { return; } string text2 = TagRemoval.Replace(text, ""); if (text2.Contains("$")) { if (text.Contains("TAX")) { string text3 = text.Replace("$", "₸"); ((TMP_Text)__instance.haulGoalScreen).text = text3; return; } int num = ((!___isShop) ? ___haulCurrent : (__instance.haulGoal - ___haulCurrent)); bool flag = text2.TrimStart().StartsWith("-"); string text4 = CurrencyFormatter.FormatHaul(Math.Abs(num)); string text5 = ((!(num < 0 || flag)) ? text4 : ("-" + text4 + "")); ((TMP_Text)__instance.haulGoalScreen).text = text5; } } [HarmonyPatch("StateSuccess")] [HarmonyPostfix] private static void StateSuccessPostfix(ExtractionPoint __instance, int ___haulCurrent, bool ___isShop) { if ((Object)(object)__instance.haulGoalScreen == (Object)null) { return; } string text = ((TMP_Text)__instance.haulGoalScreen).text; if (!string.IsNullOrEmpty(text) && text.Contains("$") && !text.Contains("₸") && !text.Contains("тг") && !text.Contains("KZT")) { if (text.Contains("TAX")) { string text2 = text.Replace("$", "₸"); ((TMP_Text)__instance.haulGoalScreen).text = text2; return; } int units = Math.Max(0, __instance.haulGoal - ___haulCurrent); TagRemoval.Replace(text, "").TrimStart().StartsWith("-"); string text3 = CurrencyFormatter.FormatHaul(units); ((TMP_Text)__instance.haulGoalScreen).text = text3; } } [HarmonyPatch("StateSurplus")] [HarmonyPostfix] private static void StateSurplusPostfix(ExtractionPoint __instance) { if ((Object)(object)__instance.haulGoalScreen == (Object)null) { return; } string text = ((TMP_Text)__instance.haulGoalScreen).text; if (string.IsNullOrEmpty(text) || !text.Contains("$") || text.Contains("₸") || text.Contains("тг") || text.Contains("KZT")) { return; } string text2 = TagRemoval.Replace(text, ""); if (text.Contains("TAX")) { string text3 = text.Replace("$", "₸"); ((TMP_Text)__instance.haulGoalScreen).text = text3; return; } bool flag = text2.TrimStart().StartsWith("+"); bool flag2 = text2.TrimStart().StartsWith("-"); if (!int.TryParse(text2.Replace("+", "").Replace("-", "").Replace("$", "") .Replace(".", "") .Replace(" ", "") .Replace(",", ""), out var result)) { string text4 = text.Replace("$", "₸"); ((TMP_Text)__instance.haulGoalScreen).text = text4; return; } if (flag2 && result > 0) { result = -result; } string text5 = CurrencyFormatter.FormatHaul(Math.Abs(result)); string text6 = ((result < 0 || flag2) ? ("-" + text5 + "") : ((!flag) ? text5 : ("+" + text5))); ((TMP_Text)__instance.haulGoalScreen).text = text6; } } [HarmonyPatch(typeof(ValueScreen), "SetValueText")] internal class ValueScreenSetValueTextPatch { [HarmonyPostfix] private static void SetValueTextPostfix(ValueScreen __instance) { try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.displayText == (Object)null)) { TengeSymbolSupport.EnsureFallbackFont((TMP_Text)(object)__instance.displayText); int valueCurrent = __instance.valueCurrent; ((TMP_Text)__instance.displayText).text = CurrencyFormatter.FormatCart(valueCurrent); } } catch (Exception arg) { Debug.LogError((object)$"[ValueScreen] Exception in SetValueTextPostfix: {arg}"); } } } [HarmonyPatch(typeof(ShopCostUI), "Update")] public class ShopCostUIPatch { private static TMP_FontAsset _cachedTengeFont; [HarmonyPostfix] public static void UpdatePostfix(ShopCostUI __instance, TextMeshProUGUI ___Text) { if ((Object)(object)___Text != (Object)null && !string.IsNullOrEmpty(((TMP_Text)___Text).text)) { string text = ((TMP_Text)___Text).text; if (text.StartsWith("-$") && text.EndsWith("K")) { string value = text.Substring(2, text.Length - 3); ((TMP_Text)___Text).text = "-" + CurrencyFormatter.FormatShopCost(value); } else if (text.StartsWith("+$") && text.EndsWith("K")) { string value2 = text.Substring(2, text.Length - 3); ((TMP_Text)___Text).text = "+" + CurrencyFormatter.FormatShopCost(value2); } if (_cachedTengeFont == null) { _cachedTengeFont = TengeSymbolSupport.GetTengeFallbackFont(); } if ((Object)(object)_cachedTengeFont != (Object)null && (Object)(object)((TMP_Text)___Text).font != (Object)(object)_cachedTengeFont) { TengeSymbolSupport.SetPrimaryFont((TMP_Text)(object)___Text); } } } } [HarmonyPatch] public static class ShoppingListInitWatcher { [HarmonyPostfix] [HarmonyPatch(typeof(GameObject), "AddComponent", new Type[] { typeof(Type) })] private static void AddComponent_Postfix(GameObject __instance, Type componentType, Component __result) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown try { if (componentType == null) { return; } string text = componentType.FullName ?? string.Empty; if (!((componentType.Name ?? string.Empty) == "ShoppingListHUD") && !text.EndsWith(".ShoppingListHUD") && !(text == "ShoppingListHUD")) { return; } ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)"[ShoppingListInitWatcher] Detected ShoppingListHUD component added — applying runtime patches."); } try { if (ShoppingListPatches.TryPatchNow(new Harmony("kztCurrency.shoppinglist"))) { ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogInfo((object)"[ShoppingListInitWatcher] ShoppingList patches applied successfully on AddComponent"); } } else { ManualLogSource logger3 = Plugin.Logger; if (logger3 != null) { logger3.LogDebug((object)"[ShoppingListInitWatcher] ShoppingList patches not applied (may already be patched or types not found)"); } } } catch (Exception arg) { ManualLogSource logger4 = Plugin.Logger; if (logger4 != null) { logger4.LogWarning((object)$"[ShoppingListInitWatcher] Failed to apply ShoppingList patches: {arg}"); } } } catch (Exception arg2) { ManualLogSource logger5 = Plugin.Logger; if (logger5 != null) { logger5.LogWarning((object)$"[ShoppingListInitWatcher] unexpected error: {arg2}"); } } } } public static class ShoppingListPatches { private static readonly Regex s_colorWrapped = new Regex("\\$<(?color=[^>]+)>(?[0-9\\u00A0\\s\\.,]+)", RegexOptions.Compiled); private static readonly Regex s_simpleDollar = new Regex("\\$([0-9\\u00A0\\s\\.,]+)", RegexOptions.Compiled); internal static FieldInfo s_statsInstanceField; internal static FieldInfo s_textField; internal static FieldInfo s_textNumbersField; internal static FieldInfo s_upgradesHeaderField; internal static readonly ConcurrentDictionary s_textPropCache = new ConcurrentDictionary(); internal static string Preview(string s, int max = 120) { if (s == null) { return ""; } if (s.Length > max) { return s.Substring(0, max) + "..."; } return s; } internal static string ReplaceDollarNumbers(string input) { if (string.IsNullOrEmpty(input)) { return input; } int replaced = 0; if (!input.Contains("$")) { return input; } string text = s_colorWrapped.Replace(input, delegate(Match m) { string value = m.Groups["tag"].Value; if (!long.TryParse(Regex.Replace(m.Groups["num"].Value, "[^0-9]", ""), out var result2)) { return m.Value; } string text2 = CurrencyFormatter.FormatShoppingListDigits(result2); replaced++; return "<" + value + ">" + text2 + "" + CurrencyFormatter.NBSP + "₸"; }); if (replaced == 0) { text = s_simpleDollar.Replace(text, delegate(Match m) { if (!long.TryParse(Regex.Replace(m.Groups[1].Value, "[^0-9]", ""), out var result)) { return m.Value; } replaced++; return CurrencyFormatter.FormatShoppingListUI(result); }); } if (replaced > 0) { ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)$"[ShoppingListPatches] Replaced {replaced} dollar-formatted value(s)"); } } return text; } public static bool TryPatchNow(Harmony harmony) { try { List list = harmony.CreateClassProcessor(typeof(ShoppingListHUDPatches_SetUITexts_Patch)).Patch(); if (list != null && list.Count > 0) { ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)"[ShoppingListPatches] Successfully applied patch"); } return true; } } catch (Exception ex) { ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogDebug((object)("[ShoppingListPatches] TryPatchNow failed: " + ex.Message)); } } return false; } internal static void UpdateUITexts() { try { try { if (s_statsInstanceField == null) { Type type = AccessTools.TypeByName("StatsUI"); if (type != null) { s_statsInstanceField = AccessTools.Field(type, "instance"); s_textField = AccessTools.Field(type, "Text"); s_textNumbersField = AccessTools.Field(type, "textNumbers"); s_upgradesHeaderField = AccessTools.Field(type, "upgradesHeader"); } } object obj = s_statsInstanceField?.GetValue(null); if (obj == null) { return; } object obj2 = s_textField?.GetValue(obj); object obj3 = s_textNumbersField?.GetValue(obj); object obj4 = s_upgradesHeaderField?.GetValue(obj); if (obj2 != null) { Type type2 = obj2.GetType(); PropertyInfo orAdd = s_textPropCache.GetOrAdd(type2, (Type tt) => tt.GetProperty("text")); if (orAdd != null) { string text = orAdd.GetValue(obj2) as string; if (!string.IsNullOrEmpty(text) && text.Contains("$")) { string text2 = ReplaceDollarNumbers(text); if (text2 != text) { orAdd.SetValue(obj2, text2); ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)"[ShoppingListPatches] Updated TMP_Text.Text"); } } } } } if (obj3 != null) { Type type3 = obj3.GetType(); PropertyInfo orAdd2 = s_textPropCache.GetOrAdd(type3, (Type tt) => tt.GetProperty("text")); if (orAdd2 != null) { string text3 = orAdd2.GetValue(obj3) as string; if (!string.IsNullOrEmpty(text3) && text3.Contains("$")) { string text4 = ReplaceDollarNumbers(text3); if (text4 != text3) { orAdd2.SetValue(obj3, text4); ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogDebug((object)"[ShoppingListPatches] Updated TMP_Text.textNumbers"); } } } } } if (obj4 == null) { return; } Type type4 = obj4.GetType(); PropertyInfo orAdd3 = s_textPropCache.GetOrAdd(type4, (Type tt) => tt.GetProperty("text")); if (!(orAdd3 != null)) { return; } string text5 = orAdd3.GetValue(obj4) as string; if (string.IsNullOrEmpty(text5) || !text5.Contains("$")) { return; } string text6 = ReplaceDollarNumbers(text5); if (text6 != text5) { orAdd3.SetValue(obj4, text6); ManualLogSource logger3 = Plugin.Logger; if (logger3 != null) { logger3.LogDebug((object)"[ShoppingListPatches] Updated TMP_Text.upgradesHeader"); } } } catch (Exception arg) { ManualLogSource logger4 = Plugin.Logger; if (logger4 != null) { logger4.LogWarning((object)$"[ShoppingListPatches] Postfix_SetUITexts inner error: {arg}"); } } } catch (Exception arg2) { ManualLogSource logger5 = Plugin.Logger; if (logger5 != null) { logger5.LogWarning((object)$"[ShoppingListPatches] Postfix_SetUITexts error: {arg2}"); } } } } [HarmonyPatch] internal class ShoppingListHUDPatches_SetUITexts_Patch { private static bool Prepare() { bool flag = AccessTools.TypeByName("ShoppingListHUDPatches") != null; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogDebug((object)$"[ShoppingListPatches] Prepare ShoppingListHUDPatches.SetUITexts: {flag}"); } return flag; } private static MethodBase TargetMethod() { return AccessTools.Method("ShoppingListHUDPatches:SetUITexts", (Type[])null, (Type[])null); } private static void Postfix() { ShoppingListPatches.UpdateUITexts(); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class TMPTextAutoFontPatch { [HarmonyPrefix] private static void Prefix(TMP_Text __instance, ref string value) { if (!((Object)(object)__instance == (Object)null) && !string.IsNullOrEmpty(value) && ContainsCyrillicOrTenge(value)) { TMP_FontAsset tengeFallbackFont = TengeSymbolSupport.GetTengeFallbackFont(); if (!((Object)(object)tengeFallbackFont == (Object)null) && !((Object)(object)__instance.font == (Object)(object)tengeFallbackFont)) { TengeSymbolSupport.SetPrimaryFont(__instance); } } } private static bool ContainsCyrillicOrTenge(string s) { foreach (char c in s) { if ((c >= 'Ѐ' && c <= 'ӿ') || c == '₸') { return true; } } return false; } } [HarmonyPatch(typeof(VehicleUI), "ShowValuableBoxValue")] internal static class VehicleUIValuePatch { [HarmonyPostfix] private static void ShowValuableBoxValuePostfix(VehicleUI __instance, int _value) { try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.valuableBoxText == (Object)null)) { TengeSymbolSupport.SetPrimaryFont((TMP_Text)(object)__instance.valuableBoxText); ((TMP_Text)__instance.valuableBoxText).text = CurrencyFormatter.FormatCart(_value); } } catch (Exception arg) { Debug.LogError((object)$"[VehicleUI] Exception in ShowValuableBoxValuePostfix: {arg}"); } } } [HarmonyPatch(typeof(WorldSpaceUIValueLost), "Start")] public static class WorldSpaceUIValueLostPatch { [HarmonyPostfix] public static void StartPostfix(WorldSpaceUIValueLost __instance, TextMeshProUGUI ___text, int ___value) { if ((Object)(object)___text == (Object)null) { return; } TengeSymbolSupport.SetPrimaryFont((TMP_Text)(object)___text); try { ((TMP_Text)___text).text = "-" + CurrencyFormatter.FormatItemValue(___value); } catch { ((TMP_Text)___text).text = "-$" + SemiFunc.DollarGetString(___value); } } } [HarmonyPatch(typeof(WorldSpaceUIValue), "Show", new Type[] { typeof(PhysGrabObject), typeof(int), typeof(bool), typeof(Vector3) })] public class WorldSpaceUIValuePatch { [HarmonyPatch(typeof(WorldSpaceUIValue), "Show", new Type[] { typeof(StaticGrabObject), typeof(int), typeof(bool), typeof(Vector3) })] public class WorldSpaceUIValueStaticPatch { [HarmonyPostfix] public static void ShowPostfix(WorldSpaceUIValue __instance, int _value, bool _cost, TextMeshProUGUI ___text) { ApplyFormatting(___text, _value, _cost); } } [HarmonyPostfix] public static void ShowPostfix(WorldSpaceUIValue __instance, PhysGrabObject _grabObject, int _value, bool _cost, TextMeshProUGUI ___text, PhysGrabObject ___currentPhysGrabObject) { if (!((Object)(object)___currentPhysGrabObject != (Object)null) || !((Object)(object)___currentPhysGrabObject != (Object)(object)_grabObject)) { ApplyFormatting(___text, _value, _cost); } } private static void ApplyFormatting(TextMeshProUGUI text, int value, bool isCost) { if (!((Object)(object)text == (Object)null) && !string.IsNullOrEmpty(((TMP_Text)text).text)) { TengeSymbolSupport.SetPrimaryFont((TMP_Text)(object)text); if (isCost) { ((TMP_Text)text).text = "-" + CurrencyFormatter.FormatItemCost(value); } else { ((TMP_Text)text).text = CurrencyFormatter.FormatItemValue(value); } } } } [BepInPlugin("kztCurrency", "kztCurrency", "1.2.3")] public class Plugin : BaseUnityPlugin { internal class TemplateInfo { public string Template { get; set; } public bool MultiplyBy1000 { get; set; } public TemplateInfo(string template, bool multiplyBy1000) { Template = template; MultiplyBy1000 = multiplyBy1000; } } internal static ManualLogSource Logger; private static readonly Regex ZeroSuffixPattern = new Regex("\\{value\\}(?:[Kkк]|[\\u00A0 ]?тыс\\.?)", RegexOptions.Compiled); private static readonly Dictionary ExampleToTemplate_PlayerUI = new Dictionary { { "100K тг", new TemplateInfo("{value}K\u00a0тг", multiplyBy1000: false) }, { "100K ₸", new TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false) }, { "100K KZT", new TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false) }, { "100к тг", new TemplateInfo("{value}к\u00a0тг", multiplyBy1000: false) }, { "100к ₸", new TemplateInfo("{value}к\u00a0₸", multiplyBy1000: false) }, { "100к KZT", new TemplateInfo("{value}к\u00a0KZT", multiplyBy1000: false) }, { "100 тыс. тг", new TemplateInfo("{value}\u00a0тыс.\u00a0тг", multiplyBy1000: false) }, { "100 000 тг", new TemplateInfo("{value}\u00a0тг", multiplyBy1000: true) }, { "100 000 ₸", new TemplateInfo("{value}\u00a0₸", multiplyBy1000: true) }, { "100 000 KZT", new TemplateInfo("{value}\u00a0KZT", multiplyBy1000: true) } }; private static readonly Dictionary ExampleToTemplate_ItemCost = new Dictionary { { "100K тг", new TemplateInfo("{value}K\u00a0тг", multiplyBy1000: false) }, { "100K ₸", new TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false) }, { "100K KZT", new TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false) }, { "100 тыс. тг", new TemplateInfo("{value}\u00a0тыс.\u00a0тг", multiplyBy1000: false) }, { "100 тыс. ₸", new TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false) }, { "100 тыс. KZT", new TemplateInfo("{value}\u00a0тыс.\u00a0KZT", multiplyBy1000: false) }, { "100 000 тг", new TemplateInfo("{value}\u00a0тг", multiplyBy1000: true) }, { "100 000 ₸", new TemplateInfo("{value}\u00a0₸", multiplyBy1000: true) }, { "100 000 KZT", new TemplateInfo("{value}\u00a0KZT", multiplyBy1000: true) } }; private static readonly Dictionary ExampleToTemplate_HaulUI = new Dictionary { { "100K тг", new TemplateInfo("{value}K\u00a0тг", multiplyBy1000: false) }, { "100K ₸", new TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false) }, { "100K KZT", new TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false) }, { "100к тг", new TemplateInfo("{value}к\u00a0тг", multiplyBy1000: false) }, { "100к ₸", new TemplateInfo("{value}к\u00a0₸", multiplyBy1000: false) }, { "100к KZT", new TemplateInfo("{value}к\u00a0KZT", multiplyBy1000: false) }, { "100 000 тг", new TemplateInfo("{value}\u00a0тг", multiplyBy1000: true) }, { "100 000 ₸", new TemplateInfo("{value}\u00a0₸", multiplyBy1000: true) }, { "100 000 KZT", new TemplateInfo("{value}\u00a0KZT", multiplyBy1000: true) } }; private static readonly Dictionary ExampleToTemplate_Haul = new Dictionary { { "100K тг", new TemplateInfo("{value}K\u00a0тг", multiplyBy1000: false) }, { "100K ₸", new TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false) }, { "100K KZT", new TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false) }, { "100к тг", new TemplateInfo("{value}к\u00a0тг", multiplyBy1000: false) }, { "100к ₸", new TemplateInfo("{value}к\u00a0₸", multiplyBy1000: false) }, { "100 000 тг", new TemplateInfo("{value}\u00a0тг", multiplyBy1000: true) }, { "100 000 ₸", new TemplateInfo("{value}\u00a0₸", multiplyBy1000: true) }, { "100 000 KZT", new TemplateInfo("{value}\u00a0KZT", multiplyBy1000: true) } }; private static readonly Dictionary ExampleToTemplate_Cart = new Dictionary { { "100 тыс. тг", new TemplateInfo("{value}\u00a0тыс.\u00a0тг", multiplyBy1000: false) }, { "100 тыс. ₸", new TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false) }, { "100 тыс. KZT", new TemplateInfo("{value}\u00a0тыс.\u00a0KZT", multiplyBy1000: false) }, { "100 тг", new TemplateInfo("{value}\u00a0тг", multiplyBy1000: false) }, { "100 000 тг", new TemplateInfo("{value}\u00a0тг", multiplyBy1000: true) }, { "100 000 ₸", new TemplateInfo("{value}\u00a0₸", multiplyBy1000: true) }, { "100 000 KZT", new TemplateInfo("{value}\u00a0KZT", multiplyBy1000: true) } }; internal static ConfigEntry Format_PlayerUI; internal static ConfigEntry Format_ItemCost; internal static ConfigEntry Format_ItemPickup; internal static ConfigEntry Format_ExtractionPointUI; internal static ConfigEntry Format_ExtractionPoint; internal static ConfigEntry Format_Cart; internal static TemplateInfo Template_PlayerUI; internal static TemplateInfo Template_ItemCost; internal static TemplateInfo Template_HaulUI; internal static TemplateInfo Template_Haul; internal static TemplateInfo Template_Cart; internal static string TemplateZero_PlayerUI; internal static string TemplateZero_ItemCost; internal static string TemplateZero_ItemPickup; internal static string TemplateZero_HaulUI; internal static string TemplateZero_Haul; internal static string TemplateZero_Cart; private static string MakeZeroFriendlyTemplate(string template) { if (string.IsNullOrEmpty(template)) { return template; } return ZeroSuffixPattern.Replace(template, "{value}"); } private static TemplateInfo ConvertExampleToTemplateInfo(string example, Dictionary mapping, string mappingName = "Unknown") { if (mapping.TryGetValue(example, out var value)) { return value; } Logger.LogWarning((object)("[Formatting] No mapping found for example '" + example + "' in " + mappingName + " mapper. Using fallback with MultiplyBy1000=false.")); return new TemplateInfo(example, multiplyBy1000: false); } internal static TemplateInfo GetFormatTemplateInfo(ConfigEntry configEntry, TemplateInfo defaultTemplateInfo, Dictionary mapping, string mappingName = "Unknown") { if (configEntry == null || configEntry.Value == null) { return defaultTemplateInfo; } return ConvertExampleToTemplateInfo(configEntry.Value, mapping, mappingName); } internal static void RefreshTemplates(string reason) { try { string arg = Format_PlayerUI?.Value; string arg2 = Format_ItemCost?.Value; string arg3 = Format_ItemPickup?.Value; string arg4 = Format_ExtractionPointUI?.Value; string arg5 = Format_Cart?.Value; Template_PlayerUI = GetFormatTemplateInfo(Format_PlayerUI, new TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false), ExampleToTemplate_PlayerUI, "PlayerUI"); Template_ItemCost = GetFormatTemplateInfo(Format_ItemCost, new TemplateInfo("{value}K\u00a0KZT", multiplyBy1000: false), ExampleToTemplate_ItemCost, "ItemCost"); Template_HaulUI = GetFormatTemplateInfo(Format_ExtractionPointUI, new TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false), ExampleToTemplate_HaulUI, "HaulUI"); Template_Haul = GetFormatTemplateInfo(Format_ExtractionPoint, new TemplateInfo("{value}K\u00a0₸", multiplyBy1000: false), ExampleToTemplate_Haul, "Haul"); Template_Cart = GetFormatTemplateInfo(Format_Cart, new TemplateInfo("{value}\u00a0тыс.\u00a0₸", multiplyBy1000: false), ExampleToTemplate_Cart, "Cart"); TemplateZero_PlayerUI = MakeZeroFriendlyTemplate(Template_PlayerUI.Template); TemplateZero_ItemCost = MakeZeroFriendlyTemplate(Template_ItemCost.Template); TemplateZero_ItemPickup = MakeZeroFriendlyTemplate(Template_ItemCost.Template); TemplateZero_HaulUI = MakeZeroFriendlyTemplate(Template_HaulUI.Template); TemplateZero_Haul = MakeZeroFriendlyTemplate(Template_Haul.Template); TemplateZero_Cart = MakeZeroFriendlyTemplate(Template_Cart.Template); Logger.LogInfo((object)("[Formatting] Refreshed templates (" + reason + ")")); Logger.LogInfo((object)$" PlayerUI: raw='{arg}' => tpl='{Template_PlayerUI.Template}' x1000={Template_PlayerUI.MultiplyBy1000}"); Logger.LogInfo((object)$" ItemCost: raw='{arg2}' => tpl='{Template_ItemCost.Template}' x1000={Template_ItemCost.MultiplyBy1000}"); Logger.LogInfo((object)$" ItemPickup: raw='{arg3}' => tpl='{Template_ItemCost.Template}' x1000={Template_ItemCost.MultiplyBy1000}"); Logger.LogInfo((object)$" Haul: raw='{arg4}' => tpl='{Template_Haul.Template}' x1000={Template_Haul.MultiplyBy1000}"); Logger.LogInfo((object)$" HaulUI: raw='{arg4}' => tpl='{Template_HaulUI.Template}' x1000={Template_HaulUI.MultiplyBy1000}"); Logger.LogInfo((object)$" Cart: raw='{arg5}' => tpl='{Template_Cart.Template}' x1000={Template_Cart.MultiplyBy1000}"); } catch (Exception ex) { Logger.LogWarning((object)("[Formatting] Failed to log templates: " + ex.Message)); } } private void Awake() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Expected O, but got Unknown //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Expected O, but got Unknown //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected O, but got Unknown //IL_02f9: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; Format_PlayerUI = ((BaseUnityPlugin)this).Config.Bind("Formatting", "PlayerUI", "100 000 ₸", new ConfigDescription("Player UI currency format.", (AcceptableValueBase)(object)new AcceptableValueList(new string[9] { "100K тг", "100K ₸", "100K KZT", "100к тг", "100к ₸", "100 тыс. тг", "100 000 тг", "100 000 ₸", "100 000 KZT" }), Array.Empty())); Format_ItemCost = ((BaseUnityPlugin)this).Config.Bind("Formatting", "ItemCost", "100K ₸", new ConfigDescription("Shop/cart UI currency format.", (AcceptableValueBase)(object)new AcceptableValueList(new string[6] { "100K тг", "100K ₸", "100K KZT", "100 000 тг", "100 000 ₸", "100 000 KZT" }), Array.Empty())); Format_ItemPickup = ((BaseUnityPlugin)this).Config.Bind("Formatting", "ItemPickup", "100 000 ₸", new ConfigDescription("Item pickup/value UI currency format. For values >= 1000: uses thousands format; for < 1000: shows units.", (AcceptableValueBase)(object)new AcceptableValueList(new string[5] { "100 тыс. тг", "100 тыс. ₸", "100 тыс. KZT", "100 000 тг", "100 000 ₸" }), Array.Empty())); Format_ExtractionPointUI = ((BaseUnityPlugin)this).Config.Bind("Formatting", "HaulUI", "100 000 ₸", new ConfigDescription("Extraction point UI currency format.", (AcceptableValueBase)(object)new AcceptableValueList(new string[9] { "100K тг", "100K ₸", "100K KZT", "100к тг", "100к ₸", "100к KZT", "100 000 тг", "100 000 ₸", "100 000 KZT" }), Array.Empty())); Format_ExtractionPoint = ((BaseUnityPlugin)this).Config.Bind("Formatting", "ExtractionPoint", "100 000 ₸", new ConfigDescription("Extraction point (plain) currency format used by extraction point screens.", (AcceptableValueBase)(object)new AcceptableValueList(new string[8] { "100K тг", "100K ₸", "100K KZT", "100к тг", "100к ₸", "100 000 тг", "100 000 ₸", "100 000 KZT" }), Array.Empty())); Format_Cart = ((BaseUnityPlugin)this).Config.Bind("Formatting", "Cart", "100 тыс. тг", new ConfigDescription("Cart haul currency format.", (AcceptableValueBase)(object)new AcceptableValueList(new string[6] { "100 тыс. тг", "100 тыс. ₸", "100 тыс. KZT", "100 000 тг", "100 000 ₸", "100 000 KZT" }), Array.Empty())); TengeSymbolSupport.Initialize(); RefreshTemplates("startup"); ((BaseUnityPlugin)this).Config.SettingChanged += delegate(object _, SettingChangedEventArgs args) { RefreshTemplates("configChanged: " + args.ChangedSetting.Definition.Key); }; new Harmony("kztCurrency").PatchAll(); Logger.LogInfo((object)"Plugin loaded!"); } } public static class TengeSymbolSupport { private const string BUNDLE_FILE_NAME = "teko-cyrillic-tenge.bundle"; private static TMP_FontAsset tengeFallbackFont; private static bool initialized; public static void Initialize() { if (!initialized) { LoadFontAsset(); if ((Object)(object)tengeFallbackFont == (Object)null) { Plugin.Logger.LogError((object)"Failed to load Tenge font asset"); return; } AddFallbackToDefaultFont(); InjectFallbackIntoAllFonts(); initialized = true; Plugin.Logger.LogInfo((object)"Tenge symbol (₸) support initialized"); } } private static void LoadFontAsset() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string r) => r.EndsWith("teko-cyrillic-tenge.bundle", StringComparison.OrdinalIgnoreCase)); if (text == null) { throw new Exception("Embedded resource ending with 'teko-cyrillic-tenge.bundle' not found"); } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { throw new Exception("Failed to open resource stream: " + text); } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); AssetBundle obj = AssetBundle.LoadFromMemory(array); if ((Object)(object)obj == (Object)null) { throw new Exception("Failed to load AssetBundle from memory"); } TMP_FontAsset[] array2 = obj.LoadAllAssets(); if (array2 == null || array2.Length == 0) { throw new Exception("No TMP_FontAsset found in bundle"); } tengeFallbackFont = array2[0]; EnsureFontMaterial(); } private static void EnsureFontMaterial() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if ((Object)(object)((TMP_Asset)tengeFallbackFont).material != (Object)null) { return; } Shader val = Shader.Find("TextMeshPro/Distance Field") ?? Shader.Find("TextMeshPro/Mobile/Distance Field"); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogWarning((object)"TMP shader not found"); return; } Material val2 = new Material(val) { name = "TengeFont_Material" }; if ((Object)(object)tengeFallbackFont.atlasTexture != (Object)null) { val2.mainTexture = (Texture)(object)tengeFallbackFont.atlasTexture; } ((TMP_Asset)tengeFallbackFont).material = val2; } private static void AddFallbackToDefaultFont() { List fallbackFontAssets = TMP_Settings.fallbackFontAssets; if (fallbackFontAssets != null && !fallbackFontAssets.Contains(tengeFallbackFont)) { fallbackFontAssets.Insert(0, tengeFallbackFont); } TMP_FontAsset defaultFontAsset = TMP_Settings.defaultFontAsset; if (!((Object)(object)defaultFontAsset == (Object)null)) { List list2 = (defaultFontAsset.fallbackFontAssetTable = defaultFontAsset.fallbackFontAssetTable ?? new List()); if (!list2.Contains(tengeFallbackFont)) { list2.Insert(0, tengeFallbackFont); } } } private static void InjectFallbackIntoAllFonts() { TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll(); foreach (TMP_FontAsset val in array) { if (!((Object)(object)val == (Object)null) && val != tengeFallbackFont) { List list2 = (val.fallbackFontAssetTable = val.fallbackFontAssetTable ?? new List()); if (!list2.Contains(tengeFallbackFont)) { list2.Insert(0, tengeFallbackFont); } } } } public static void EnsureFallbackFont(TMP_Text textComponent) { if ((Object)(object)textComponent == (Object)null || (Object)(object)tengeFallbackFont == (Object)null) { return; } TMP_FontAsset font = textComponent.font; if (!((Object)(object)font == (Object)null)) { List list2 = (font.fallbackFontAssetTable = font.fallbackFontAssetTable ?? new List()); if (!list2.Contains(tengeFallbackFont)) { list2.Add(tengeFallbackFont); } } } public static void SetPrimaryFont(TMP_Text textComponent) { if (!((Object)(object)textComponent == (Object)null) && !((Object)(object)tengeFallbackFont == (Object)null) && textComponent.font != tengeFallbackFont) { textComponent.font = tengeFallbackFont; if ((Object)(object)((TMP_Asset)tengeFallbackFont).material != (Object)null) { textComponent.fontSharedMaterial = ((TMP_Asset)tengeFallbackFont).material; textComponent.fontMaterial = ((TMP_Asset)tengeFallbackFont).material; } ((Graphic)textComponent).SetAllDirty(); } } public static TMP_FontAsset GetTengeFallbackFont() { return tengeFallbackFont; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "kztCurrency"; public const string PLUGIN_NAME = "kztCurrency"; public const string PLUGIN_VERSION = "1.2.3"; } }