Decompiled source of Bottleneck v1.1.7

Bottleneck.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Bottleneck.Nebula;
using Bottleneck.Stats;
using Bottleneck.UI;
using Bottleneck.Util;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NebulaAPI;
using NebulaAPI.Networking;
using NebulaAPI.Packets;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Bottleneck")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Better production stats and production bottleneck finder")]
[assembly: AssemblyFileVersion("1.1.7.0")]
[assembly: AssemblyInformationalVersion("1.1.7")]
[assembly: AssemblyProduct("Bottleneck")]
[assembly: AssemblyTitle("Bottleneck")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.7.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace Bottleneck
{
	[BepInPlugin("Bottleneck", "Bottleneck", "1.1.7")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class BottleneckPlugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "Bottleneck";

		private Harmony _harmony;

		private static BottleneckPlugin instance;

		private BetterStats _betterStatsObj;

		private readonly HashSet<int> _itemFilter = new HashSet<int>();

		private int _targetItemId = -1;

		private static bool _successor;

		private bool _deficientOnlyMode;

		private static readonly Texture2D filterTexture = Resources.Load<Texture2D>("ui/textures/sprites/icons/filter-icon-16");

		private readonly Dictionary<UIProductEntry, BottleneckProductEntryElement> _uiElements = new Dictionary<UIProductEntry, BottleneckProductEntryElement>();

		private readonly List<GameObject> objsToDestroy = new List<GameObject>();

		private GameObject _enablePrecursorGO;

		private Button _clearFilterBtn;

		private GameObject _clearFilterTextGO;

		private Sprite _filterSprite;

		private Image _precursorCheckBoxImage;

		private GameObject _enablePrecursorTextGO;

		internal readonly Dictionary<int, PlanetaryProductionSummary> _productionLocations = new Dictionary<int, PlanetaryProductionSummary>();

		private bool isCalculating;

		private int lastAstroFilter;

		internal bool _enableMadeOn;

		private readonly Dictionary<UIButton, FilterButtonItemAge> _buttonTipAge = new Dictionary<UIButton, FilterButtonItemAge>();

		public static BottleneckPlugin Instance => instance;

		public bool IsFactoryDataDirty { get; set; }

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Log.logger = ((BaseUnityPlugin)this).Logger;
			instance = this;
			_harmony = new Harmony("Bottleneck");
			_harmony.PatchAll(typeof(BottleneckPlugin));
			_harmony.PatchAll(typeof(Strings));
			_harmony.PatchAll(typeof(ResearchTechHelper));
			PluginConfig.InitConfig(((BaseUnityPlugin)this).Config);
			_betterStatsObj = ((Component)this).gameObject.AddComponent<BetterStats>();
			Log.Info("Plugin Bottleneck 1.1.7 is loaded!");
			if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer"))
			{
				NebulaCompat.Init(_harmony);
			}
		}

		private void ClearUI()
		{
			if ((Object)(object)_enablePrecursorGO != (Object)null)
			{
				Object.Destroy((Object)(object)_enablePrecursorTextGO);
				Object.Destroy((Object)(object)_enablePrecursorGO);
			}
			if ((Object)(object)_clearFilterTextGO != (Object)null)
			{
				Object.Destroy((Object)(object)_clearFilterTextGO);
			}
			if ((Object)(object)_precursorCheckBoxImage != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_precursorCheckBoxImage).gameObject);
			}
			if ((Object)(object)_clearFilterBtn != (Object)null && (Object)(object)((Component)_clearFilterBtn).gameObject != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_clearFilterBtn).gameObject);
			}
			foreach (GameObject item in objsToDestroy)
			{
				Object.Destroy((Object)(object)item);
			}
			objsToDestroy.Clear();
			foreach (BottleneckProductEntryElement value in _uiElements.Values)
			{
				if ((Object)(object)value.precursorButton != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value.precursorButton).gameObject);
				}
				if ((Object)(object)value.successorButton != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value.successorButton).gameObject);
				}
			}
			_uiElements.Clear();
		}

		[HarmonyPrefix]
		[HarmonyPriority(200)]
		[HarmonyPatch(typeof(UIStatisticsWindow), "ValueToAstroBox")]
		public static void UIStatisticsWindow__ValueToAstroBox_Postfix(UIStatisticsWindow __instance)
		{
			if (!__instance.isStatisticsTab || NebulaCompat.IsClient || !PluginConfig.planetFilter.Value)
			{
				return;
			}
			UIComboBox astroBox = __instance.astroBox;
			if (!__instance.isDysonTab && __instance.gameData.localPlanet != null && astroBox.Items.Count > 2)
			{
				int id = __instance.gameData.localStar.id;
				if (astroBox.Items[2] != Strings.LocalSystemLabel)
				{
					astroBox.Items.Insert(2, Strings.LocalSystemLabel);
					astroBox.ItemsData.Insert(2, id * 100);
				}
			}
			if (instance._itemFilter.Count == 0)
			{
				return;
			}
			List<string> list = new List<string>();
			List<int> list2 = new List<int>();
			int num = -1;
			string item = "";
			for (int i = 0; i < astroBox.Items.Count; i++)
			{
				int num2 = astroBox.ItemsData[i];
				if (num2 <= 0)
				{
					list2.Add(num2);
					list.Add(astroBox.Items[i]);
					continue;
				}
				if (num2 % 100 == 0)
				{
					num = num2;
					item = UIRoot.instance.uiGame.statWindow.gameData.galaxy.StarById(num2 / 100).displayName + Localization.Translate("空格行星系");
					continue;
				}
				PlanetData val = GameMain.data.galaxy.PlanetById(num2);
				if (val != null && instance._productionLocations.TryGetValue(instance._targetItemId, out var value) && ((_successor && value.IsConsumerPlanet(val.id)) || (!_successor && value.IsProducerPlanet(val.id))))
				{
					if (num > 0 && PluginConfig.systemFilter.Value)
					{
						list2.Add(num);
						list.Add(item);
						num = -1;
					}
					list2.Add(num2);
					list.Add(astroBox.Items[i]);
				}
			}
			lock (__instance.astroBox.Items)
			{
				__instance.astroBox.Items.Clear();
				__instance.astroBox.ItemsData.Clear();
				__instance.astroBox.Items.AddRange(list);
				__instance.astroBox.ItemsData.AddRange(list2);
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		[HarmonyPatch(typeof(UIStatisticsWindow), "_OnClose")]
		public static void UIStatisticsWindow__OnClose_Postfix()
		{
			BetterStats.UIStatisticsWindow__OnClose_Postfix();
		}

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		[HarmonyPatch(typeof(UIStatisticsWindow), "_OnOpen")]
		public static void UIStatisticsWindow__OnOpen_Postfix(UIStatisticsWindow __instance)
		{
			BetterStats.UIStatisticsWindow__OnOpen_Postfix(__instance);
			if ((Object)(object)((Component)instance).gameObject != (Object)null && !PluginConfig.statsOnly.Value)
			{
				instance.AddEnablePrecursorFilterButton(__instance);
				instance._enableMadeOn = NebulaCompat.IsClient;
				instance.IsFactoryDataDirty = true;
				NebulaCompat.OnWindowOpen();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIStatisticsWindow), "OnTabButtonClick")]
		public static void UIStatisticsWindow_OnTabButtonClick_Postfix(UIStatisticsWindow __instance)
		{
			BetterStats.UIStatisticsWindow_OnTabButtonClick_Postfix(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIProductEntryList), "FilterEntries")]
		public static void UIProductEntryList_FilterEntries_Postfix(UIProductEntryList __instance)
		{
			if (BetterStats.filterStr != "")
			{
				HashSet<int> itemsToShow = instance.GetItemsToShow(__instance);
				BetterStats.UIProductEntryList_FilterEntries_Postfix(__instance, itemsToShow);
			}
			else
			{
				instance.FilterEntries(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIKillEntryList), "FilterEntries")]
		public static void UIKillEntryList_FilterEntries_Postfix(UIKillEntryList __instance)
		{
			if (BetterStats.filterStr != "")
			{
				BetterStats.UIKillEntryList_FilterEntries_Postfix(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIStatisticsWindow), "_OnUpdate")]
		public static void UIStatisticsWindow__OnUpdate_Prefix(UIStatisticsWindow __instance)
		{
			BetterStats.UIStatisticsWindow__OnUpdate_Prefix(__instance);
			if (!PluginConfig.statsOnly.Value)
			{
				instance.UpdateButtonState();
			}
		}

		private void UpdateButtonState()
		{
			if (!((Object)(object)_clearFilterBtn == (Object)null) && !((Object)(object)((Component)_clearFilterBtn).gameObject == (Object)null) && !((Object)(object)_clearFilterTextGO == (Object)null))
			{
				if (_targetItemId == -1)
				{
					((Component)_clearFilterBtn).gameObject.SetActive(false);
					_clearFilterTextGO.SetActive(false);
				}
				else
				{
					((Component)_clearFilterBtn).gameObject.SetActive(true);
					_clearFilterTextGO.SetActive(true);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		[HarmonyPatch(typeof(UIProductEntry), "_OnUpdate")]
		public static void UIProductEntry__OnUpdate_Postfix(UIProductEntry __instance)
		{
			BetterStats.UIProductEntry__OnUpdate_Postfix(__instance);
			if (!PluginConfig.statsOnly.Value)
			{
				instance.OnUpdateEnhance(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		[HarmonyPatch(typeof(UIKillEntry), "_OnUpdate")]
		public static void UIKillEntry__OnUpdate_Postfix(UIKillEntry __instance)
		{
			BetterStats.UIKillEntry__OnUpdate_Postfix(__instance);
		}

		private void ClearFilter()
		{
			_itemFilter.Clear();
			_targetItemId = -1;
			UIRoot.instance.uiGame.statWindow.RefreshAstroBox();
			SetFilterHighLight(-1, successor: false);
		}

		private void SetFilterHighLight(int itemId, bool successor)
		{
			foreach (KeyValuePair<UIProductEntry, BottleneckProductEntryElement> uiElement in _uiElements)
			{
				if ((Object)(object)uiElement.Value.precursorButton != (Object)null)
				{
					UIButton precursorButton = uiElement.Value.precursorButton;
					int highlighted;
					if (!successor)
					{
						UIProductEntryData entryData = uiElement.Key.entryData;
						highlighted = ((entryData != null && entryData.itemId == itemId) ? 1 : 0);
					}
					else
					{
						highlighted = 0;
					}
					precursorButton.highlighted = (byte)highlighted != 0;
				}
				if ((Object)(object)uiElement.Value.successorButton != (Object)null)
				{
					UIButton successorButton = uiElement.Value.successorButton;
					int highlighted2;
					if (successor)
					{
						UIProductEntryData entryData2 = uiElement.Key.entryData;
						highlighted2 = ((entryData2 != null && entryData2.itemId == itemId) ? 1 : 0);
					}
					else
					{
						highlighted2 = 0;
					}
					successorButton.highlighted = (byte)highlighted2 != 0;
				}
			}
		}

		private BottleneckProductEntryElement EnhanceElement(UIProductEntry productEntry)
		{
			//IL_002f: 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)
			UIButton val = Bottleneck.UI.Util.CopyButton(productEntry, productEntry.favoriteBtn1, new Vector2(167f, 60f), productEntry.entryData.itemId, delegate
			{
				UpdatePrecursorFilter(productEntry.entryData.itemId);
			}, _filterSprite);
			objsToDestroy.Add(((Component)val).gameObject);
			UIButton val2 = Bottleneck.UI.Util.CopyButton(productEntry, productEntry.favoriteBtn1, new Vector2(167f, 0f), productEntry.entryData.itemId, delegate
			{
				UpdatePrecursorFilter(productEntry.entryData.itemId, successor: true);
			}, _filterSprite);
			objsToDestroy.Add(((Component)val2).gameObject);
			BottleneckProductEntryElement bottleneckProductEntryElement = new BottleneckProductEntryElement
			{
				precursorButton = val,
				successorButton = val2
			};
			_uiElements.Add(productEntry, bottleneckProductEntryElement);
			return bottleneckProductEntryElement;
		}

		private void UpdatePrecursorFilter(int itemId, bool successor = false)
		{
			if (_targetItemId == itemId && _successor == successor && _deficientOnlyMode == VFInput.control)
			{
				ClearFilter();
				return;
			}
			_itemFilter.Clear();
			_itemFilter.Add(itemId);
			_targetItemId = itemId;
			_successor = successor;
			_deficientOnlyMode = VFInput.control;
			if (!successor)
			{
				List<int> list = ItemUtil.DirectPrecursorItems(itemId);
				foreach (int item in list)
				{
					_itemFilter.Add(item);
				}
				if (PluginConfig.includeSecondLevelConsumerProducer.Value)
				{
					foreach (int item2 in list)
					{
						foreach (int item3 in ItemUtil.DirectPrecursorItems(item2))
						{
							_itemFilter.Add(item3);
						}
					}
				}
			}
			else
			{
				List<int> list2 = ItemUtil.DirectSuccessorItems(itemId);
				foreach (int item4 in list2)
				{
					_itemFilter.Add(item4);
				}
				if (PluginConfig.includeSecondLevelConsumerProducer.Value)
				{
					foreach (int item5 in list2)
					{
						foreach (int item6 in ItemUtil.DirectSuccessorItems(item5))
						{
							_itemFilter.Add(item6);
						}
					}
				}
			}
			UIRoot.instance.uiGame.statWindow.RefreshAstroBox();
			BetterStats.filterStr = "";
		}

		private HashSet<int> GetItemsToShow(UIProductEntryList uiProductEntryList)
		{
			HashSet<int> hashSet = new HashSet<int>();
			if (_itemFilter.Count == 0)
			{
				return hashSet;
			}
			for (int num = uiProductEntryList.entryDatasCursor - 1; num >= 0; num--)
			{
				UIProductEntryData val = uiProductEntryList.entryDatas[num];
				bool flag = !_itemFilter.Contains(val.itemId);
				if (_deficientOnlyMode && val.itemId != _targetItemId)
				{
					flag = !ProductionDeficit.IsDeficitItemFor(val.itemId, _targetItemId);
				}
				if (!flag)
				{
					hashSet.Add(val.itemId);
				}
			}
			return hashSet;
		}

		private void FilterEntries(UIProductEntryList uiProductEntryList)
		{
			if (_itemFilter.Count == 0)
			{
				return;
			}
			for (int num = uiProductEntryList.entryDatasCursor - 1; num >= 0; num--)
			{
				UIProductEntryData val = uiProductEntryList.entryDatas[num];
				bool flag = !_itemFilter.Contains(val.itemId);
				if (_deficientOnlyMode && val.itemId != _targetItemId)
				{
					flag = !ProductionDeficit.IsDeficitItemFor(val.itemId, _targetItemId);
				}
				if (flag)
				{
					uiProductEntryList.Swap(num, uiProductEntryList.entryDatasCursor - 1);
					uiProductEntryList.entryDatasCursor--;
				}
			}
			SetFilterHighLight(_targetItemId, _successor);
		}

		private void AddEnablePrecursorFilterButton(UIStatisticsWindow uiStatisticsWindow)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_enablePrecursorGO != (Object)null))
			{
				_filterSprite = Sprite.Create(filterTexture, new Rect(0f, 0f, (float)((Texture)filterTexture).width * 0.75f, (float)((Texture)filterTexture).height * 0.75f), new Vector2(0.5f, 0.5f));
				_enablePrecursorGO = new GameObject("enablePrecursor");
				RectTransform val = _enablePrecursorGO.AddComponent<RectTransform>();
				((Transform)val).SetParent(((Component)uiStatisticsWindow.productSortBox).transform.parent, false);
				val.anchorMax = new Vector2(0f, 1f);
				val.anchorMin = new Vector2(0f, 1f);
				val.sizeDelta = new Vector2(20f, 20f);
				val.pivot = new Vector2(0f, 0.5f);
				val.anchoredPosition = new Vector2(350f, -33f);
				objsToDestroy.Add(((Component)val).gameObject);
				_clearFilterBtn = ((Component)val).gameObject.AddComponent<Button>();
				((UnityEvent)_clearFilterBtn.onClick).AddListener(new UnityAction(ClearFilter));
				_precursorCheckBoxImage = ((Component)_clearFilterBtn).gameObject.AddComponent<Image>();
				((Graphic)_precursorCheckBoxImage).color = new Color(0.8f, 0.8f, 0.8f, 1f);
				_precursorCheckBoxImage.sprite = _filterSprite;
				_enablePrecursorTextGO = new GameObject("enablePrecursorText");
				RectTransform val2 = _enablePrecursorTextGO.AddComponent<RectTransform>();
				((Transform)val2).SetParent(_enablePrecursorGO.transform, false);
				val2.anchorMax = new Vector2(0f, 0.5f);
				val2.anchorMin = new Vector2(0f, 0.5f);
				val2.sizeDelta = new Vector2(100f, 20f);
				val2.pivot = new Vector2(0f, 0.5f);
				val2.anchoredPosition = new Vector2(20f, 0f);
				objsToDestroy.Add(((Component)val2).gameObject);
				Text val3 = ((Component)val2).gameObject.AddComponent<Text>();
				val3.text = Strings.ClearFilterLabel;
				val3.fontStyle = (FontStyle)0;
				val3.fontSize = 12;
				val3.verticalOverflow = (VerticalWrapMode)1;
				val3.horizontalOverflow = (HorizontalWrapMode)0;
				((Graphic)val3).color = new Color(0.8f, 0.8f, 0.8f, 1f);
				Font val4 = Resources.Load<Font>("ui/fonts/SAIRASB");
				if ((Object)(object)val4 != (Object)null)
				{
					val3.font = val4;
				}
				_clearFilterTextGO = ((Component)val3).gameObject;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIStatisticsWindow), "ComputeDisplayProductEntries")]
		public static void UIProductionStatWindow_ComputeDisplayEntries_Prefix(UIStatisticsWindow __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				if ((Object)(object)instance._betterStatsObj != (Object)null && PluginConfig.statsOnly.Value)
				{
					BetterStats.UIProductionStatWindow_ComputeDisplayProductEntries_Prefix(__instance);
				}
				else
				{
					instance.RecordEntryData(__instance);
				}
			}
		}

		private void RecordEntryData(UIStatisticsWindow uiStatsWindow)
		{
			if (NebulaCompat.IsClient && uiStatsWindow.astroFilter != lastAstroFilter)
			{
				if (!_enableMadeOn)
				{
					_productionLocations.Clear();
					_enableMadeOn = true;
					return;
				}
				lastAstroFilter = uiStatsWindow.astroFilter;
				if (uiStatsWindow.astroFilter != NebulaCompat.LastAstroFilter)
				{
					NebulaCompat.SendRequest(ERequest.Bottleneck);
				}
			}
			else if (!isCalculating)
			{
				if (!_enableMadeOn)
				{
					isCalculating = true;
					Task.Run((Action)ProcessMadeOnTask);
				}
				else if (IsFactoryDataDirty || uiStatsWindow.astroFilter != lastAstroFilter)
				{
					isCalculating = true;
					lastAstroFilter = uiStatsWindow.astroFilter;
					IsFactoryDataDirty = false;
					Task.Run((Action)ProcessDeficitTask);
				}
			}
		}

		public void ProcessMadeOnTask()
		{
			isCalculating = true;
			_productionLocations.Clear();
			for (int i = 0; i < GameMain.data.factoryCount; i++)
			{
				AddPlanetFactoryData(GameMain.data.factories[i], planetUsage: true);
			}
			_enableMadeOn = true;
			isCalculating = false;
		}

		private void ProcessDeficitTask()
		{
			isCalculating = true;
			UIStatisticsWindow statWindow = UIRoot.instance.uiGame.statWindow;
			ProductionDeficit.Clear();
			BetterStats.counter.Clear();
			if (statWindow.astroFilter == -1)
			{
				int factoryCount = statWindow.gameData.factoryCount;
				for (int i = 0; i < factoryCount; i++)
				{
					AddPlanetFactoryData(statWindow.gameData.factories[i], planetUsage: false);
				}
			}
			else if (statWindow.astroFilter == 0)
			{
				if (statWindow.gameData.localPlanet.factory != null)
				{
					AddPlanetFactoryData(statWindow.gameData.localPlanet.factory, planetUsage: false);
				}
			}
			else if (statWindow.astroFilter % 100 > 0)
			{
				PlanetData val = statWindow.gameData.galaxy.PlanetById(statWindow.astroFilter);
				if (val != null)
				{
					AddPlanetFactoryData(val.factory, planetUsage: false);
				}
			}
			else if (statWindow.astroFilter % 100 == 0)
			{
				int num = statWindow.astroFilter / 100;
				StarData val2 = statWindow.gameData.galaxy.StarById(num);
				for (int j = 0; j < val2.planetCount; j++)
				{
					if (val2.planets[j].factory != null)
					{
						AddPlanetFactoryData(val2.planets[j].factory, planetUsage: false);
					}
				}
			}
			isCalculating = false;
		}

		public void AddPlanetFactoryData(PlanetFactory planetFactory, bool planetUsage)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Invalid comparison between Unknown and I4
			if (planetFactory == null)
			{
				return;
			}
			int maxPilerStackingUnlocked = ResearchTechHelper.GetMaxPilerStackingUnlocked();
			FactorySystem factorySystem = planetFactory.factorySystem;
			VeinData[] veinPool = planetFactory.planet.factory.veinPool;
			int waterItemId = planetFactory.planet.waterItemId;
			for (int i = 1; i < factorySystem.minerCursor; i++)
			{
				ref MinerComponent reference = ref factorySystem.minerPool[i];
				if (i != reference.id)
				{
					continue;
				}
				if (!planetUsage)
				{
					BetterStats.RecordMinerStats(in reference, planetFactory, waterItemId);
					continue;
				}
				int num = reference.productId;
				int num2 = ((reference.veinCount != 0) ? reference.veins[reference.currentVeinIndex] : 0);
				if ((int)reference.type == 1)
				{
					num = planetFactory.planet.waterItemId;
				}
				else if (num == 0)
				{
					num = veinPool[num2].productId;
				}
				if (num != 0)
				{
					AddPlanetaryUsage(num, planetFactory.planet);
				}
			}
			float maxProductivityIncrease = ResearchTechHelper.GetMaxProductivityIncrease();
			float maxSpeedIncrease = ResearchTechHelper.GetMaxSpeedIncrease();
			if (PluginConfig.disableProliferatorCalc.Value)
			{
				maxProductivityIncrease = 0f;
				maxSpeedIncrease = 0f;
			}
			for (int j = 1; j < factorySystem.assemblerCursor; j++)
			{
				ref AssemblerComponent reference2 = ref factorySystem.assemblerPool[j];
				if (reference2.id != j || reference2.recipeId == 0)
				{
					continue;
				}
				int[] requires;
				if (planetUsage)
				{
					requires = reference2.requires;
					foreach (int productId in requires)
					{
						AddPlanetaryUsage(productId, planetFactory.planet, consumption: true);
					}
				}
				else
				{
					BetterStats.RecordAssemblerStats(in reference2, maxSpeedIncrease, maxProductivityIncrease);
				}
				requires = reference2.products;
				foreach (int num3 in requires)
				{
					if (planetUsage)
					{
						AddPlanetaryUsage(num3, planetFactory.planet);
					}
					else
					{
						ProductionDeficit.RecordDeficit(num3, in reference2, planetFactory);
					}
				}
			}
			for (int l = 1; l < factorySystem.fractionatorCursor; l++)
			{
				ref FractionatorComponent reference3 = ref factorySystem.fractionatorPool[l];
				if (reference3.id != l)
				{
					continue;
				}
				if (!planetUsage)
				{
					BetterStats.RecordFractionatorStats(in reference3, maxSpeedIncrease, maxPilerStackingUnlocked);
					continue;
				}
				if (reference3.fluidId != 0)
				{
					AddPlanetaryUsage(reference3.fluidId, planetFactory.planet, consumption: true);
				}
				if (reference3.productId != 0)
				{
					AddPlanetaryUsage(reference3.productId, planetFactory.planet);
				}
			}
			for (int m = 1; m < factorySystem.ejectorCursor; m++)
			{
				ref EjectorComponent reference4 = ref factorySystem.ejectorPool[m];
				if (reference4.id == m)
				{
					if (!planetUsage)
					{
						BetterStats.RecordEjectorStats(in reference4);
					}
					else
					{
						AddPlanetaryUsage(reference4.bulletId, planetFactory.planet, consumption: true);
					}
				}
			}
			for (int n = 1; n < factorySystem.siloCursor; n++)
			{
				ref SiloComponent reference5 = ref factorySystem.siloPool[n];
				if (reference5.id == n)
				{
					if (!planetUsage)
					{
						BetterStats.RecordSiloStats(in reference5);
					}
					else
					{
						AddPlanetaryUsage(reference5.bulletId, planetFactory.planet, consumption: true);
					}
				}
			}
			for (int num4 = 1; num4 < factorySystem.labCursor; num4++)
			{
				ref LabComponent reference6 = ref factorySystem.labPool[num4];
				if (reference6.id != num4)
				{
					continue;
				}
				if (!planetUsage)
				{
					BetterStats.RecordLabStats(in reference6, maxSpeedIncrease, maxProductivityIncrease);
				}
				if (((LabComponent)(ref reference6)).matrixMode)
				{
					int[] requires;
					if (planetUsage)
					{
						requires = reference6.requires;
						foreach (int productId2 in requires)
						{
							AddPlanetaryUsage(productId2, planetFactory.planet, consumption: true);
						}
					}
					requires = reference6.products;
					foreach (int num5 in requires)
					{
						if (planetUsage)
						{
							AddPlanetaryUsage(num5, planetFactory.planet);
						}
						else
						{
							ProductionDeficit.RecordDeficit(num5, in reference6, planetFactory);
						}
					}
				}
				else if (reference6.researchMode && planetUsage && reference6.techId > 0)
				{
					TechProto val = ((ProtoSet<TechProto>)(object)LDB.techs).Select(reference6.techId);
					for (int num6 = 0; num6 < val.itemArray.Length; num6++)
					{
						int productId3 = val.Items[num6];
						AddPlanetaryUsage(productId3, planetFactory.planet, consumption: true);
					}
				}
			}
			double gasTotalHeat = planetFactory.planet.gasTotalHeat;
			double collectorsWorkCost = planetFactory.transport.collectorsWorkCost;
			if (!planetUsage)
			{
				for (int num7 = 1; num7 < planetFactory.transport.stationCursor; num7++)
				{
					StationComponent station = planetFactory.transport.stationPool[num7];
					BetterStats.RecordOrbitalCollectorStats(in station, gasTotalHeat, collectorsWorkCost);
				}
			}
			for (int num8 = 1; num8 < planetFactory.powerSystem.genCursor; num8++)
			{
				ref PowerGeneratorComponent reference7 = ref planetFactory.powerSystem.genPool[num8];
				if (reference7.id != num8)
				{
					continue;
				}
				if (!planetUsage)
				{
					BetterStats.RecordGeneratorStats(in reference7);
				}
				bool flag = reference7.curFuelId > 0 && reference7.productId == 0;
				if ((reference7.productId == 0 || reference7.productHeat == 0L) && !flag)
				{
					continue;
				}
				if (flag)
				{
					short curFuelId = reference7.curFuelId;
					if (planetUsage)
					{
						AddPlanetaryUsage(curFuelId, planetFactory.planet, consumption: true);
					}
					continue;
				}
				int productId4 = reference7.productId;
				if (planetUsage)
				{
					AddPlanetaryUsage(productId4, planetFactory.planet);
				}
				if (reference7.catalystId > 0)
				{
					if (planetUsage)
					{
						AddPlanetaryUsage(productId4, planetFactory.planet);
					}
					else
					{
						ProductionDeficit.RecordDeficit(reference7.productId, in reference7, planetFactory);
					}
				}
			}
			for (int num9 = 1; num9 < planetFactory.powerSystem.excCursor; num9++)
			{
				ref PowerExchangerComponent reference8 = ref planetFactory.powerSystem.excPool[num9];
				if (reference8.id == num9)
				{
					if (!planetUsage)
					{
						BetterStats.RecordPowerExchangerStats(in reference8, maxSpeedIncrease);
					}
					else if (reference8.state == 1f)
					{
						AddPlanetaryUsage(reference8.fullId, planetFactory.planet);
						AddPlanetaryUsage(reference8.emptyId, planetFactory.planet, consumption: true);
					}
					else if (reference8.state == -1f)
					{
						AddPlanetaryUsage(reference8.emptyId, planetFactory.planet);
						AddPlanetaryUsage(reference8.fullId, planetFactory.planet, consumption: true);
					}
				}
			}
			if (!planetUsage)
			{
				BetterStats.RecordSprayCoaterStats(planetFactory, maxProductivityIncrease);
				return;
			}
			for (int num10 = 1; num10 < planetFactory.cargoTraffic.spraycoaterCursor; num10++)
			{
				ref SpraycoaterComponent reference9 = ref planetFactory.cargoTraffic.spraycoaterPool[num10];
				if (reference9.id == num10 && reference9.incItemId >= 1)
				{
					AddPlanetaryUsage(reference9.incItemId, planetFactory.planet, consumption: true);
				}
			}
		}

		private void AddPlanetaryUsage(int productId, PlanetData planet, bool consumption = false)
		{
			if (!_productionLocations.ContainsKey(productId))
			{
				_productionLocations[productId] = new PlanetaryProductionSummary();
			}
			if (consumption)
			{
				_productionLocations[productId].AddConsumption(planet.id, 1);
			}
			else
			{
				_productionLocations[productId].AddProduction(planet.id, 1);
			}
		}

		private void OnUpdateEnhance(UIProductEntry productEntry)
		{
			if (!((Object)(object)productEntry.productionStatWindow == (Object)null) && productEntry.productionStatWindow.isProductionTab)
			{
				BottleneckProductEntryElement enhanceElement = GetEnhanceElement(productEntry);
				if ((Object)(object)enhanceElement.precursorButton != (Object)null && ButtonOutOfDate(enhanceElement.precursorButton, productEntry.entryData.itemId))
				{
					int itemId = productEntry.entryData.itemId;
					GetPrecursorButtonTip(itemId, out enhanceElement.precursorButton.tips.tipTitle, out enhanceElement.precursorButton.tips.tipText);
					UpdateButtonUpdateDate(enhanceElement.precursorButton, itemId);
				}
				if ((Object)(object)enhanceElement.successorButton != (Object)null && ButtonOutOfDate(enhanceElement.successorButton, productEntry.entryData.itemId))
				{
					int itemId2 = productEntry.entryData.itemId;
					GetSuccessorButtonTip(itemId2, out enhanceElement.successorButton.tips.tipTitle, out enhanceElement.successorButton.tips.tipText);
					UpdateButtonUpdateDate(enhanceElement.successorButton, itemId2);
				}
			}
		}

		public BottleneckProductEntryElement GetEnhanceElement(UIProductEntry productEntry)
		{
			if (!_uiElements.TryGetValue(productEntry, out var value))
			{
				return EnhanceElement(productEntry);
			}
			return value;
		}

		public void GetPrecursorButtonTip(int productId, out string tipTitle, out string tipText)
		{
			tipTitle = Strings.ProdDetailsLabel;
			tipText = "";
			if (NebulaCompat.IsClient)
			{
				tipText = "(...)";
				NebulaCompat.SendEntryRequest(productId, isPrecursor: true);
				return;
			}
			if (ItemUtil.HasPrecursors(productId))
			{
				tipTitle += Strings.ClickPrecursorText;
			}
			if (!_productionLocations.ContainsKey(productId))
			{
				return;
			}
			if (_enableMadeOn)
			{
				string text = (ItemUtil.HasPrecursors(productId) ? Strings.ControlClickLacking : "");
				string producedOnLabel = Strings.ProducedOnLabel;
				tipText = text + "<b>" + producedOnLabel + "</b>\r\n" + _productionLocations[productId].GetProducerSummary();
				if (_productionLocations[productId].ProducerPlanetCount() > PluginConfig.productionPlanetCount.Value)
				{
					tipTitle += $" (top {PluginConfig.productionPlanetCount.Value} / {_productionLocations[productId].ProducerPlanetCount()} planets)";
				}
			}
			else
			{
				tipText = "Calculating...";
			}
			string text2 = ProductionDeficit.MostNeeded(productId);
			if (text2.Length > 0)
			{
				tipText = tipText + "\r\n<b>" + Strings.BottlenecksLabel + "</b>\r\n" + text2;
			}
		}

		public void GetSuccessorButtonTip(int productId, out string tipTitle, out string tipText)
		{
			tipTitle = Strings.ConDetailsLabel;
			tipText = "";
			if (NebulaCompat.IsClient)
			{
				tipText = "(...)";
				NebulaCompat.SendEntryRequest(productId, isPrecursor: false);
				return;
			}
			if (ItemUtil.HasConsumers(productId))
			{
				tipTitle += Strings.ClickConsumingText;
			}
			if (_productionLocations.ContainsKey(productId) && _enableMadeOn)
			{
				string consumedOnLabel = Strings.ConsumedOnLabel;
				tipText = "<b>" + consumedOnLabel + "</b>\r\n" + _productionLocations[productId].GetConsumerSummary();
				if (_productionLocations[productId].ConsumerPlanetCount() > PluginConfig.productionPlanetCount.Value)
				{
					tipTitle += $" (top {PluginConfig.productionPlanetCount.Value} / {_productionLocations[productId].ConsumerPlanetCount()} planets)";
				}
			}
		}

		private void UpdateButtonUpdateDate(UIButton uiButton, int productId)
		{
			_buttonTipAge[uiButton] = new FilterButtonItemAge(uiButton, productId)
			{
				lastUpdated = DateTime.Now
			};
		}

		private bool ButtonOutOfDate(UIButton uiButton, int entryDataItemId)
		{
			if (_buttonTipAge.TryGetValue(uiButton, out var value))
			{
				if (value.itemId != entryDataItemId)
				{
					return true;
				}
				if (NebulaCompat.IsClient)
				{
					return false;
				}
				return (DateTime.Now - value.lastUpdated).TotalSeconds > 4.0;
			}
			_buttonTipAge[uiButton] = new FilterButtonItemAge(uiButton, entryDataItemId)
			{
				lastUpdated = DateTime.Now
			};
			return true;
		}
	}
	public class FilterButtonItemAge : IComparable<FilterButtonItemAge>, IEquatable<FilterButtonItemAge>
	{
		public readonly UIButton uiButton;

		public readonly int itemId;

		public DateTime lastUpdated;

		public FilterButtonItemAge(UIButton uiButton, int itemId)
		{
			this.uiButton = uiButton;
			this.itemId = itemId;
		}

		public int CompareTo(FilterButtonItemAge other)
		{
			if (uiButton != other.uiButton)
			{
				return ((Object)uiButton).GetInstanceID().CompareTo(((Object)other.uiButton).GetInstanceID());
			}
			int num = itemId;
			return num.CompareTo(other.itemId);
		}

		public bool Equals(FilterButtonItemAge other)
		{
			if (other == null)
			{
				return false;
			}
			if (uiButton == other.uiButton)
			{
				return itemId == other.itemId;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((Object)uiButton).GetInstanceID() + itemId;
		}
	}
	public class PlanetaryProductionSummary
	{
		private readonly Dictionary<int, int> _planetProducerCount = new Dictionary<int, int>();

		private readonly Dictionary<int, int> _planetCosumerCount = new Dictionary<int, int>();

		private bool _prodSummaryTextDirty = true;

		private string _prodSummary = "";

		private bool _consumerSummaryTextDirty = true;

		private string _consumerSummary = "";

		public void AddProduction(int planetId, int producerCount)
		{
			if (_planetProducerCount.TryGetValue(planetId, out var value))
			{
				_planetProducerCount[planetId] = value + producerCount;
			}
			else
			{
				_planetProducerCount[planetId] = producerCount;
			}
			_prodSummaryTextDirty = true;
		}

		public void AddConsumption(int planetId, int consumerCount)
		{
			if (_planetCosumerCount.TryGetValue(planetId, out var value))
			{
				_planetCosumerCount[planetId] = value + consumerCount;
			}
			else
			{
				_planetCosumerCount[planetId] = consumerCount;
			}
			_consumerSummaryTextDirty = true;
		}

		public string GetProducerSummary()
		{
			if (!_prodSummaryTextDirty)
			{
				return _prodSummary;
			}
			string producersLabel = Strings.ProducersLabel;
			IEnumerable<string> values = from prod in _planetProducerCount.OrderByDescending((KeyValuePair<int, int> pair) => pair.Value).Take(PluginConfig.productionPlanetCount.Value)
				select $"{GameMain.galaxy.PlanetById(prod.Key).displayName}: {producersLabel}={prod.Value}";
			_prodSummary = string.Join("\n", values);
			_prodSummaryTextDirty = false;
			return _prodSummary;
		}

		public string GetConsumerSummary()
		{
			if (!_consumerSummaryTextDirty)
			{
				return _consumerSummary;
			}
			string consLabel = Strings.ConsumersLabel;
			IEnumerable<string> values = from prod in _planetCosumerCount.OrderByDescending((KeyValuePair<int, int> pair) => pair.Value).Take(PluginConfig.productionPlanetCount.Value)
				select $"{GameMain.galaxy.PlanetById(prod.Key).displayName}: {consLabel}={prod.Value}";
			_consumerSummary = string.Join("\n", values);
			_consumerSummaryTextDirty = false;
			return _consumerSummary;
		}

		public int ProducerPlanetCount()
		{
			return _planetProducerCount.Count;
		}

		public int ConsumerPlanetCount()
		{
			return _planetCosumerCount.Count;
		}

		public bool IsProducerPlanet(int planetId)
		{
			return _planetProducerCount.ContainsKey(planetId);
		}

		public bool IsConsumerPlanet(int planetId)
		{
			return _planetCosumerCount.ContainsKey(planetId);
		}
	}
	public static class PluginConfig
	{
		public static ConfigEntry<int> productionPlanetCount;

		public static ConfigEntry<bool> popupLowPowerWarnings;

		public static ConfigEntry<float> lackOfProductionRatioTrigger;

		public static ConfigEntry<float> consumptionToProductionRatioTrigger;

		public static ConfigEntry<float> maximumReachRatioTrigger;

		public static ConfigEntry<bool> statsOnly;

		public static ConfigEntry<bool> planetFilter;

		public static ConfigEntry<bool> systemFilter;

		public static ConfigEntry<bool> includeSecondLevelConsumerProducer;

		public static ConfigEntry<bool> disableItemHoverTip;

		public static ConfigEntry<int> overwriteStackingLevel;

		public static ConfigEntry<int> overwriteProliferatorLevel;

		public static ConfigEntry<bool> disableProliferatorCalc;

		public static ConfigEntry<float> ejectorSpeedFactor;

		public static ConfigEntry<float> siloSpeedFactor;

		public static ConfigEntry<float> minerOutputLimit;

		public static ConfigEntry<bool> displayPerSecond;

		public static ConfigEntry<int> fontSizeValue;

		public static void InitConfig(ConfigFile confFile)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			productionPlanetCount = confFile.Bind<int>("General", "ProductionPlanetCount", 5, new ConfigDescription("Number of production planets to show. Too many and tip gets very large", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 35), Array.Empty<object>()));
			includeSecondLevelConsumerProducer = confFile.Bind<bool>("General", "Include Second Level Items", true, "Disable to show only the direct consumers or producers. When enabled one extra level of consumer/producer will be included in results");
			disableItemHoverTip = confFile.Bind<bool>("General", "Disable Item Hover Tip", false, "Suppress item tooltip in stats window");
			popupLowPowerWarnings = confFile.Bind<bool>("General", "PopupLowPowerWarnings", true, "When planets with too little power are detected a message will be popped up (once per session)");
			planetFilter = confFile.Bind<bool>("General", "Planet Filter", true, "When precursor/consumer filter is active filter planet list to only ones that produce/consume selected item");
			systemFilter = confFile.Bind<bool>("General", "System Filter", true, "When planet filter is active include star systems item in list (requires Planet Filter enabled)");
			lackOfProductionRatioTrigger = confFile.Bind<float>("General", "lackOfProductionRatio", 1f, "When consumption rises above the given ratio of max production, flag both text in red. (e.g. if set to '0.9' then you will be warned if you consume more than 90% of your max production)");
			consumptionToProductionRatioTrigger = confFile.Bind<float>("General", "consumptionToProductionRatio", 1.5f, "If max consumption raises above the given max production ratio, flag the text in yellow. (e.g. if set to '1.5' then you will be warned if your max consumption is more than 150% of your max production)");
			maximumReachRatioTrigger = confFile.Bind<float>("General", "maximumReachRatio", 0.999f, "If production or consumption raise above the given theory max ratio, flag the unit text in blue or yellow.");
			statsOnly = confFile.Bind<bool>("Stats", "Disable Bottleneck", false, "Disable Bottleneck functionality, use only BetterStats features");
			overwriteStackingLevel = confFile.Bind<int>("Stats", "Overwrite Stacking Level", -1, "Overwrite the maximum cargo stacking level. By default it uses the vanilla limit (4)");
			overwriteProliferatorLevel = confFile.Bind<int>("Stats", "Overwrite Proliferator Level", -1, "Overwrite the maximum proliferator level. By default it uses the highest proliferator unlocked");
			disableProliferatorCalc = confFile.Bind<bool>("Stats", "Disable Proliferator Calculation", false, "Tells mod to ignore proliferator points completely. Can cause production rates to exceed theoretical max values");
			ejectorSpeedFactor = confFile.Bind<float>("Stats", "Ejector Speed Factor", 1f, "EM-Rail Ejector speed multiplier. Set this value to 2.0 when feeding proliferated sails.");
			siloSpeedFactor = confFile.Bind<float>("Stats", "Silo Speed Factor", 1f, "Vertical Launching Silo speed multiplier. Set this value to 2.0 when feeding proliferated rockets.");
			minerOutputLimit = confFile.Bind<float>("Stats", "Miner Output Limit", 0f, "Maximum output limit (/min) of Mining Machine, Water Pump or Oil Extractor. Default value (0) is no limit");
			displayPerSecond = confFile.Bind<bool>("UI", "displayPerSecond", false, "Used by UI to persist the last selected value for checkbox");
			fontSizeValue = confFile.Bind<int>("UI", "Font Size - Value", 26, "Font size of the value text in UIProductEntry. Vanilla font size is 34");
		}
	}
	public class ProductionDeficitItem
	{
		private readonly int[] needed = new int[10];

		private readonly int[] assemblersNeedingCount = new int[10];

		private readonly int[] assemblersMissingSprayCount = new int[10];

		private readonly string[] inputItemNames = new string[10];

		private readonly int[] inputItemId = new int[10];

		private readonly Dictionary<int, int> inputItemIndex = new Dictionary<int, int>();

		private int neededCount;

		private const double Threshold = 0.01;

		private static readonly Dictionary<int, Dictionary<int, ProductionDeficitItem>> _byItemByRecipeId = new Dictionary<int, Dictionary<int, ProductionDeficitItem>>();

		private static readonly Dictionary<int, ProductionDeficitItem> _byItemOnly = new Dictionary<int, ProductionDeficitItem>();

		public string RecipeName { get; set; }

		public int AssemblerCount { get; set; }

		public int LackingPowerCount { get; set; }

		public int JammedCount { get; set; }

		public void AddNeeded(int itemId, int count)
		{
			if (inputItemIndex.TryGetValue(itemId, out var value))
			{
				needed[value] += count;
				assemblersNeedingCount[value]++;
			}
		}

		public void AddMissingSpray(int inputItem, int count)
		{
			if (inputItemIndex.ContainsKey(inputItem))
			{
				assemblersMissingSprayCount[inputItemIndex[inputItem]] += count;
			}
		}

		public (string neededStr, string stackStr, string unpoweredStr, string unsprayStr) GetTopNeeded(int outputProductId)
		{
			if (AssemblerCount < 1)
			{
				return ("", "", "", "");
			}
			int num = int.MinValue;
			string text = "";
			string text2 = "";
			int num2 = int.MinValue;
			int num3 = int.MinValue;
			int num4 = 0;
			string arg = "";
			ItemCalculationRuntimeSetting itemCalculationRuntimeSetting = ItemCalculationRuntimeSetting.ForItemId(outputProductId);
			bool flag = !PluginConfig.disableProliferatorCalc.Value && itemCalculationRuntimeSetting.Enabled && itemCalculationRuntimeSetting.Mode != ItemCalculationMode.None;
			for (int i = 0; i < neededCount; i++)
			{
				if (needed[i] > num)
				{
					num = needed[i];
					text2 = text;
					text = inputItemNames[i];
					num3 = num2;
					num2 = assemblersNeedingCount[i];
				}
				if (flag && assemblersMissingSprayCount[i] > 0 && assemblersMissingSprayCount[i] > num4)
				{
					num4 = assemblersMissingSprayCount[i];
					arg = inputItemNames[i];
				}
			}
			double num5 = (double)num2 / (double)AssemblerCount;
			double num6 = (double)JammedCount / (double)AssemblerCount;
			double num7 = (double)LackingPowerCount / (double)AssemblerCount;
			double num8 = (double)num4 / (double)AssemblerCount;
			string text3 = ((num5 < 0.01) ? "" : $"{text} {num5:P2}");
			string text4 = ((num6 < 0.01) ? "" : $"{num6:P2}");
			string item = ((num7 < 0.01) ? "" : $"{num7:P2}");
			string item2 = (((double)num4 > 0.01) ? $"{arg} {num8:P2}" : "");
			if (!string.IsNullOrEmpty(text2) && (double)num3 / (double)AssemblerCount > 0.01)
			{
				text3 = (text3 + " (2nd: " + text2 + ")").Trim();
			}
			return (text3.Trim(), text4.Trim(), item, item2);
		}

		public HashSet<int> NeededItems()
		{
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < neededCount; i++)
			{
				if (needed[i] > 0 && (double)assemblersNeedingCount[i] / (double)AssemblerCount > 0.05)
				{
					hashSet.Add(inputItemId[i]);
				}
			}
			return hashSet;
		}

		public static List<ProductionDeficitItem> GetItemsById(int itemId)
		{
			if (!_byItemByRecipeId.TryGetValue(itemId, out var value))
			{
				if (!_byItemOnly.TryGetValue(itemId, out var value2))
				{
					return new List<ProductionDeficitItem>();
				}
				return new List<ProductionDeficitItem> { value2 };
			}
			return value.Values.ToList();
		}

		public static ProductionDeficitItem FromItem(int inputItemId, int outputItemId)
		{
			if (!_byItemOnly.TryGetValue(outputItemId, out var value))
			{
				value = (_byItemOnly[outputItemId] = new ProductionDeficitItem());
			}
			value.inputItemId[0] = inputItemId;
			value.inputItemIndex[inputItemId] = 0;
			value.needed[value.inputItemIndex[inputItemId]] = 0;
			value.RecipeName = "Ray receiver";
			return value;
		}

		public static ProductionDeficitItem FromItem(int itemId, in AssemblerComponent assemblerComponent)
		{
			int recipeId = assemblerComponent.recipeId;
			if (!_byItemByRecipeId.TryGetValue(itemId, out var value))
			{
				value = (_byItemByRecipeId[itemId] = new Dictionary<int, ProductionDeficitItem>());
			}
			if (!value.TryGetValue(recipeId, out var value2))
			{
				int valueOrDefault = (assemblerComponent.requires?.Length).GetValueOrDefault();
				value2 = new ProductionDeficitItem
				{
					neededCount = valueOrDefault,
					RecipeName = ItemUtil.GetRecipeName(recipeId)
				};
				if (assemblerComponent.requires != null && assemblerComponent.requires.Length != 0)
				{
					for (int i = 0; i < value2.neededCount; i++)
					{
						ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(assemblerComponent.requires[i]);
						value2.inputItemNames[i] = Localization.Translate(((Proto)val).Name);
						value2.inputItemId[i] = ((Proto)val).ID;
						value2.inputItemIndex[assemblerComponent.requires[i]] = i;
					}
				}
				value[recipeId] = value2;
			}
			return value2;
		}

		public static ProductionDeficitItem FromItem(int itemId, in LabComponent assemblerComponent)
		{
			int recipeId = assemblerComponent.recipeId;
			if (!_byItemByRecipeId.TryGetValue(itemId, out var value))
			{
				value = (_byItemByRecipeId[itemId] = new Dictionary<int, ProductionDeficitItem>());
			}
			if (!value.TryGetValue(recipeId, out var value2))
			{
				value2 = new ProductionDeficitItem
				{
					neededCount = assemblerComponent.requires.Length,
					RecipeName = Localization.Translate(((Proto)((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipeId)).Name)
				};
				for (int i = 0; i < value2.neededCount; i++)
				{
					ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(assemblerComponent.requires[i]);
					value2.inputItemNames[i] = Localization.Translate(((Proto)val).Name);
					value2.inputItemId[i] = ((Proto)val).ID;
					value2.inputItemIndex[assemblerComponent.requires[i]] = i;
				}
				value[recipeId] = value2;
			}
			return value2;
		}

		private void Clear()
		{
			Array.Clear(needed, 0, needed.Length);
			Array.Clear(assemblersNeedingCount, 0, assemblersNeedingCount.Length);
			Array.Clear(assemblersMissingSprayCount, 0, assemblersMissingSprayCount.Length);
			AssemblerCount = 0;
			JammedCount = 0;
			LackingPowerCount = 0;
		}

		public static void ClearCounts()
		{
			foreach (int key in _byItemByRecipeId.Keys)
			{
				foreach (ProductionDeficitItem item in GetItemsById(key))
				{
					item.Clear();
				}
			}
			foreach (int key2 in _byItemOnly.Keys)
			{
				_byItemOnly[key2].Clear();
			}
		}
	}
	public static class ProductionDeficit
	{
		private static readonly HashSet<int> _loggedLowPowerByPlanetId = new HashSet<int>();

		public static void Clear()
		{
			ProductionDeficitItem.ClearCounts();
		}

		public static string MostNeeded(int recipeProductId)
		{
			StringBuilder stringBuilder = new StringBuilder();
			List<ProductionDeficitItem> itemsById = ProductionDeficitItem.GetItemsById(recipeProductId);
			foreach (ProductionDeficitItem item in itemsById)
			{
				var (text, text2, text3, text4) = item.GetTopNeeded(recipeProductId);
				if (text.Length == 0 && text2.Length == 0 && text3.Length == 0 && text4.Length == 0)
				{
					continue;
				}
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append("\r\n");
				}
				StringBuilder stringBuilder2 = new StringBuilder();
				if (text.Length > 0)
				{
					stringBuilder2.Append(Strings.NeedLabel + ": " + text);
					if (text2.Length > 0)
					{
						stringBuilder2.Append(", " + Strings.StackingLabel + ": " + text2);
					}
					if (text3.Length > 0)
					{
						stringBuilder2.Append(", " + Strings.UnderPoweredLabel + ": " + text3);
					}
					if (text4.Length > 0)
					{
						stringBuilder2.Append(", " + Strings.MissingSprayLabel + ": " + text4);
					}
				}
				else if (text2.Length > 0)
				{
					stringBuilder2.Append(Strings.StackingLabel + ": " + text2);
					if (text3.Length > 0)
					{
						stringBuilder2.Append(", " + Strings.UnderPoweredLabel + ": " + text3);
					}
					if (text4.Length > 0)
					{
						stringBuilder2.Append(", " + Strings.MissingSprayLabel + ": " + text4);
					}
				}
				else if (text3.Length > 0)
				{
					stringBuilder2.Append(Strings.UnderPoweredLabel + ": " + text3);
				}
				else
				{
					stringBuilder2.Append(Strings.MissingSprayLabel + ": " + text4);
				}
				if (itemsById.Count > 1)
				{
					stringBuilder.Append($"{Strings.RecipePreText}: {item.RecipeName}, {stringBuilder2}");
				}
				else
				{
					stringBuilder.Append((object?)stringBuilder2);
				}
			}
			return stringBuilder.ToString();
		}

		public static void RecordDeficit(int itemId, in AssemblerComponent assembler, PlanetFactory planetFactory)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			int maxIncIndex = ResearchTechHelper.GetMaxIncIndex();
			ProductionDeficitItem productionDeficitItem = ProductionDeficitItem.FromItem(itemId, in assembler);
			int networkId = planetFactory.powerSystem.consumerPool[assembler.pcId].networkId;
			PowerNetwork val = planetFactory.powerSystem.netPool[networkId];
			if (((val == null || networkId <= 0) ? 1f : ((float)val.consumerRatio)) < 0.98f)
			{
				productionDeficitItem.LackingPowerCount++;
				if (!_loggedLowPowerByPlanetId.Contains(planetFactory.planet.id))
				{
					if (PluginConfig.popupLowPowerWarnings.Value)
					{
						Log.LogAndPopupMessage("Planet '" + planetFactory.planet.displayName + "' low on power");
						int num = default(int);
						int num2 = default(int);
						int num3 = default(int);
						int num4 = default(int);
						bool flag = default(bool);
						bool flag2 = default(bool);
						bool flag3 = default(bool);
						bool flag4 = default(bool);
						Maths.GetLatitudeLongitude(planetFactory.entityPool[assembler.entityId].pos, ref num, ref num2, ref num3, ref num4, ref flag, ref flag2, ref flag3, ref flag4);
						Log.Warn($"{num}.{num2} {flag}, {num3}.{num4} {flag3}");
					}
					else
					{
						Log.Warn("Planet is low on power " + planetFactory.planet.displayName);
					}
					_loggedLowPowerByPlanetId.Add(planetFactory.planet.id);
				}
			}
			productionDeficitItem.AssemblerCount++;
			for (int i = 0; i < assembler.requireCounts.Length; i++)
			{
				if (assembler.served[i] < assembler.requireCounts[i])
				{
					productionDeficitItem.AddNeeded(assembler.requires[i], Math.Max(1, assembler.needs[i]));
				}
				if (assembler.incServed[i] < assembler.served[i] * maxIncIndex)
				{
					productionDeficitItem.AddMissingSpray(assembler.requires[i], 1);
				}
			}
			for (int j = 0; j < assembler.products.Length; j++)
			{
				if (assembler.produced[j] >= assembler.productCounts[j] * 8)
				{
					productionDeficitItem.JammedCount++;
					break;
				}
			}
		}

		public static void RecordDeficit(int itemId, in LabComponent lab, PlanetFactory planetFactory)
		{
			int maxIncIndex = ResearchTechHelper.GetMaxIncIndex();
			ProductionDeficitItem productionDeficitItem = ProductionDeficitItem.FromItem(itemId, in lab);
			productionDeficitItem.AssemblerCount++;
			int networkId = planetFactory.powerSystem.consumerPool[lab.pcId].networkId;
			PowerNetwork val = planetFactory.powerSystem.netPool[networkId];
			if (((val == null || networkId <= 0) ? 1f : ((float)val.consumerRatio)) < 0.98f)
			{
				productionDeficitItem.LackingPowerCount++;
				if (!_loggedLowPowerByPlanetId.Contains(planetFactory.planet.id))
				{
					if (PluginConfig.popupLowPowerWarnings.Value)
					{
						Log.LogAndPopupMessage("Planet '" + planetFactory.planet.displayName + "' low on power");
					}
					else
					{
						Log.Warn("Planet is low on power " + planetFactory.planet.displayName);
					}
					_loggedLowPowerByPlanetId.Add(planetFactory.planet.id);
				}
			}
			for (int i = 0; i < lab.requires.Length; i++)
			{
				if (lab.served[i] < lab.requireCounts[i])
				{
					productionDeficitItem.AddNeeded(lab.requires[i], Math.Max(1, lab.needs[i]));
				}
				if (lab.incServed[i] < lab.served[i] * maxIncIndex)
				{
					productionDeficitItem.AddMissingSpray(lab.requires[i], 1);
				}
			}
			if (lab.time >= lab.timeSpend)
			{
				productionDeficitItem.JammedCount++;
			}
		}

		public static bool IsDeficitItemFor(int precursorItem, int targetItem)
		{
			foreach (ProductionDeficitItem item in ProductionDeficitItem.GetItemsById(targetItem))
			{
				if (item.NeededItems().Contains(precursorItem))
				{
					return true;
				}
			}
			return false;
		}

		public static void RecordDeficit(int rayReceiverProductId, in PowerGeneratorComponent generator, PlanetFactory _)
		{
			ProductionDeficitItem productionDeficitItem = ProductionDeficitItem.FromItem(generator.catalystId, rayReceiverProductId);
			productionDeficitItem.AssemblerCount++;
			if (generator.productCount > 5f)
			{
				productionDeficitItem.JammedCount++;
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "Bottleneck";

		public const string PLUGIN_NAME = "Bottleneck";

		public const string PLUGIN_VERSION = "1.1.7";
	}
}
namespace Bottleneck.Util
{
	public static class ItemUtil
	{
		private static readonly Dictionary<int, List<int>> _itemPrecursorCache = new Dictionary<int, List<int>>();

