Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of UltimateLethal StorePriceModifier v0.1.0
BepInEx/plugins/UltimateLethal_StorePriceModifier/UltimateLethal.StorePriceModifier.dll
Decompiled 8 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [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("UltimateLethal.StorePriceModifier")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("UltimateLethal.StorePriceModifier")] [assembly: AssemblyTitle("UltimateLethal.StorePriceModifier")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UltimateLethal.StorePriceModifier { [BepInPlugin("com.ultimatelethal.storepricemodifier", "Ultimate Lethal Store Price Modifier", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { private sealed class PriceRule { internal string DisplayName; internal int Price; internal bool Matched; } public const string Guid = "com.ultimatelethal.storepricemodifier"; public const string Name = "Ultimate Lethal Store Price Modifier"; public const string Version = "0.1.0"; private const string DefaultOverrides = "Belt Bag=800;Company Hauler=250;Assault Rifle=450;Bolt-Action Rifle=500;Flame Thrower=400;Heavy Shotgun=375;Pistol=300;Revolver=275"; internal static Plugin Instance; internal static ConfigEntry<string> PriceOverrides; internal static ConfigEntry<bool> LogSuccessfulOverrides; private Harmony _harmony; private float _nextApplyAt; private string _lastRawOverrides; private readonly Dictionary<string, PriceRule> _rules = new Dictionary<string, PriceRule>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _loggedMatches = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _loggedMissing = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private float _startupTime; private void Awake() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown Instance = this; PriceOverrides = ((BaseUnityPlugin)this).Config.Bind<string>("Store Prices", "Overrides", "Belt Bag=800;Company Hauler=250;Assault Rifle=450;Bolt-Action Rifle=500;Flame Thrower=400;Heavy Shotgun=375;Pistol=300;Revolver=275", "Semicolon-separated Item Name=Price rules. Names ignore spaces, hyphens and punctuation. Use -1 to leave a listed item unchanged. This is the authoritative Ultimate Lethal store balance list."); LogSuccessfulOverrides = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Log Successful Overrides", true, "Log each configured store item the first time Ultimate Lethal successfully applies its price."); ParseRules(force: true); _startupTime = Time.unscaledTime; _harmony = new Harmony("com.ultimatelethal.storepricemodifier"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded with {2} configured price override(s).", "Ultimate Lethal Store Price Modifier", "0.1.0", _rules.Count)); RequestImmediateApply(); } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } if (Instance == this) { Instance = null; } } private void Update() { ParseRules(force: false); if (!(Time.unscaledTime < _nextApplyAt)) { float num = Time.unscaledTime - _startupTime; _nextApplyAt = Time.unscaledTime + ((num < 20f) ? 0.5f : 3f); ApplyAll(); if (num > 12f) { LogMissingRulesOnce(); } } } internal void RequestImmediateApply() { _nextApplyAt = 0f; } private void ParseRules(bool force) { string text = PriceOverrides?.Value ?? string.Empty; if (!force && string.Equals(text, _lastRawOverrides, StringComparison.Ordinal)) { return; } _lastRawOverrides = text; _rules.Clear(); _loggedMatches.Clear(); _loggedMissing.Clear(); string[] array = text.Split(new char[3] { ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num <= 0 || num >= text2.Length - 1) { continue; } string text3 = text2.Substring(0, num).Trim(); string s = text2.Substring(num + 1).Trim(); if (!string.IsNullOrWhiteSpace(text3) && int.TryParse(s, out var result) && result >= -1 && result >= 0) { string text4 = Normalize(text3); if (text4.Length != 0) { _rules[text4] = new PriceRule { DisplayName = text3, Price = result }; } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Parsed {_rules.Count} Ultimate Lethal store price override(s)."); RequestImmediateApply(); } internal void ApplyAll() { if (_rules.Count != 0) { ApplyBetterArmoryConfigAdapter(); ApplyItemPrices(); ApplyVehiclePrices(); } } private void ApplyItemPrices() { Item[] array; try { array = Resources.FindObjectsOfTypeAll<Item>(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Item price scan failed: " + ex.GetBaseException().Message)); return; } foreach (Item val in array) { if ((Object)(object)val == (Object)null) { continue; } string text = (string.IsNullOrWhiteSpace(val.itemName) ? ((Object)val).name : val.itemName); if (!TryGetRule(text, out var rule)) { continue; } try { if (val.creditsWorth != rule.Price) { val.creditsWorth = rule.Price; } MarkMatched(rule, "Item '" + text + "'"); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to price '" + text + "': " + ex2.GetBaseException().Message)); } } } private void ApplyBetterArmoryConfigAdapter() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("com.y4ngz.betterarmory", out var value) || (Object)(object)((value != null) ? value.Instance : null) == (Object)null) { return; } ConfigFile config = value.Instance.Config; if (config == null) { return; } string[] array = new string[6] { "Assault Rifle", "Bolt-Action Rifle", "Flame Thrower", "Heavy Shotgun", "Pistol", "Revolver" }; ConfigEntry<int> val2 = default(ConfigEntry<int>); foreach (string text in array) { if (!TryGetRule(text, out var rule)) { continue; } try { ConfigDefinition val = new ConfigDefinition("Weapon: " + text, "Shop Price"); if (config.TryGetEntry<int>(val, ref val2) && val2 != null) { if (val2.Value != rule.Price) { val2.Value = rule.Price; } MarkMatched(rule, "BetterArmory '" + text + "'"); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("BetterArmory adapter failed for '" + text + "': " + ex.GetBaseException().Message)); } } } private void ApplyVehiclePrices() { if (!TryGetRule("Company Hauler", out var rule)) { return; } Terminal val = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val == (Object)null) { return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; int num = 0; FieldInfo[] fields = ((object)val).GetType().GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.Name.IndexOf("vehicle", StringComparison.OrdinalIgnoreCase) >= 0) { try { num += ApplyVehicleEnumerable(fieldInfo.GetValue(val) as IEnumerable, rule); } catch { } } } PropertyInfo[] properties = ((object)val).GetType().GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.CanRead && propertyInfo.Name.IndexOf("vehicle", StringComparison.OrdinalIgnoreCase) >= 0) { try { num += ApplyVehicleEnumerable(propertyInfo.GetValue(val, null) as IEnumerable, rule); } catch { } } } if (num > 0) { MarkMatched(rule, "Company Hauler vehicle registration"); } } private int ApplyVehicleEnumerable(IEnumerable entries, PriceRule rule) { if (entries == null) { return 0; } int num = 0; foreach (object entry in entries) { if (entry != null && ObjectContainsName(entry, "hauler") && TrySetIntPriceMember(entry, rule.Price)) { num++; } } return num; } private static bool ObjectContainsName(object entry, string token) { Type type = entry.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; string[] array = new string[5] { "vehicleDisplayName", "vehicleName", "displayName", "name", "itemName" }; foreach (string name in array) { try { if (type.GetField(name, bindingAttr)?.GetValue(entry) is string text && text.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } PropertyInfo property = type.GetProperty(name, bindingAttr); if (property != null && property.CanRead && property.GetValue(entry, null) is string text2 && text2.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } catch { } } Object val = (Object)((entry is Object) ? entry : null); if (val != null && !string.IsNullOrEmpty(val.name)) { return val.name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool TrySetIntPriceMember(object entry, int price) { Type type = entry.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; string[] array = new string[5] { "creditsWorth", "creditsCost", "creditCost", "price", "cost" }; foreach (string name in array) { try { FieldInfo field = type.GetField(name, bindingAttr); if (field != null && field.FieldType == typeof(int)) { field.SetValue(entry, price); return true; } PropertyInfo property = type.GetProperty(name, bindingAttr); if (property != null && property.CanWrite && property.PropertyType == typeof(int)) { property.SetValue(entry, price, null); return true; } } catch { } } return false; } private bool TryGetRule(string name, out PriceRule rule) { rule = null; string text = Normalize(name); if (text.Length > 0) { return _rules.TryGetValue(text, out rule); } return false; } private void MarkMatched(PriceRule rule, string source) { if (rule != null) { rule.Matched = true; ConfigEntry<bool> logSuccessfulOverrides = LogSuccessfulOverrides; if (logSuccessfulOverrides != null && logSuccessfulOverrides.Value && _loggedMatches.Add(rule.DisplayName)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"STORE PRICE: {rule.DisplayName} = {rule.Price} credits ({source})."); } } } private void LogMissingRulesOnce() { foreach (PriceRule value in _rules.Values) { if (!value.Matched && _loggedMissing.Add(value.DisplayName)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)($"STORE PRICE target not found yet: '{value.DisplayName}' ({value.Price} credits). " + "Check the runtime item name if this remains missing after store registration.")); } } } private static string Normalize(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } char[] array = new char[value.Length]; int length = 0; foreach (char c in value) { if (char.IsLetterOrDigit(c)) { array[length++] = char.ToLowerInvariant(c); } } return new string(array, 0, length); } } [HarmonyPatch] internal static class TerminalStoreRefreshHooks { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[5] { "Start", "TextPostProcess", "LoadNewNode", "LoadNewNodeIfAffordable", "ParsePlayerSentence" }; HashSet<MethodBase> seen = new HashSet<MethodBase>(); string[] array2 = array; foreach (string name in array2) { MethodInfo[] methods = typeof(Terminal).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo[] array3 = methods; foreach (MethodInfo methodInfo in array3) { if (methodInfo.Name == name && seen.Add(methodInfo)) { yield return methodInfo; } } } } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix() { Plugin.Instance?.ApplyAll(); Plugin.Instance?.RequestImmediateApply(); } } }