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 UniversalMoonCostConfig v1.0.0
UniversalMoonCostConfig.dll
Decompiled 4 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.SceneManagement; [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("slivkonsin")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("UniversalMoonCostConfig")] [assembly: AssemblyTitle("UniversalMoonCostConfig")] [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 UniversalMoonCostConfig { internal static class Elsewhere { internal sealed class Where { public string Mod; public string File; public string Section; public string Setting; public string Extra; public string Short => File + " (" + Section + ")"; public override string ToString() { return File + " -> [" + Section + "] -> \"" + Setting + "\"" + ((Extra != null) ? (" (" + Extra + ")") : ""); } } private const string LllGuid = "imabatby.lethallevelloader"; private static readonly string[] PriceWords = new string[3] { "price", "cost", "route" }; private static List<(string pluginName, string file, ConfigFile cfg)> _files; private static ConfigFile _lllLevelConfig; private static bool _lllTried; private static string _lllFallbackText; public static void Check(List<Moon> moons) { if (_files == null) { _files = CollectConfigs(); } foreach (Moon moon in moons) { moon.SetElsewhere = null; try { moon.SetElsewhere = FindLll(moon) ?? FindAnywhere(moon); } catch { } } } private static List<(string, string, ConfigFile)> CollectConfigs() { List<(string, string, ConfigFile)> list = new List<(string, string, ConfigFile)>(); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (!((Object)(object)((value != null) ? value.Instance : null) == (Object)null) && !(value.Metadata.GUID == "slivkonsin.UniversalMoonCostConfig")) { try { list.Add((value.Metadata.Name, Path.GetFileName(value.Instance.Config.ConfigFilePath), value.Instance.Config)); } catch { } } } return list; } private static Where FindLll(Moon m) { if (!Chainloader.PluginInfos.ContainsKey("imabatby.lethallevelloader")) { return null; } if (!_lllTried) { _lllTried = true; try { Assembly assembly = ((object)Chainloader.PluginInfos["imabatby.lethallevelloader"].Instance).GetType().Assembly; FieldInfo[] array = (assembly.GetType("LethalLevelLoader.Tools.ConfigLoader") ?? assembly.GetType("LethalLevelLoader.ConfigLoader"))?.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? Array.Empty<FieldInfo>(); foreach (FieldInfo fieldInfo in array) { if (fieldInfo.FieldType == typeof(ConfigFile)) { object? value = fieldInfo.GetValue(null); _lllLevelConfig = (ConfigFile)((value is ConfigFile) ? value : null); break; } } } catch { } if (_lllLevelConfig == null) { try { _lllFallbackText = File.ReadAllText(Path.Combine(Paths.ConfigPath, "LethalLevelLoader.cfg")).Replace("\u200b", ""); } catch { } } } string key = m.Key; if (_lllLevelConfig != null) { foreach (ConfigDefinition key2 in _lllLevelConfig.Keys) { string text = Clean(key2.Section); if (text.StartsWith("Custom Level:", StringComparison.OrdinalIgnoreCase) && EndsWithName(text, key) && key2.Key.IndexOf("Route Price", StringComparison.OrdinalIgnoreCase) >= 0) { return new Where { Mod = "LethalLevelLoader", File = "LethalLevelLoader.cfg", Section = text, Setting = key2.Key, Extra = "only used when \"Enable Content Configuration\" in the same section is on" }; } } return null; } if (_lllFallbackText != null) { string text2 = null; string[] array2 = _lllFallbackText.Split('\n'); for (int i = 0; i < array2.Length; i++) { string text3 = array2[i].Trim(); if (text3.StartsWith("[")) { text2 = text3.Trim('[', ']').Trim(); } else if (text2 != null && text2.StartsWith("Custom Level:", StringComparison.OrdinalIgnoreCase) && EndsWithName(text2, key)) { int num = text3.IndexOf('='); if (num > 0 && text3.Substring(0, num).IndexOf("Route Price", StringComparison.OrdinalIgnoreCase) >= 0) { return new Where { Mod = "LethalLevelLoader", File = "LethalLevelLoader.cfg", Section = text2, Setting = text3.Substring(0, num).Trim(), Extra = "only used when \"Enable Content Configuration\" in the same section is on" }; } } } } return null; } private static Where FindAnywhere(Moon m) { ConfigEntry<int> val2 = default(ConfigEntry<int>); ConfigEntry<float> val3 = default(ConfigEntry<float>); foreach (var (text, file, val) in _files) { if (text == "LethalLevelLoader") { continue; } foreach (ConfigDefinition key in val.Keys) { if (!val.TryGetEntry<int>(key, ref val2) && !val.TryGetEntry<float>(key, ref val3)) { continue; } string text2 = Clean(key.Section) + " " + key.Key; if (!MentionsWord(text2, m.Key)) { continue; } bool flag = false; string[] priceWords = PriceWords; foreach (string value in priceWords) { if (text2.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { flag = true; break; } } if (flag) { return new Where { Mod = text, File = file, Section = Clean(key.Section), Setting = key.Key }; } } } return null; } private static string Clean(string s) { return (s ?? "").Replace("\u200b", "").Trim(); } private static bool EndsWithName(string section, string name) { if (!section.EndsWith(name, StringComparison.OrdinalIgnoreCase)) { return false; } int num = section.Length - name.Length - 1; if (num >= 0) { return !char.IsLetter(section[num]); } return true; } private static bool MentionsWord(string text, string word) { int startIndex = 0; while ((startIndex = text.IndexOf(word, startIndex, StringComparison.OrdinalIgnoreCase)) >= 0) { bool num = startIndex == 0 || !char.IsLetterOrDigit(text[startIndex - 1]); int num2 = startIndex + word.Length; bool flag = num2 >= text.Length || !char.IsLetterOrDigit(text[num2]); if (num && flag) { return true; } startIndex = num2; } return false; } } internal static class LethalConfigSupport { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static CanModifyDelegate <>9__1_0; internal CanModifyResult <AddMoons>b__1_0() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (Net.IsClient) { return CanModifyResult.False("Moon prices are set by the host."); } return CanModifyResult.True(); } } private static readonly HashSet<string> Added = new HashSet<string>(); public static void AddMoons(List<Moon> moons) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown foreach (Moon moon in moons) { if (!Prices.Price.TryGetValue(moon.Key, out var value) || !Added.Add("p:" + moon.Key)) { continue; } ConfigEntry<int> obj = value; IntInputFieldOptions val = new IntInputFieldOptions { RequiresRestart = false }; ((BaseRangeOptions<int>)val).Min = ((moon.SetElsewhere != null) ? (-1) : 0); ((BaseRangeOptions<int>)val).Max = 1000000; object obj2 = <>c.<>9__1_0; if (obj2 == null) { CanModifyDelegate val2 = () => Net.IsClient ? CanModifyResult.False("Moon prices are set by the host.") : CanModifyResult.True(); <>c.<>9__1_0 = val2; obj2 = (object)val2; } ((BaseOptions)val).CanModifyCallback = (CanModifyDelegate)obj2; LethalConfigManager.AddConfigItem((BaseConfigItem)new IntInputFieldConfigItem(obj, val)); } } private static CanModifyResult HostOnly() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsClient) { return CanModifyResult.True(); } return CanModifyResult.False("Moon prices are set by the host."); } } internal sealed class Moon { public string Key; public string Display; public SelectableLevel Level; public TerminalNode Route; public TerminalNode Confirm; public object Extended; public int Original; public Elsewhere.Where SetElsewhere; public int? Applied; public int Corrections; public bool GaveUp; public int Current { get { if (!((Object)(object)Route != (Object)null)) { return Original; } return Route.itemCost; } } } internal static class Moons { public static readonly List<Moon> All = new List<Moon>(); private static readonly Dictionary<string, int> OriginalByKey = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private static PropertyInfo _lllRoutePrice; private static bool _lllTried; private static IList _lllLevels; private static PropertyInfo _lllSelectable; public static bool Ready { get; private set; } public static void Reset() { All.Clear(); Ready = false; } public static bool Discover() { StartOfRound instance = StartOfRound.Instance; Terminal val = Object.FindObjectOfType<Terminal>(); if ((Object)(object)instance == (Object)null || instance.levels == null || (Object)(object)val == (Object)null || (Object)(object)val.terminalNodes == (Object)null) { return false; } Dictionary<int, (TerminalNode, TerminalNode)> dictionary = new Dictionary<int, (TerminalNode, TerminalNode)>(); TerminalKeyword[] array = val.terminalNodes.allKeywords ?? Array.Empty<TerminalKeyword>(); foreach (TerminalKeyword val2 in array) { if ((Object)(object)val2 == (Object)null || val2.compatibleNouns == null) { continue; } CompatibleNoun[] compatibleNouns = val2.compatibleNouns; for (int j = 0; j < compatibleNouns.Length; j++) { TerminalNode val3 = compatibleNouns[j]?.result; if ((Object)(object)val3 == (Object)null || val3.buyRerouteToMoon != -2 || val3.terminalOptions == null) { continue; } CompatibleNoun[] terminalOptions = val3.terminalOptions; for (int k = 0; k < terminalOptions.Length; k++) { TerminalNode val4 = terminalOptions[k]?.result; if (!((Object)(object)val4 == (Object)null) && val4.buyRerouteToMoon >= 0 && val4.buyRerouteToMoon < instance.levels.Length && !dictionary.ContainsKey(val4.buyRerouteToMoon)) { dictionary[val4.buyRerouteToMoon] = (val3, val4); } } } } All.Clear(); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<int, (TerminalNode, TerminalNode)> item in dictionary) { SelectableLevel val5 = instance.levels[item.Key]; if ((Object)(object)val5 == (Object)null) { continue; } string text = ConfigKey(val5.PlanetName); if (text.Length != 0) { if (!hashSet.Add(text)) { text = text + " (" + item.Key + ")"; hashSet.Add(text); } Moon moon = new Moon { Key = text, Display = val5.PlanetName, Level = val5, Route = item.Value.Item1, Confirm = item.Value.Item2, Extended = FindExtendedLevel(val5) }; if (!OriginalByKey.TryGetValue(text, out moon.Original)) { OriginalByKey[text] = (moon.Original = Math.Max(0, moon.Route.itemCost)); } All.Add(moon); } } All.Sort((Moon a, Moon b) => string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase)); Ready = All.Count > 0; return Ready; } public static string ConfigKey(string planetName) { string text = (planetName ?? "").Trim(); int num = text.IndexOf(' '); if (num > 0 && char.IsDigit(text[0])) { text = text.Substring(num + 1).Trim(); } StringBuilder stringBuilder = new StringBuilder(text.Length); string text2 = text; foreach (char c in text2) { if (c != '=' && c != '[' && c != ']' && c != '\n' && c != '\r' && c != '\t' && c != '\\' && c != '"' && c != '\'' && c != '\u200b') { stringBuilder.Append(c); } } return stringBuilder.ToString().Trim(); } public static bool SetPrice(Moon m, int price) { price = Mathf.Clamp(price, 0, 1000000); try { if (m.Extended != null && _lllRoutePrice != null && _lllRoutePrice.CanWrite) { _lllRoutePrice.SetValue(m.Extended, price); } if ((Object)(object)m.Route != (Object)null) { m.Route.itemCost = price; } if ((Object)(object)m.Confirm != (Object)null) { m.Confirm.itemCost = price; } return true; } catch (Exception ex) { DiagnosticsTelemetry.Errors++; Plugin.Log.LogWarning((object)("Couldn't set the price of " + m.Key + ": " + ex.Message)); return false; } } private static object FindExtendedLevel(SelectableLevel level) { if (!_lllTried) { _lllTried = true; try { if (Chainloader.PluginInfos.TryGetValue("imabatby.lethallevelloader", out var value) && (Object)(object)value.Instance != (Object)null) { Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("LethalLevelLoader.PatchedContent"); Type? type2 = assembly.GetType("LethalLevelLoader.ExtendedLevel"); _lllLevels = type?.GetProperty("ExtendedLevels", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) as IList; _lllSelectable = type2?.GetProperty("SelectableLevel", BindingFlags.Instance | BindingFlags.Public); _lllRoutePrice = type2?.GetProperty("RoutePrice", BindingFlags.Instance | BindingFlags.Public); if (_lllLevels == null || _lllSelectable == null || _lllRoutePrice == null) { _lllLevels = null; Plugin.Log.LogInfo((object)"LethalLevelLoader found, but not a version this mod understands. Prices are set on the terminal pages directly instead."); } } } catch { _lllLevels = null; } } if (_lllLevels == null) { return null; } try { foreach (object lllLevel in _lllLevels) { if (lllLevel != null && _lllSelectable.GetValue(lllLevel) == level) { return lllLevel; } } } catch { } return null; } } internal static class Net { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnPrices; } private const string MsgName = "slivkonsin.UniversalMoonCostConfig.Prices"; private const float Heartbeat = 5f; private static CustomMessagingManager _registered; private static string _lastSent; private static string _lastReceived; private static float _nextSend; private static bool _dirty; public static Dictionary<string, int> HostPrices { get; private set; } public static bool IsClient { get; private set; } public static void MarkDirty() { _dirty = true; } public unsafe static void Update() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null) { _registered = null; IsClient = false; if (HostPrices != null) { HostPrices = null; Prices.MarkDirty(); } return; } if (_registered != singleton.CustomMessagingManager) { _registered = singleton.CustomMessagingManager; CustomMessagingManager registered = _registered; object obj = <>O.<0>__OnPrices; if (obj == null) { HandleNamedMessageDelegate val = OnPrices; <>O.<0>__OnPrices = val; obj = (object)val; } registered.RegisterNamedMessageHandler("slivkonsin.UniversalMoonCostConfig.Prices", (HandleNamedMessageDelegate)obj); HostPrices = null; _lastSent = (_lastReceived = null); _nextSend = 0f; } IsClient = !singleton.IsServer; if (IsClient || !Moons.Ready) { return; } string text = Serialize(Prices.Wanted()); if (!(text != _lastSent) && !_dirty && Time.realtimeSinceStartup < _nextSend) { return; } _dirty = false; _lastSent = text; _nextSend = Time.realtimeSinceStartup + 5f; if (singleton.ConnectedClientsIds.Count <= 1) { return; } try { FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(FastBufferWriter.GetWriteSize(text, false), (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe(text, false); _registered.SendNamedMessageToAll("slivkonsin.UniversalMoonCostConfig.Prices", val2, (NetworkDelivery)4); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't send prices to the other players: " + ex.Message)); } } private static string Serialize(Dictionary<string, int> d) { List<string> list = new List<string>(d.Keys); list.Sort(StringComparer.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder("1\n"); foreach (string item in list) { stringBuilder.Append(item).Append('=').Append(d[item].ToString(CultureInfo.InvariantCulture)) .Append('\n'); } return stringBuilder.ToString(); } private static void OnPrices(ulong sender, FastBufferReader r) { try { if (sender != 0L) { return; } string text = default(string); ((FastBufferReader)(ref r)).ReadValueSafe(ref text, false); if (text == _lastReceived) { return; } _lastReceived = text; Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); string[] array = text.Split('\n'); if (array.Length == 0 || array[0] != "1") { return; } for (int i = 1; i < array.Length; i++) { int num = array[i].LastIndexOf('='); if (num > 0 && int.TryParse(array[i].Substring(num + 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { dictionary[array[i].Substring(0, num)] = Mathf.Clamp(result, 0, 1000000); } } HostPrices = dictionary; Prices.MarkDirty(); Plugin.Log.LogInfo((object)$"Using the host's moon prices ({dictionary.Count} moons)."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't read the host's prices: " + ex.Message)); } } } [BepInPlugin("slivkonsin.UniversalMoonCostConfig", "Universal Moon Cost Config", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "slivkonsin.UniversalMoonCostConfig"; public const string Name = "Universal Moon Cost Config"; public const string Version = "1.0.0"; private const string LethalConfigGuid = "ainavt.lc.lethalconfig"; internal static ManualLogSource Log; internal static ConfigFile Cfg; internal static bool HasLethalConfig; private void Awake() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Cfg = ((BaseUnityPlugin)this).Config; HasLethalConfig = Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"); GameObject val = new GameObject("UniversalMoonCostConfig"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<Runner>(); SceneManager.sceneLoaded += delegate { Runner.OnSceneLoaded(); }; Log.LogInfo((object)"Universal Moon Cost Config 1.0.0 loaded."); } } internal sealed class Runner : MonoBehaviour { private static float _sceneLoadedAt; public static void OnSceneLoaded() { if ((Object)(object)StartOfRound.Instance == (Object)null && Moons.Ready) { Moons.Reset(); } _sceneLoadedAt = Time.realtimeSinceStartup; } private void Update() { try { Discover(); } catch (Exception ex) { DiagnosticsTelemetry.Errors++; Plugin.Log.LogWarning((object)("Finding moons: " + ex.Message)); } try { Net.Update(); } catch (Exception ex2) { DiagnosticsTelemetry.Errors++; Plugin.Log.LogWarning((object)("Price sync: " + ex2.Message)); } try { Prices.Update(); } catch (Exception ex3) { DiagnosticsTelemetry.Errors++; Plugin.Log.LogWarning((object)("Setting prices: " + ex3.Message)); } } private static void Discover() { if (Moons.Ready || (Object)(object)StartOfRound.Instance == (Object)null || Time.realtimeSinceStartup - _sceneLoadedAt < 1.5f) { return; } if (!Moons.Discover()) { _sceneLoadedAt = Time.realtimeSinceStartup; return; } Elsewhere.Check(Moons.All); Prices.Bind(Plugin.Cfg, Moons.All); if (Plugin.HasLethalConfig) { try { LethalConfigSupport.AddMoons(Moons.All); } catch (Exception ex) { Plugin.HasLethalConfig = false; Plugin.Log.LogWarning((object)("LethalConfig support off: " + ex.Message)); } } DiagnosticsTelemetry.MoonsFound = Moons.All.Count; DiagnosticsTelemetry.MoonsSetElsewhere = 0; foreach (Moon item in Moons.All) { if (item.SetElsewhere != null) { DiagnosticsTelemetry.MoonsSetElsewhere++; } } Plugin.Log.LogInfo((object)Prices.Summary()); Prices.MarkDirty(); Net.MarkDirty(); } } internal static class Prices { private const string PriceSection = "Moons"; private const string ElsewhereSection = "Moons set by other mods"; public const int UseOtherMod = -1; private const int MaxCorrections = 4; public static readonly Dictionary<string, ConfigEntry<int>> Price = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> Changed = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static float _checkTimer; private static bool _dirty = true; public static void MarkDirty() { _dirty = true; } public static void Bind(ConfigFile c, List<Moon> moons) { foreach (Moon moon2 in moons) { if (!Price.ContainsKey(moon2.Key)) { ConfigEntry<int> val = ((moon2.SetElsewhere == null) ? c.Bind<int>("Moons", moon2.Key, moon2.Original, $"Normal price: {moon2.Original}") : c.Bind<int>("Moons set by other mods", moon2.Key, -1, $"Normal price: {moon2.Original}. -1 = use {moon2.SetElsewhere.Short}. Any other number overrides it.")); Moon moon = moon2; val.SettingChanged += delegate { moon.GaveUp = false; moon.Corrections = 0; MarkDirty(); }; Price[moon2.Key] = val; } } } public static bool UsesOwnSetting(Moon m) { if (m.SetElsewhere != null) { if (Price.TryGetValue(m.Key, out var value)) { return value.Value >= 0; } return false; } return true; } public static Dictionary<string, int> Wanted() { Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); foreach (Moon item in Moons.All) { if (!item.GaveUp && UsesOwnSetting(item) && Price.TryGetValue(item.Key, out var value)) { int num = Mathf.Clamp(value.Value, 0, 1000000); if (num != item.Original || item.SetElsewhere != null) { dictionary[item.Key] = num; } } } return dictionary; } public static Dictionary<string, int> InEffect() { if (Net.IsClient) { return Net.HostPrices ?? new Dictionary<string, int>(); } return Wanted(); } public static void Update() { if (Moons.Ready) { _checkTimer -= Time.unscaledDeltaTime; if (_dirty || !(_checkTimer > 0f)) { _checkTimer = 2f; bool dirty = _dirty; _dirty = false; Apply(InEffect(), dirty); } } } private static void Apply(Dictionary<string, int> want, bool fromChange) { foreach (Moon item in Moons.All) { if (want.TryGetValue(item.Key, out var value)) { if (item.Current == value) { item.Applied = value; continue; } if (item.Applied == value && !fromChange) { item.Corrections++; if (item.Corrections > 4 && !Net.IsClient) { item.GaveUp = true; item.Applied = null; DiagnosticsTelemetry.MoonsGivenUp++; Plugin.Log.LogWarning((object)($"Something else keeps changing {item.Key}'s price (now {item.Current}). Leaving it alone so the two don't fight over it. " + "Change the setting to try again.")); Net.MarkDirty(); continue; } Plugin.Log.LogInfo((object)$"{item.Key}'s price was changed to {item.Current} by something else, setting it back to {value}."); DiagnosticsTelemetry.Corrections++; } if (Moons.SetPrice(item, value)) { item.Applied = value; Changed.Add(item.Key); } } else if (item.Applied.HasValue || Changed.Contains(item.Key)) { if (item.Current != item.Original) { Moons.SetPrice(item, item.Original); } item.Applied = null; Changed.Remove(item.Key); } } DiagnosticsTelemetry.MoonsManaged = 0; foreach (Moon item2 in Moons.All) { if (item2.Applied.HasValue) { DiagnosticsTelemetry.MoonsManaged++; } } } public static void RestoreAll() { foreach (Moon item in Moons.All) { if (item.Applied.HasValue || Changed.Contains(item.Key)) { if (item.Current != item.Original) { Moons.SetPrice(item, item.Original); } item.Applied = null; } } Changed.Clear(); } public static string Summary() { StringBuilder stringBuilder = new StringBuilder($"Found {Moons.All.Count} moons:"); foreach (Moon item in Moons.All) { stringBuilder.Append($"\n {item.Key,-22} own price {item.Original,6}"); if (item.SetElsewhere != null) { stringBuilder.Append(UsesOwnSetting(item) ? (" (also in " + item.SetElsewhere.Mod + "'s config, overridden here)") : $" -> set in {item.SetElsewhere}"); } } return stringBuilder.ToString(); } } public static class DiagnosticsTelemetry { public static int MoonsFound; public static int MoonsSetElsewhere; public static int MoonsManaged; public static int Corrections; public static int MoonsGivenUp; public static int Errors; } }