		private static readonly Dictionary<int, List<int>> _itemSuccessorCache = new Dictionary<int, List<int>>();

		private static readonly ConcurrentDictionary<int, string> _recipeNames = new ConcurrentDictionary<int, string>();

		public static List<int> DirectPrecursorItems(int itemId)
		{
			if (_itemPrecursorCache.ContainsKey(itemId))
			{
				return _itemPrecursorCache[itemId];
			}
			RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray;
			List<int> list = new List<int>();
			foreach (RecipeProto val in dataArray)
			{
				if (!val.Results.ToList().Contains(itemId))
				{
					continue;
				}
				int[] items = val.Items;
				foreach (int num in items)
				{
					if (num != itemId)
					{
						list.Add(num);
					}
				}
			}
			_itemPrecursorCache.Add(itemId, list);
			return list;
		}

		public static List<int> DirectSuccessorItems(int itemId)
		{
			if (_itemSuccessorCache.ContainsKey(itemId))
			{
				return _itemSuccessorCache[itemId];
			}
			RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray;
			List<int> list = new List<int>();
			foreach (RecipeProto val in dataArray)
			{
				if (!val.Items.Contains(itemId))
				{
					continue;
				}
				int[] results = val.Results;
				foreach (int num in results)
				{
					if (num != itemId)
					{
						list.Add(num);
					}
				}
			}
			_itemSuccessorCache[itemId] = list;
			return list;
		}

