Decompiled source of UniversalMoonCostConfig v1.0.0

UniversalMoonCostConfig.dll

Decompiled 7 hours ago
using 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;
	}
}