		public static bool HasPrecursors(int productId)
		{
			return DirectPrecursorItems(productId).Count > 0;
		}

		public static bool HasConsumers(int productId)
		{
			return DirectSuccessorItems(productId).Count > 0;
		}

		public static string GetRecipeName(int recipeId)
		{
			if (_recipeNames.TryGetValue(recipeId, out var value))
			{
				return value;
			}
			RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipeId);
			if (val == null || ((Proto)val).Name == null)
			{
				return $"UNKNOWN_RECIPE_${recipeId}";
			}
			_recipeNames[recipeId] = Localization.Translate(((Proto)val).Name);
			return _recipeNames[recipeId];
		}
	}
	public static class Log
	{
		public static ManualLogSource logger;

		public static void Debug(string message)
		{
		}

		public static void Info(string message)
		{
			logger.LogInfo((object)$"[{DateTime.Now:HH:mm:ss.fff}] {message}");
		}

		public static void Warn(string message)
		{
			logger.LogWarning((object)$"[{DateTime.Now:HH:mm:ss.fff}] {message}");
		}

		public static void LogAndPopupMessage(string message)
		{
			UIRealtimeTip.Popup(message, false, 0);
			logger.LogInfo((object)("POPUP: '" + message + "'"));
		}
	}
}
namespace Bottleneck.UI
{
	public class BottleneckProductEntryElement
	{
		public UIButton precursorButton;

		public UIButton successorButton;
	}
	public static class Util
	{
		public static UIButton CopyButton(UIProductEntry uiProductEntry, UIButton button, Vector2 positionDelta, int entryDataItemId, Action<int> action, Sprite btnSprite)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			RectTransform component = ((Component)button).GetComponent<RectTransform>();
			RectTransform obj = Object.Instantiate<RectTransform>(component, ((Component)uiProductEntry).transform, false);
			Image component2 = ((Component)((Component)obj).transform).GetComponent<Image>();
			component2.sprite = btnSprite;
			component2.fillAmount = 0f;
			obj.anchorMin = component.anchorMin;
			obj.anchorMax = component.anchorMax;
			obj.sizeDelta = component.sizeDelta * 0.75f;
			obj.anchoredPosition = component.anchoredPosition + positionDelta;
			UIButton componentInChildren = ((Component)obj).GetComponentInChildren<UIButton>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				string itemName = GetItemName(entryDataItemId);
				componentInChildren.tips.tipTitle = itemName + " made on";
				componentInChildren.tips.tipText = "";
				((UnityEventBase)componentInChildren.button.onClick).RemoveAllListeners();
				((UnityEvent)componentInChildren.button.onClick).AddListener((UnityAction)delegate
				{
					action(1);
				});
				componentInChildren.highlighted = false;
				componentInChildren.Init();
			}
			return componentInChildren;
		}

		private static string GetItemName(int itemId)
		{
			return Localization.Translate(((Proto)((ProtoSet<ItemProto>)(object)LDB.items).Select(itemId)).Name);
		}
	}
	public static class Strings
	{
		private static bool isZHCN;

		public static string ClearFilterLabel;

		public static string LocalSystemLabel;

		public static string PerMinLabel;

		public static string PerSecLabel;

		public static string DispPerSecLabel;

		public static string FilterLabel;

		public static string ConsumersLabel;

		public static string ProducersLabel;

		public static string TheoreticalMaxLabel;

		public static string ProdDetailsLabel;

		public static string ClickPrecursorText;

		public static string ControlClickLacking;

		public static string ProducedOnLabel;

		public static string ConDetailsLabel;

		public static string ClickConsumingText;

		public static string ConsumedOnLabel;

		public static string NeedLabel;

		public static string CurrentLabel;

		public static string StackingLabel;

		public static string UnderPoweredLabel;

		public static string MissingSprayLabel;

		public static string BottlenecksLabel;

		public static string ProliferatorCalculationDisabled;

		public static string ProliferatorCalculationDisabledHover;

		public static string ProliferatorCalculationEnabled;

		public static string AssemblerSelectionMode;

		public static string AssemblerSelectionHover;

		public static string ForceProductivityMode;

		public static string ForceProductivityHover;

		public static string ForceSpeedMode;

		public static string ForceSpeedModeHover;

		public static string RecipePreText;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameOption), "Apply")]
		public static void ApplyLanguageChange()
		{
			LoadStrings();
		}

		public static void LoadStrings()
		{
			isZHCN = false;
			try
			{
				isZHCN = IsZHCN();
			}
			catch (Exception ex)
			{
				Log.Warn("Get Localization.isZHCN error!" + ex);
			}
			RegisterString(ref ClearFilterLabel, "Clear filter", "清除筛选器");
			RegisterString(ref LocalSystemLabel, "Local System", "本地系统");
			RegisterString(ref PerMinLabel, "/min", "/min");
			RegisterString(ref PerSecLabel, "/sec", "/sec");
			RegisterString(ref DispPerSecLabel, "Display /sec", "以 /秒 显示");
			RegisterString(ref FilterLabel, "Filter", "筛选");
			RegisterString(ref ConsumersLabel, "Consumers", "消耗设施");
			RegisterString(ref ProducersLabel, "Producers", "生产设施");
			RegisterString(ref TheoreticalMaxLabel, "Theoretical max", "理论最大值");
			RegisterString(ref ProdDetailsLabel, "Production Details", "生产详情");
			RegisterString(ref ClickPrecursorText, " (click to show only precursor items)", "(鼠标单击 仅展示所有前置材料)");
			RegisterString(ref ControlClickLacking, "(Control click see only precursors that are lacking)\r\n", "(按住Ctrl+鼠标单击 仅展示产量不足的前置材料)\r\n");
			RegisterString(ref ProducedOnLabel, "Produced on", "生产于");
			RegisterString(ref ConDetailsLabel, "Consumption Details", "消耗详情");
			RegisterString(ref ClickConsumingText, " (click to show only consuming items)", "(鼠标单击 仅展示用于制作的物品)");
			RegisterString(ref ConsumedOnLabel, "Consumed on", "消耗于");
			RegisterString(ref NeedLabel, "Need", "需要");
			RegisterString(ref CurrentLabel, "current", "当前");
			RegisterString(ref StackingLabel, "Stacking", "产物堆积");
			RegisterString(ref UnderPoweredLabel, "Under Powered", "电力不足");
			RegisterString(ref MissingSprayLabel, "Missing spray", "缺少增产剂");
			RegisterString(ref BottlenecksLabel, "Bottlenecks", "瓶颈");
			RegisterString(ref ProliferatorCalculationDisabled, "Proliferator Calculation Disabled", "增产剂计算已禁用");
			RegisterString(ref ProliferatorCalculationDisabledHover, "Don't use Proliferator Points for calculation of Theoretical max values", "不使用增产点数计算理论最大值");
			RegisterString(ref ProliferatorCalculationEnabled, "Proliferator Calculation Enabled", "增产剂计算已启用");
			RegisterString(ref AssemblerSelectionMode, "Assembler Selection Mode", "生产设施当前选择 模式");
			RegisterString(ref AssemblerSelectionHover, "Max values calculated using currently selected mode for each assembler.", "使用每个生产设施 当前选择 的模式计算理论最大值");
			RegisterString(ref ForceProductivityMode, "Force Productivity Mode", "强制 额外产出 模式");
			RegisterString(ref ForceProductivityHover, "Max values calculated as if all all assemblers were set to 'Extra Products'.", "假设每个生产设施使用 额外产出 模式计算理论最大值");
			RegisterString(ref ForceSpeedMode, "Force Speed Mode", "强制 生产加速 模式");
			RegisterString(ref ForceSpeedModeHover, "Max values calculated as if all all assemblers were set to 'Production Speedup'.", "假设每个生产设施使用 生产加速 模式计算理论最大值");
			RegisterString(ref RecipePreText, "Recipe", "配方");
		}

		private static bool IsZHCN()
		{
			return Localization.isZHCN;
		}

		private static void RegisterString(ref string result, string enTrans, string cnTrans)
		{
			string text = Localization.Translate("result");
			if (!string.Equals("result", text))
			{
				result = text;
			}
			else
			{
				result = (isZHCN ? cnTrans : enTrans);
			}
		}
	}
}
namespace Bottleneck.Stats
{
	public class BetterStats : MonoBehaviour
	{
		private class EnhancedUIProductEntryElements
		{
			public int itemId;

			private int tipItemId;

			public Text maxProductionLabel;

			public Text maxProductionValue;

			public Text maxProductionUnit;

			public Text maxConsumptionLabel;

			public Text maxConsumptionValue;

			public Text maxConsumptionUnit;

			public Text counterProductionLabel;

			public Text counterProductionValue;

			public Text counterConsumptionLabel;

			public Text counterConsumptionValue;

			public ProliferatorOperationSetting proliferatorOperationSetting;

			public EventTrigger trigger;

			public UIItemTip tip;

			public UIProductEntry ProductEntry { get; set; }

			public void OnMouseOverItem(BaseEventData _)
			{
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				if (PluginConfig.disableItemHoverTip.Value || (Object)(object)ProductEntry == (Object)null)
				{
					return;
				}
				if ((Object)(object)tip != (Object)null)
				{
					if (tipItemId == itemId)
					{
						((Component)tip).gameObject.SetActive(true);
						return;
					}
					Object.Destroy((Object)(object)((Component)tip).gameObject);
					tip = null;
				}
				tip = UIItemTip.Create(itemId, 9, Vector2.zero, ((Component)ProductEntry.itemIcon).transform, 0, 0, (ItemTipType)2, false, false, false, false);
				tipItemId = itemId;
			}

			public void OnMouseOffItem(BaseEventData _)
			{
				if ((Object)(object)tip != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)tip).gameObject);
					tip = null;
					tipItemId = -1;
				}
			}
		}

		public class ProductMetrics
		{
			public float production;

			public float consumption;

			public int producers;

			public int consumers;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__32_0;

			public static UnityAction<string> <>9__32_2;

			internal void <CreateObjects>b__32_0()
			{
				PluginConfig.displayPerSecond.Value = !PluginConfig.displayPerSecond.Value;
				checkBoxImage.sprite = (PluginConfig.displayPerSecond.Value ? sprOn : sprOff);
			}

			internal void <CreateObjects>b__32_2(string value)
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
		}

		public static Dictionary<int, ProductMetrics> counter = new Dictionary<int, ProductMetrics>();

		private static GameObject txtGO;

		private static GameObject chxGO;

		private static GameObject filterGO;

		private static readonly Texture2D texOff = Resources.Load<Texture2D>("ui/textures/sprites/icons/checkbox-off");

		private static readonly Texture2D texOn = Resources.Load<Texture2D>("ui/textures/sprites/icons/checkbox-on");

		private static Sprite sprOn;

		private static Sprite sprOff;

		private static Image checkBoxImage;

		public static string filterStr = "";

		private const int initialXOffset = 70;

		private const int valuesWidth = 90;

		private const int unitsWidth = 20;

		private const int labelsWidth = 110;

		private const int margin = 10;

		private const int maxOffset = 120;

		private static int lastTimeLevel;

		private static int lastAstroFilter;

		private static readonly Dictionary<UIProductEntry, EnhancedUIProductEntryElements> enhancements = new Dictionary<UIProductEntry, EnhancedUIProductEntryElements>();

		private static UIStatisticsWindow statWindow;

		public static ManualLogSource Log;

		public const float TICKS_PER_SEC = 60f;

		private const float RAY_RECEIVER_GRAVITON_LENS_CONSUMPTION_RATE_PER_MIN = 0.1f;

		internal void Awake()
		{
			try
			{
				ProliferatorOperationSetting.Init();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)ex.ToString());
			}
		}

		internal void OnDestroy()
		{
			if ((Object)(object)txtGO != (Object)null)
			{
				Object.Destroy((Object)(object)txtGO);
				Object.Destroy((Object)(object)chxGO);
				Object.Destroy((Object)(object)filterGO);
				Object.Destroy((Object)(object)sprOn);
				Object.Destroy((Object)(object)sprOff);
			}
			GameObject val = GameObject.Find("UI Root/Overlay Canvas/In Game/Windows/Production Stat Window/product-bg/top/favorite-text");
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(true);
			}
			ClearEnhancedUIProductEntries();
			ProliferatorOperationSetting.Unload();
		}

		private static void ClearEnhancedUIProductEntries()
		{
			if ((Object)(object)statWindow == (Object)null)
			{
				return;
			}
			foreach (EnhancedUIProductEntryElements value in enhancements.Values)
			{
				Object.Destroy((Object)(object)((Component)value.maxProductionLabel).gameObject);
				Object.Destroy((Object)(object)((Component)value.maxProductionValue).gameObject);
				Object.Destroy((Object)(object)((Component)value.maxProductionUnit).gameObject);
				Object.Destroy((Object)(object)((Component)value.maxConsumptionLabel).gameObject);
				Object.Destroy((Object)(object)((Component)value.maxConsumptionValue).gameObject);
				Object.Destroy((Object)(object)((Component)value.maxConsumptionUnit).gameObject);
				Object.Destroy((Object)(object)((Component)value.counterProductionLabel).gameObject);
				Object.Destroy((Object)(object)((Component)value.counterProductionValue).gameObject);
				Object.Destroy((Object)(object)((Component)value.counterConsumptionLabel).gameObject);
				Object.Destroy((Object)(object)((Component)value.counterConsumptionValue).gameObject);
				value.trigger.triggers.Clear();
			}
			enhancements.Clear();
		}

		private static Text CopyText(Text original, Vector2 positionDelta)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			Text obj = Object.Instantiate<Text>(original);
			((Component)obj).transform.SetParent(((Component)original).transform.parent, false);
			RectTransform component = ((Component)obj).GetComponent<RectTransform>();
			RectTransform component2 = ((Component)original).GetComponent<RectTransform>();
			component.anchorMin = component2.anchorMin;
			component.anchorMax = component2.anchorMax;
			component.sizeDelta = component2.sizeDelta;
			component.anchoredPosition = component2.anchoredPosition + positionDelta;
			return obj;
		}

		private static string FormatMetric(float value, bool skipFraction = false)
		{
			if ((double)value >= 1000000.0)
			{
				return (value / 1000000f).ToString("F2") + " M";
			}
			if ((double)value >= 10000.0)
			{
				return (value / 1000f).ToString("F2") + " k";
			}
			float num = value - (float)(int)value;
			if ((double)value >= 1000.0 || (skipFraction && (double)num < 0.0001))
			{
				return value.ToString("F0");
			}
			if ((double)value >= 100.0)
			{
				return value.ToString("F1");
			}
			if ((double)value >= 1.0)
			{
				return value.ToString("F2");
			}
			if ((double)value > 0.0)
			{
				return value.ToString("F3");
			}
			return value.ToString();
		}

		private static EnhancedUIProductEntryElements EnhanceUIProductEntry(UIProductEntry __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0553: Unknown result type (might be due to invalid IL or missing references)
			//IL_057b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			//IL_0629: Unknown result type (might be due to invalid IL or missing references)
			//IL_0646: Unknown result type (might be due to invalid IL or missing references)
			//IL_066c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0689: Unknown result type (might be due to invalid IL or missing references)
			//IL_073e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0745: Expected O, but got Unknown
			//IL_0748: Unknown result type (might be due to invalid IL or missing references)
			//IL_0779: Unknown result type (might be due to invalid IL or missing references)
			//IL_0780: Expected O, but got Unknown
			//IL_0783: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = ((Component)__instance.itemIcon).transform.parent;
			((Component)parent).GetComponent<RectTransform>().sizeDelta = new Vector2(80f, 80f);
			((Component)parent).GetComponent<RectTransform>().anchoredPosition = new Vector2(22f, 12f);
			((Component)__instance.favoriteBtn1).GetComponent<RectTransform>().anchoredPosition = new Vector2(26f, -32f);
			((Component)__instance.favoriteBtn2).GetComponent<RectTransform>().anchoredPosition = new Vector2(49f, -32f);
			((Component)__instance.favoriteBtn3).GetComponent<RectTransform>().anchoredPosition = new Vector2(72f, -32f);
			((Component)__instance.itemName).transform.SetParent(parent, false);
			RectTransform component = ((Component)__instance.itemName).GetComponent<RectTransform>();
			component.pivot = new Vector2(0.5f, 0f);
			component.anchorMin = new Vector2(0f, 0f);
			component.anchorMax = new Vector2(1f, 0f);
			component.anchoredPosition = new Vector2(0f, 0f);
			((Component)parent).GetComponent<RectTransform>().sizeDelta = new Vector2(80f, 80f);
			__instance.itemName.resizeTextForBestFit = true;
			__instance.itemName.resizeTextMaxSize = 14;
			__instance.itemName.alignment = (TextAnchor)4;
			__instance.itemName.alignByGeometry = true;
			__instance.itemName.horizontalOverflow = (HorizontalWrapMode)0;
			__instance.itemName.lineSpacing = 0.6f;
			Transform obj = ((Component)__instance.consumeUnitLabel).transform.parent.Find("sep-line");
			((Component)obj).GetComponent<RectTransform>().pivot = new Vector2(0f, 1f);
			((Transform)((Component)obj).GetComponent<RectTransform>()).rotation = Quaternion.Euler(0f, 0f, 90f);
			((Component)obj).GetComponent<RectTransform>().sizeDelta = new Vector2(1f, 336f);
			((Component)obj).GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, -50f);
			__instance.productLabel.alignment = (TextAnchor)2;
			((Component)__instance.productLabel).GetComponent<RectTransform>().sizeDelta = new Vector2(110f, 24f);
			((Component)__instance.productLabel).GetComponent<RectTransform>().anchoredPosition = new Vector2(70f, 0f);
			((Component)__instance.productLabel).GetComponent<RectTransform>().ForceUpdateRectTransforms();
			__instance.productText.alignByGeometry = true;
			__instance.productText.resizeTextForBestFit = true;
			__instance.productText.resizeTextMaxSize = 34;
			__instance.productText.alignment = (TextAnchor)8;
			((Component)__instance.productText).GetComponent<RectTransform>().sizeDelta = new Vector2(90f, 40f);
			((Component)__instance.productText).GetComponent<RectTransform>().anchoredPosition = new Vector2(70f, 56f);
			__instance.productUnitLabel.alignByGeometry = true;
			__instance.productUnitLabel.alignment = (TextAnchor)6;
			((Component)__instance.productUnitLabel).GetComponent<RectTransform>().sizeDelta = new Vector2(20f, 24f);
			((Component)__instance.productUnitLabel).GetComponent<RectTransform>().pivot = new Vector2(0f, 0f);
			((Component)__instance.productUnitLabel).GetComponent<RectTransform>().anchoredPosition = new Vector2(164f, -42f);
			__instance.consumeLabel.alignment = (TextAnchor)2;
			((Component)__instance.consumeLabel).GetComponent<RectTransform>().sizeDelta = new Vector2(110f, 24f);
			((Component)__instance.consumeLabel).GetComponent<RectTransform>().anchoredPosition = new Vector2(70f, -60f);
			__instance.consumeText.alignByGeometry = true;
			__instance.consumeText.resizeTextForBestFit = true;
			__instance.consumeText.resizeTextMaxSize = 34;
			__instance.consumeText.alignment = (TextAnchor)8;
			((Component)__instance.consumeText).GetComponent<RectTransform>().sizeDelta = new Vector2(90f, 40f);
			((Component)__instance.consumeText).GetComponent<RectTransform>().anchoredPosition = new Vector2(70f, -4f);
			__instance.consumeUnitLabel.alignByGeometry = true;
			__instance.consumeUnitLabel.alignment = (TextAnchor)6;
			((Component)__instance.consumeUnitLabel).GetComponent<RectTransform>().sizeDelta = new Vector2(20f, 24f);
			((Component)__instance.consumeUnitLabel).GetComponent<RectTransform>().anchorMin = new Vector2(0f, 0f);
			((Component)__instance.consumeUnitLabel).GetComponent<RectTransform>().anchorMax = new Vector2(0f, 0f);
			((Component)__instance.consumeUnitLabel).GetComponent<RectTransform>().pivot = new Vector2(0f, 0f);
			((Component)__instance.consumeUnitLabel).GetComponent<RectTransform>().anchoredPosition = new Vector2(164f, -4f);
			Text val = CopyText(__instance.productLabel, new Vector2(120f, 0f));
			val.text = Strings.TheoreticalMaxLabel;
			Text val2 = CopyText(__instance.productText, new Vector2(120f, 0f));
			val2.text = "0";
			Text val3 = CopyText(__instance.productUnitLabel, new Vector2(120f, 0f));
			val3.text = Strings.PerMinLabel;
			Text val4 = CopyText(__instance.consumeLabel, new Vector2(120f, 0f));
			val4.text = Strings.TheoreticalMaxLabel;
			Text val5 = CopyText(__instance.consumeText, new Vector2(120f, 0f));
			val5.text = "0";
			Text val6 = CopyText(__instance.consumeUnitLabel, new Vector2(120f, 0f));
			val6.text = Strings.PerMinLabel;
			Text val7 = CopyText(__instance.productLabel, new Vector2(-70f, 0f));
			((Component)val7).GetComponent<RectTransform>().sizeDelta = new Vector2(60f, 40f);
			val7.text = Strings.ProducersLabel;
			Text val8 = CopyText(__instance.productText, new Vector2(-70f, 0f));
			((Component)val8).GetComponent<RectTransform>().sizeDelta = new Vector2(60f, 40f);
			val8.text = "0";
			Text val9 = CopyText(__instance.consumeLabel, new Vector2(-70f, 0f));
			((Component)val9).GetComponent<RectTransform>().sizeDelta = new Vector2(60f, 40f);
			val9.text = Strings.ConsumersLabel;
			Text val10 = CopyText(__instance.consumeText, new Vector2(-70f, 0f));
			((Component)val10).GetComponent<RectTransform>().sizeDelta = new Vector2(60f, 40f);
			val10.text = "0";
			ProliferatorOperationSetting proliferatorOperationSetting = ProliferatorOperationSetting.ForProductEntry(__instance);
			EnhancedUIProductEntryElements enhancedUIProductEntryElements = new EnhancedUIProductEntryElements
			{
				itemId = __instance.entryData.itemId,
				maxProductionLabel = val,
				maxProductionValue = val2,
				maxProductionUnit = val3,
				maxConsumptionLabel = val4,
				maxConsumptionValue = val5,
				maxConsumptionUnit = val6,
				counterProductionLabel = val7,
				counterProductionValue = val8,
				counterConsumptionLabel = val9,
				counterConsumptionValue = val10,
				proliferatorOperationSetting = proliferatorOperationSetting,
				ProductEntry = __instance
			};
			((Graphic)__instance.itemIcon).raycastTarget = true;
			enhancedUIProductEntryElements.trigger = ((Component)__instance.itemIcon).gameObject.AddComponent<EventTrigger>();
			Entry val11 = new Entry();
			val11.eventID = (EventTriggerType)0;
			((UnityEvent<BaseEventData>)(object)val11.callback).AddListener((UnityAction<BaseEventData>)enhancedUIProductEntryElements.OnMouseOverItem);
			enhancedUIProductEntryElements.trigger.triggers.Add(val11);
			Entry val12 = new Entry();
			val12.eventID = (EventTriggerType)1;
			((UnityEvent<BaseEventData>)(object)val12.callback).AddListener((UnityAction<BaseEventData>)enhancedUIProductEntryElements.OnMouseOffItem);
			enhancedUIProductEntryElements.trigger.triggers.Add(val12);
			enhancements.Add(__instance, enhancedUIProductEntryElements);
			if (PluginConfig.fontSizeValue.Value > 0)
			{
				Text productText = __instance.productText;
				Text consumeText = __instance.consumeText;
				Text counterProductionValue = enhancedUIProductEntryElements.counterProductionValue;
				Text counterConsumptionValue = enhancedUIProductEntryElements.counterConsumptionValue;
				Text maxProductionValue = enhancedUIProductEntryElements.maxProductionValue;
				int num = (enhancedUIProductEntryElements.maxConsumptionValue.fontSize = PluginConfig.fontSizeValue.Value);
				int num3 = (maxProductionValue.fontSize = num);
				int num5 = (counterConsumptionValue.fontSize = num3);
				int num7 = (counterProductionValue.fontSize = num5);
				int fontSize = (consumeText.fontSize = num7);
				productText.fontSize = fontSize;
			}
			return enhancedUIProductEntryElements;
		}

		public static void UIStatisticsWindow__OnClose_Postfix()
		{
			foreach (EnhancedUIProductEntryElements value in enhancements.Values)
			{
				value.OnMouseOffItem(null);
			}
			lastTimeLevel = (lastAstroFilter = -1);
		}

		public static void UIStatisticsWindow__OnOpen_Postfix(UIStatisticsWindow __instance)
		{
			if ((Object)(object)statWindow == (Object)null)
			{
				statWindow = __instance;
			}
			if ((Object)(object)chxGO == (Object)null)
			{
				CreateObjects(__instance);
			}
			UIStatisticsWindow_OnTabButtonClick_Postfix(__instance);
		}

		public static void UIStatisticsWindow_OnTabButtonClick_Postfix(UIStatisticsWindow __instance)
		{
			if (!((Object)(object)chxGO == (Object)null) && !((Object)(object)filterGO == (Object)null))
			{
				if (__instance.isProductionTab)
				{
					chxGO.transform.SetParent(((Component)__instance.productSortBox).transform.parent, false);
					filterGO.transform.SetParent(((Component)__instance.productSortBox).transform.parent, false);
				}
				else if (__instance.isKillTab)
				{
					chxGO.transform.SetParent(((Component)__instance.killSortBox).transform.parent, false);
					filterGO.transform.SetParent(((Component)__instance.killSortBox).transform.parent, false);
				}
			}
		}

		private static void CreateObjects(UIStatisticsWindow __instance)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Expected O, but got Unknown
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Expected O, but got Unknown
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0516: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("UI Root/Overlay Canvas/In Game/Windows/Statistics Window/product-bg/top/favorite-text");
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(false);
			}
			val = GameObject.Find("UI Root/Overlay Canvas/In Game/Windows/Statistics Window/kill-bg/top/favorite-text");
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(false);
			}
			sprOn = Sprite.Create(texOn, new Rect(0f, 0f, (float)((Texture)texOn).width, (float)((Texture)texOn).height), new Vector2(0.5f, 0.5f));
			sprOff = Sprite.Create(texOff, new Rect(0f, 0f, (float)((Texture)texOff).width, (float)((Texture)texOff).height), new Vector2(0.5f, 0.5f));
			chxGO = new GameObject("displaySec");
			RectTransform obj = chxGO.AddComponent<RectTransform>();
			((Transform)obj).SetParent(((Component)__instance.productSortBox).transform.parent, false);
			obj.anchorMax = new Vector2(0f, 1f);
			obj.anchorMin = new Vector2(0f, 1f);
			obj.sizeDelta = new Vector2(20f, 20f);
			obj.pivot = new Vector2(0f, 0.5f);
			obj.anchoredPosition = new Vector2(250f, -33f);
			Button obj2 = ((Component)obj).gameObject.AddComponent<Button>();
			ButtonClickedEvent onClick = obj2.onClick;
			object obj3 = <>c.<>9__32_0;
			if (obj3 == null)
			{
				UnityAction val2 = delegate
				{
					PluginConfig.displayPerSecond.Value = !PluginConfig.displayPerSecond.Value;
					checkBoxImage.sprite = (PluginConfig.displayPerSecond.Value ? sprOn : sprOff);
				};
				<>c.<>9__32_0 = val2;
				obj3 = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj3);
			checkBoxImage = ((Component)obj2).gameObject.AddComponent<Image>();
			((Graphic)checkBoxImage).color = new Color(0.8f, 0.8f, 0.8f, 1f);
			checkBoxImage.sprite = (PluginConfig.displayPerSecond.Value ? sprOn : sprOff);
			txtGO = new GameObject("displaySecTxt");
			RectTransform obj4 = txtGO.AddComponent<RectTransform>();
			((Transform)obj4).SetParent(chxGO.transform, false);
			obj4.anchorMax = new Vector2(0f, 0.5f);
			obj4.anchorMin = new Vector2(0f, 0.5f);
			obj4.sizeDelta = new Vector2(100f, 20f);
			obj4.pivot = new Vector2(0f, 0.5f);
			obj4.anchoredPosition = new Vector2(20f, 0f);
			Text val3 = ((Component)obj4).gameObject.AddComponent<Text>();
			val3.text = Strings.DispPerSecLabel;
			val3.fontStyle = (FontStyle)0;
			val3.fontSize = 14;
			val3.verticalOverflow = (VerticalWrapMode)1;
			val3.horizontalOverflow = (HorizontalWrapMode)0;
			((Graphic)val3).color = new Color(0.8f, 0.8f, 0.8f, 1f);
			Font val4 = Resources.Load<Font>("ui/fonts/SAIRASB");
			if ((Object)(object)val4 != (Object)null)
			{
				val3.font = val4;
			}
			filterGO = new GameObject("filterGo");
			RectTransform val5 = filterGO.AddComponent<RectTransform>();
			((Transform)val5).SetParent(((Component)__instance.productSortBox).transform.parent, false);
			val5.anchorMax = new Vector2(0f, 1f);
			val5.anchorMin = new Vector2(0f, 1f);
			val5.sizeDelta = new Vector2(100f, 30f);
			val5.pivot = new Vector2(0f, 0.5f);
			val5.anchoredPosition = new Vector2(120f, -33f);
			Image val6 = filterGO.AddComponent<Image>();
			((Component)val6).transform.SetParent((Transform)(object)val5, false);
			((Graphic)val6).color = new Color(0f, 0f, 0f, 0.5f);
			GameObject val7 = new GameObject
			{
				name = "Text"
			};
			val7.transform.SetParent((Transform)(object)val5, false);
			Text val8 = val7.AddComponent<Text>();
			val8.supportRichText = false;
			((Graphic)val8).color = new Color(0.8f, 0.8f, 0.8f, 1f);
			val8.font = val4;
			val8.fontSize = 16;
			val8.alignment = (TextAnchor)3;
			val8.horizontalOverflow = (HorizontalWrapMode)1;
			Transform transform = ((Component)val8).transform;
			((RectTransform)((transform is RectTransform) ? transform : null)).sizeDelta = new Vector2(90f, 30f);
			Transform transform2 = ((Component)val8).transform;
			((RectTransform)((transform2 is RectTransform) ? transform2 : null)).anchoredPosition = new Vector2(5f, 0f);
			GameObject val9 = new GameObject
			{
				name = "Placeholder"
			};
			val9.transform.SetParent((Transform)(object)val5, false);
			Text val10 = val9.AddComponent<Text>();
			((Graphic)val10).color = new Color(0.8f, 0.8f, 0.8f, 1f);
			val10.font = val4;
			val10.fontSize = 16;
			val10.fontStyle = (FontStyle)2;
			val10.alignment = (TextAnchor)3;
			val10.supportRichText = false;
			val10.horizontalOverflow = (HorizontalWrapMode)1;
			val10.text = Strings.FilterLabel;
			Transform transform3 = ((Component)val10).transform;
			((RectTransform)((transform3 is RectTransform) ? transform3 : null)).sizeDelta = new Vector2(90f, 30f);
			Transform transform4 = ((Component)val10).transform;
			((RectTransform)((transform4 is RectTransform) ? transform4 : null)).anchoredPosition = new Vector2(5f, 0f);
			InputField _inputField = filterGO.AddComponent<InputField>();
			((Component)_inputField).transform.SetParent((Transform)(object)val5, false);
			((Selectable)_inputField).targetGraphic = (Graphic)(object)val6;
			_inputField.textComponent = val8;
			_inputField.placeholder = (Graphic)(object)val10;
			((UnityEvent<string>)(object)_inputField.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				if (_inputField.wasCanceled)
				{
					_inputField.text = filterStr;
				}
				else
				{
					filterStr = value;
				}
				if (__instance.isProductionTab)
				{
					__instance.ComputeDisplayProductEntries();
				}
				else if (__instance.isKillTab)
				{
					__instance.ComputeDisplayKillEntries();
				}
			});
			((UnityEvent<string>)(object)_inputField.onEndEdit).AddListener((UnityAction<string>)delegate
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			});
			chxGO.transform.SetParent(((Component)__instance.productSortBox).transform.parent, false);
			txtGO.transform.SetParent(chxGO.transform, false);
			filterGO.transform.SetParent(((Component)__instance.productSortBox).transform.parent, false);
		}

		public static void UIProductEntryList_FilterEntries_Postfix(UIProductEntryList __instance, HashSet<int> itemsToShow)
		{
			if (filterStr == "")
			{
				return;
			}
			for (int num = __instance.entryDatasCursor - 1; num >= 0; num--)
			{
				UIProductEntryData val = __instance.entryDatas[num];
				if (((Proto)((ProtoSet<ItemProto>)(object)LDB.items).Select(val.itemId)).name.IndexOf(filterStr, StringComparison.OrdinalIgnoreCase) < 0 && !itemsToShow.Contains(val.itemId))
				{
					__instance.Swap(num, __instance.entryDatasCursor - 1);
					__instance.entryDatasCursor--;
				}
			}
		}

		public static void UIKillEntryList_FilterEntries_Postfix(UIKillEntryList __instance)
		{
			if (filterStr == "")
			{
				return;
			}
			for (int num = __instance.entryDatasCursor - 1; num >= 0; num--)
			{
				UIKillEntryData val = __instance.entryDatas[num];
				if (((ProtoSet<ModelProto>)(object)LDB.models).Select(val.modelId).displayName.IndexOf(filterStr, StringComparison.OrdinalIgnoreCase) < 0)
				{
					__instance.Swap(num, __instance.entryDatasCursor - 1);
					__instance.entryDatasCursor--;
				}
			}
		}

		public static void UIStatisticsWindow__OnUpdate_Prefix(UIStatisticsWindow __instance)
		{
			if ((Object)(object)statWindow == (Object)null)
			{
				statWindow = __instance;
			}
		}

		public static void UIProductEntry__OnUpdate_Postfix(UIProductEntry __instance)
		{
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance.productionStatWindow == (Object)null || !__instance.productionStatWindow.isProductionTab)
			{
				return;
			}
			if (!enhancements.TryGetValue(__instance, out var value))
			{
				value = EnhanceUIProductEntry(__instance);
			}
			value.itemId = __instance.entryData.itemId;
			bool flag = __instance.productionStatWindow.timeLevel == 5;
			float num = (flag ? 1f : ((float)__instance.lvDivisors[__instance.productionStatWindow.timeLevel]));
			float num2 = (float)__instance.entryData.production / num;
			float num3 = (float)__instance.entryData.consumption / num;
			string text = "0";
			string text2 = "0";
			string text3 = "0";
			string text4 = "0";
			string text5 = (PluginConfig.displayPerSecond.Value ? Strings.PerSecLabel : Strings.PerMinLabel);
			string text6 = (flag ? "" : Strings.PerMinLabel);
			int num4 = 1;
			bool flag2 = false;
			bool flag3 = false;
			bool flag4 = false;
			bool flag5 = false;
			if (PluginConfig.displayPerSecond.Value)
			{
				num4 = 60;
				text6 = ((!flag) ? Strings.PerSecLabel : text6);
				if (!flag)
				{
					num2 /= (float)num4;
					num3 /= (float)num4;
					__instance.productText.text = FormatMetric(num2);
					__instance.consumeText.text = FormatMetric(num3);
				}
			}
			Text productUnitLabel = __instance.productUnitLabel;
			string text8 = (__instance.consumeUnitLabel.text = text6);
			productUnitLabel.text = text8;
			Text maxProductionUnit = value.maxProductionUnit;
			text8 = (value.maxConsumptionUnit.text = text5);
			maxProductionUnit.text = text8;
			Color color2 = (((Graphic)value.maxProductionUnit).color = (((Graphic)value.maxConsumptionUnit).color = ((Graphic)__instance.productUnitLabel).color));
			if (counter.TryGetValue(__instance.entryData.itemId, out var value2) && value2 != null)
			{
				float num5 = value2.production / (float)num4;
				float num6 = value2.consumption / (float)num4;
				text3 = FormatMetric(num5, skipFraction: true);
				text4 = FormatMetric(num6, skipFraction: true);
				text = value2.producers.ToString();
				text2 = value2.consumers.ToString();
				if (num3 > num5 * PluginConfig.lackOfProductionRatioTrigger.Value)
				{
					flag2 = true;
				}
				if (num6 > num5 * PluginConfig.consumptionToProductionRatioTrigger.Value)
				{
					flag3 = true;
				}
				if (num2 > num5 * PluginConfig.maximumReachRatioTrigger.Value)
				{
					flag4 = true;
				}
				if (num3 > num6 * PluginConfig.maximumReachRatioTrigger.Value)
				{
					flag5 = true;
				}
			}
			value.maxProductionValue.text = text3;
			value.maxConsumptionValue.text = t