Decompiled source of PhotonStockExchange v0.1.1

plugins/DSP-StockExchange/DSP-StockExchange.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using CommonAPI;
using CommonAPI.Systems;
using CommonAPI.Systems.ModLocalization;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DSP-StockExchange")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("DSP-StockExchange")]
[assembly: AssemblyTitle("DSP-StockExchange")]
[assembly: AssemblyVersion("0.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace StockExchange
{
	internal enum TradeMode
	{
		SellSails,
		BuySails,
		BuyPhotons
	}
	internal static class ExchangeLogic
	{
		private const int MaxPendingInput = 20000;

		private const int MaxOutputBuffer = 200;

		private const int MaxConvertPerTick = 4;

		internal static long TicksSeen;

		private static long lastTickedGameTick = long.MinValue;

		internal static int GetMode(in FractionatorComponent frac)
		{
			int num = (int)(frac.seed - 1);
			if (num < 0 || num > 2)
			{
				return 1;
			}
			return num;
		}

		private static int ModeInputItem(int mode)
		{
			if (mode != 1)
			{
				return 6008;
			}
			return 1501;
		}

		private static int ModeOutputItem(int mode)
		{
			return mode switch
			{
				1 => 6008, 
				0 => 1501, 
				_ => 1208, 
			};
		}

		internal static string ModeName(int mode)
		{
			return mode switch
			{
				0 => L10N.T("卖出能量币(币 → 太阳帆)", "Sell coins (coins -> sails)"), 
				2 => L10N.T("兑换光子(币 → 光子)", "Buy photons (coins -> photons)"), 
				_ => L10N.T("买入能量币(太阳帆 → 币)", "Buy coins (sails -> coins)"), 
			};
		}

		internal static bool TryGetExchange(FactorySystem fs, int fracId, out FractionatorComponent frac)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			frac = default(FractionatorComponent);
			if (fs == null || fs.factory == null || fs.fractionatorPool == null)
			{
				return false;
			}
			if (fracId <= 0 || fracId >= fs.fractionatorPool.Length)
			{
				return false;
			}
			ref FractionatorComponent reference = ref fs.fractionatorPool[fracId];
			if (reference.id != fracId || reference.entityId <= 0)
			{
				return false;
			}
			EntityData[] entityPool = fs.factory.entityPool;
			if (reference.entityId >= entityPool.Length || entityPool[reference.entityId].protoId != 6009)
			{
				return false;
			}
			frac = reference;
			return true;
		}

		internal static void SetMode(FactorySystem fs, int fracId, TradeMode mode, Player player)
		{
			if (TryGetExchange(fs, fracId, out var frac) && GetMode(in frac) != (int)mode)
			{
				ref FractionatorComponent reference = ref fs.fractionatorPool[fracId];
				RefundPending(ref reference, player);
				reference.seed = (uint)(mode + 1);
				Plugin.LogInfo($"[exchange] mode -> {mode} (frac {fracId})");
			}
		}

		internal static void TickAll()
		{
			if (!Plugin.Registered)
			{
				return;
			}
			GameData data = GameMain.data;
			if (data == null || data.factories == null)
			{
				return;
			}
			long gameTick = GameMain.gameTick;
			if (gameTick == lastTickedGameTick)
			{
				return;
			}
			lastTickedGameTick = gameTick;
			int num = data.factoryCount;
			if (num > data.factories.Length)
			{
				num = data.factories.Length;
			}
			for (int i = 0; i < num; i++)
			{
				PlanetFactory val = data.factories[i];
				if (val != null && val.factorySystem != null)
				{
					try
					{
						TickFactory(val.factorySystem);
					}
					catch (Exception e)
					{
						Plugin.LogError("TickAll factory failed", e);
					}
				}
			}
		}

		internal static void TickFactory(FactorySystem fs)
		{
			if (!Plugin.Registered || fs == null)
			{
				return;
			}
			TicksSeen++;
			if (GameMain.data == null || GameMain.history == null)
			{
				return;
			}
			EnsureRecipeUnlocked();
			PlanetFactory factory = fs.factory;
			if (factory == null)
			{
				return;
			}
			CargoTraffic cargoTraffic = factory.cargoTraffic;
			if (cargoTraffic == null)
			{
				return;
			}
			FractionatorComponent[] fractionatorPool = fs.fractionatorPool;
			if (fractionatorPool == null)
			{
				return;
			}
			int num = fs.fractionatorCursor;
			if (num > fractionatorPool.Length)
			{
				num = fractionatorPool.Length;
			}
			EntityData[] entityPool = factory.entityPool;
			for (int i = 1; i < num; i++)
			{
				ref FractionatorComponent reference = ref fractionatorPool[i];
				if (reference.id != i)
				{
					continue;
				}
				int entityId = reference.entityId;
				if (entityId > 0 && entityId < entityPool.Length && entityPool[entityId].protoId == 6009)
				{
					try
					{
						Process(ref reference, fs, cargoTraffic);
					}
					catch (Exception e)
					{
						Plugin.LogError("trade tick failed (fracId=" + i + ")", e);
					}
				}
			}
		}

		internal static void EnsureRecipeUnlocked()
		{
			GameHistoryData history = GameMain.history;
			if (history == null)
			{
				return;
			}
			int value = Plugin.UnlockTechId.Value;
			if (value <= 0)
			{
				if (!history.RecipeUnlocked(6010))
				{
					history.UnlockRecipe(6010);
				}
			}
			else if (!history.RecipeUnlocked(6010) && history.TechUnlocked(value))
			{
				history.UnlockRecipe(6010);
			}
		}

		private static void Process(ref FractionatorComponent frac, FactorySystem fs, CargoTraffic traffic)
		{
			frac.fluidInputMax = 0;
			frac.productOutputMax = 0;
			frac.fluidOutputMax = 0;
			StarData val = ((fs.planet != null) ? fs.planet.star : null);
			if (val == null)
			{
				return;
			}
			int mode = GetMode(in frac);
			if (frac.seed != (uint)(mode + 1))
			{
				frac.seed = (uint)(mode + 1);
			}
			double price = PriceService.GetPrice(val);
			double tax = Mathf.Clamp((float)Plugin.TaxRate.Value, 0f, 0.5f);
			int itemId = ModeInputItem(mode);
			if (!frac.isOutput1 && frac.belt1 > 0)
			{
				IntakeFromBelt(ref frac, traffic, frac.belt1, itemId);
			}
			if (!frac.isOutput2 && frac.belt2 > 0)
			{
				IntakeFromBelt(ref frac, traffic, frac.belt2, itemId);
			}
			float powerRatio = GetPowerRatio(fs, in frac);
			bool flag = Plugin.RequirePower == null || !Plugin.RequirePower.Value || powerRatio > 0.1f;
			if (flag)
			{
				switch (mode)
				{
				case 1:
					ConvertBuySails(ref frac, price, tax);
					break;
				case 0:
					ConvertSellSails(ref frac, price, tax);
					break;
				default:
					ConvertBuyPhotons(ref frac);
					break;
				}
				OutputToBelt(ref frac, traffic, ModeOutputItem(mode));
			}
			frac.isWorking = flag && (frac.fluidInputCount > 0 || frac.productOutputCount > 0 || frac.fluidInputInc > 0 || frac.fluidOutputCount > 0 || frac.progress > 0);
		}

		internal static float GetPowerRatio(FactorySystem fs, in FractionatorComponent frac)
		{
			try
			{
				PowerSystem val = fs.factory?.powerSystem;
				if (val == null || frac.pcId <= 0 || frac.pcId >= val.consumerPool.Length)
				{
					return 0f;
				}
				int networkId = val.consumerPool[frac.pcId].networkId;
				if (networkId <= 0 || val.netPool == null || networkId >= val.netPool.Length)
				{
					return 0f;
				}
				PowerNetwork val2 = val.netPool[networkId];
				return (val2 != null) ? ((float)val2.consumerRatio) : 0f;
			}
			catch
			{
				return 0f;
			}
		}

		private static void IntakeFromBelt(ref FractionatorComponent frac, CargoTraffic traffic, int beltId, int itemId)
		{
			byte b = default(byte);
			byte b2 = default(byte);
			if (frac.fluidInputCount < 20000 && traffic.GetItemIdAtRear(beltId) == itemId && traffic.TryPickItemAtRear(beltId, itemId, (int[])null, ref b, ref b2) > 0 && b > 0)
			{
				frac.fluidInputCount += b;
				frac.fluidInputCargoCount = (int)b;
				Plugin.LogInfo($"in : +{b} #{itemId} (pending {frac.fluidInputCount})");
			}
		}

		private static void ConvertBuySails(ref FractionatorComponent frac, double price, double tax)
		{
			int num = Math.Max(1, (int)Math.Ceiling(price * (1.0 + tax)));
			int num2 = 0;
			while (frac.fluidInputCount >= num && frac.productOutputCount < 200 && num2++ < 4)
			{
				frac.fluidInputCount -= num;
				frac.productOutputCount++;
				Plugin.LogInfo($"buy: -{num} sail -> +1 coin (out buffer {frac.productOutputCount})");
			}
		}

		private static void ConvertSellSails(ref FractionatorComponent frac, double price, double tax)
		{
			double num = price * (1.0 - tax);
			int num2 = (int)Math.Floor(num * 1000.0);
			if (num2 <= 0 && num > 0.0)
			{
				num2 = 1;
			}
			int num3 = 0;
			while (frac.fluidInputCount > 0 && frac.progress < 100000 && num3++ < 4)
			{
				frac.fluidInputCount--;
				frac.progress += num2;
			}
			while (frac.progress >= 1000 && frac.productOutputCount < 200)
			{
				frac.progress -= 1000;
				frac.productOutputCount++;
				Plugin.LogInfo($"sell: +1 sail (out buffer {frac.productOutputCount}, milli left {frac.progress})");
			}
		}

		private static void ConvertBuyPhotons(ref FractionatorComponent frac)
		{
			int num = Math.Max(1, Plugin.PhotonCoinCost.Value);
			int num2 = 0;
			while (frac.fluidInputCount >= num && frac.productOutputCount < 200 && num2++ < 4)
			{
				frac.fluidInputCount -= num;
				frac.productOutputCount++;
				Plugin.LogInfo($"photon: -{num} coin -> +1 photon (out buffer {frac.productOutputCount})");
			}
		}

		private static void OutputToBelt(ref FractionatorComponent frac, CargoTraffic traffic, int outputItem)
		{
			int belt = frac.belt0;
			if (belt > 0 && frac.productOutputCount > 0 && traffic.TryInsertItemAtHead(belt, outputItem, (byte)1, (byte)0))
			{
				frac.productOutputCount--;
			}
		}

		internal static void RefundPending(ref FractionatorComponent frac, Player player)
		{
			int mode = GetMode(in frac);
			int fluidInputCount = frac.fluidInputCount;
			int productOutputCount = frac.productOutputCount;
			int num = ((mode == 0) ? (frac.progress / 1000) : 0);
			int fluidInputInc = frac.fluidInputInc;
			int fluidOutputCount = frac.fluidOutputCount;
			Plugin.LogInfo($"[refund] frac entity={frac.entityId} mode={mode} in={fluidInputCount} out={productOutputCount} prog={frac.progress} oldCoin={fluidInputInc} oldSail={fluidOutputCount} player={player != null}");
			if (player != null)
			{
				int num2 = ModeInputItem(mode);
				int num3 = ModeOutputItem(mode);
				if (fluidInputCount > 0)
				{
					player.TryAddItemToPackage(num2, fluidInputCount, 0, true, 0, false);
				}
				if (productOutputCount > 0)
				{
					player.TryAddItemToPackage(num3, productOutputCount, 0, true, 0, false);
				}
				if (num > 0)
				{
					player.TryAddItemToPackage(1501, num, 0, true, 0, false);
				}
				if (fluidInputInc > 0)
				{
					player.TryAddItemToPackage(6008, fluidInputInc, 0, true, 0, false);
				}
				if (fluidOutputCount > 0)
				{
					player.TryAddItemToPackage(1501, fluidOutputCount, 0, true, 0, false);
				}
			}
			frac.fluidInputCount = 0;
			frac.fluidInputInc = 0;
			frac.fluidOutputCount = 0;
			frac.fluidOutputInc = 0;
			frac.productOutputCount = 0;
			frac.progress = 0;
		}
	}
	public static class PriceService
	{
		public static long GetEpoch()
		{
			int num = Math.Max(1, Plugin.PricePeriodMinutes.Value);
			long num2 = (long)(60.0 * 60.0 * (double)num);
			if (num2 > 0)
			{
				return GameMain.gameTick / num2;
			}
			return 0L;
		}

		public static double GetPrice(StarData star)
		{
			return GetPriceAt(star, GetEpoch());
		}

		public static double GetPriceAt(StarData star, long epoch)
		{
			return GetPriceAtContinuous(star, epoch);
		}

		public static double GetPriceAtContinuous(StarData star, double epoch)
		{
			if (star == null)
			{
				return Math.Max(0.1, Plugin.BasePrice.Value);
			}
			double value = Plugin.BasePrice.Value;
			double value2 = Plugin.RegionSpread.Value;
			double value3 = Plugin.Volatility.Value;
			double num = Hash01(star.seed, star.index * 31 + 7);
			double num2 = 1.0 + value2 * (num * 2.0 - 1.0);
			double num3 = Hash01(star.seed * 17 + 3, star.index * 131 + 11) * Math.PI * 2.0;
			double num4 = 0.65 * Math.Sin(epoch * 0.9 + num3) + 0.35 * Math.Sin(epoch * 0.37 + num3 * 2.1);
			double num5 = value * num2 * (1.0 + value3 * num4);
			if (num5 < 0.2)
			{
				num5 = 0.2;
			}
			else if (num5 > 5.0)
			{
				num5 = 5.0;
			}
			return num5;
		}

		public static void GetQuotes(double price, out int sailsPerCoin, out double sailsPerCoinSold)
		{
			double num = Math.Max(0.0, Math.Min(0.5, Plugin.TaxRate.Value));
			sailsPerCoin = Math.Max(1, (int)Math.Ceiling(price * (1.0 + num)));
			sailsPerCoinSold = Math.Max(0.0, price * (1.0 - num));
		}

		private static double Hash01(int a, int b)
		{
			ulong num = (((0x14650FB0739D0383uL ^ (ulong)(uint)a) * 1099511628211L) ^ (uint)b) * 1099511628211L;
			long num2 = (long)(num ^ (num >> 33)) * -49064778989728563L;
			long num3 = (num2 ^ (num2 >>> 33)) * -4265267296055464877L;
			return (double)((ulong)(num3 ^ (num3 >>> 33)) % 1000000uL) / 1000000.0;
		}
	}
	internal static class L10N
	{
		private static int cachedLcid = int.MinValue;

		private static bool cachedIsChinese;

		public static bool IsChinese
		{
			get
			{
				try
				{
					int currentLanguageLCID = Localization.CurrentLanguageLCID;
					if (currentLanguageLCID != cachedLcid)
					{
						cachedLcid = currentLanguageLCID;
						cachedIsChinese = currentLanguageLCID == 2052 || currentLanguageLCID == 1028;
					}
					return cachedIsChinese;
				}
				catch
				{
					return false;
				}
			}
		}

		public static string T(string cn, string en)
		{
			if (!IsChinese)
			{
				return en;
			}
			return cn;
		}
	}
	internal class MarketOverlay : MonoBehaviour
	{
		private static bool marketVisible;

		private static bool chartVisible;

		private static bool stylesReady;

		private static Font cjkFont;

		private static GUIStyle panelStyle;

		private static GUIStyle titleStyle;

		private static GUIStyle textStyle;

		private static GUIStyle hintStyle;

		private static GUIStyle buttonStyle;

		private static GUIStyle goldStyle;

		private static GUIStyle closeStyle;

		private static GUIStyle closeLabelStyle;

		private static Texture2D closeTex;

		private static GUIStyle rowStyle;

		private static readonly List<StarData> cheapest = new List<StarData>();

		private static readonly List<StarData> dearest = new List<StarData>();

		private static readonly List<double> cheapestPrice = new List<double>();

		private static readonly List<double> dearestPrice = new List<double>();

		private static readonly List<Rect> exchangeButtonRects = new List<Rect>();

		private static readonly List<TradeMode> exchangeButtonModes = new List<TradeMode>();

		private static readonly List<Rect> marketStarRects = new List<Rect>();

		private static readonly List<StarData> marketStarTargets = new List<StarData>();

		private static long cachedEpoch = long.MinValue;

		private static Rect marketCloseRect;

		private static Rect chartCloseRect;

		private static Rect exchangeCloseRect;

		private static bool hasMarketClose;

		private static bool hasChartClose;

		private static bool hasExchangeClose;

		private static Texture2D whiteTex;

		private void Update()
		{
			try
			{
				if (GameMain.data != null)
				{
					ExchangeLogic.TickAll();
				}
				HandleClicks();
				if (Plugin.ToggleMarketKey != null && Plugin.ToggleMarketKey.keyValue)
				{
					marketVisible = !marketVisible;
					if (marketVisible)
					{
						chartVisible = false;
					}
				}
				if (Plugin.ToggleChartKey != null && Plugin.ToggleChartKey.keyValue)
				{
					chartVisible = !chartVisible;
					if (chartVisible)
					{
						marketVisible = false;
					}
				}
				if (marketVisible && Input.GetKeyDown((KeyCode)27))
				{
					marketVisible = false;
				}
				if (chartVisible && Input.GetKeyDown((KeyCode)27))
				{
					chartVisible = false;
				}
			}
			catch (Exception e)
			{
				Plugin.LogError("overlay input failed", e);
			}
		}

		private void OnGUI()
		{
			try
			{
				EnsureStyles();
				hasMarketClose = false;
				hasChartClose = false;
				hasExchangeClose = false;
				exchangeButtonRects.Clear();
				exchangeButtonModes.Clear();
				marketStarRects.Clear();
				marketStarTargets.Clear();
				if (marketVisible)
				{
					DrawMarketPanel();
				}
				if (chartVisible)
				{
					DrawChartPanel();
				}
				DrawOpenExchangePanel();
			}
			catch (Exception e)
			{
				Plugin.LogError("overlay gui failed", e);
			}
		}

		private static void HandleClicks()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			if (!Input.GetMouseButtonDown(0))
			{
				return;
			}
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y);
			if (hasMarketClose && ((Rect)(ref marketCloseRect)).Contains(val))
			{
				marketVisible = false;
				return;
			}
			if (hasChartClose && ((Rect)(ref chartCloseRect)).Contains(val))
			{
				chartVisible = false;
				return;
			}
			if (hasExchangeClose && ((Rect)(ref exchangeCloseRect)).Contains(val))
			{
				UIGame val2 = (((Object)(object)UIRoot.instance != (Object)null) ? UIRoot.instance.uiGame : null);
				if ((Object)(object)val2 != (Object)null)
				{
					val2.ShutFractionatorWindow();
				}
				return;
			}
			Rect val3;
			for (int i = 0; i < exchangeButtonRects.Count; i++)
			{
				val3 = exchangeButtonRects[i];
				if (((Rect)(ref val3)).Contains(val))
				{
					UIFractionatorWindow openFractionatorWindow = GetOpenFractionatorWindow();
					if (!((Object)(object)openFractionatorWindow == (Object)null) && ExchangeLogic.TryGetExchange(openFractionatorWindow.factorySystem, openFractionatorWindow.fractionatorId, out var _))
					{
						Plugin.LogInfo("[ui] click mode button " + exchangeButtonModes[i]);
						ExchangeLogic.SetMode(openFractionatorWindow.factorySystem, openFractionatorWindow.fractionatorId, exchangeButtonModes[i], GameMain.mainPlayer);
					}
					return;
				}
			}
			if (!marketVisible)
			{
				return;
			}
			for (int j = 0; j < marketStarRects.Count && j < marketStarTargets.Count; j++)
			{
				val3 = marketStarRects[j];
				if (((Rect)(ref val3)).Contains(val))
				{
					ToggleNavigation(marketStarTargets[j]);
					break;
				}
			}
		}

		private static void ToggleNavigation(StarData star)
		{
			try
			{
				Player mainPlayer = GameMain.mainPlayer;
				if (mainPlayer != null && mainPlayer.navigation != null && star != null)
				{
					int astroId = star.astroId;
					if (astroId > 0)
					{
						mainPlayer.navigation.indicatorAstroId = ((mainPlayer.navigation.indicatorAstroId != astroId) ? astroId : 0);
						Plugin.LogInfo("navigate star " + star.displayName + " -> " + astroId);
					}
				}
			}
			catch (Exception e)
			{
				Plugin.LogError("toggle navigation failed", e);
			}
		}

		private void DrawMarketPanel()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			RefreshMarketCache();
			StarData localStar = GameMain.localStar;
			if (localStar != null)
			{
				double num = PriceService.GetEpoch();
				double priceAt = PriceService.GetPriceAt(localStar, (long)num);
				double priceAt2 = PriceService.GetPriceAt(localStar, (long)num - 1);
				double num2 = ((priceAt2 > 0.0001) ? ((priceAt - priceAt2) / priceAt2 * 100.0) : 0.0);
				double value = Plugin.TaxRate.Value;
				PriceService.GetQuotes(priceAt, out var sailsPerCoin, out var sailsPerCoinSold);
				GUI.Box(new Rect(16f, 16f, 560f, 382f), GUIContent.none, panelStyle);
				GUI.Label(new Rect(32f, 24f, 500f, 24f), L10N.T("光子证券交易所 · 行情", "Photon Stock Exchange · Market"), titleStyle);
				DrawCloseButton(546f, 26f, out marketCloseRect, out hasMarketClose);
				float num3 = 54f;
				GUI.Label(new Rect(32f, num3, 528f, 20f), string.Format(L10N.T("当前星系:{0}", "Current system: {0}"), ShortName(localStar)), textStyle);
				num3 += 21f;
				GUI.Label(new Rect(32f, num3, 528f, 20f), string.Format(L10N.T("基准价 1 币 = {0:0.00} 帆 ({1:+0.0;-0.0;0.0}%)", "Base price 1 coin = {0:0.00} sails ({1:+0.0;-0.0;0.0}%)"), priceAt, num2), textStyle);
				num3 += 21f;
				GUI.Label(new Rect(32f, num3, 528f, 20f), string.Format(L10N.T("税后 买币 {0} 帆 = 1 币 | 卖币 1 币 = {1:0.000} 帆", "After tax  buy {0} sails = 1 coin  |  sell 1 coin = {1:0.000} sails"), sailsPerCoin, sailsPerCoinSold), goldStyle);
				num3 += 21f;
				GUI.Label(new Rect(32f, num3, 528f, 20f), L10N.T("兑换光子 1 币 = 1 光子(不计税)", "Photon exchange: 1 coin = 1 photon (tax free)"), goldStyle);
				num3 += 22f;
				GUI.Label(new Rect(32f, num3, 528f, 18f), string.Format(L10N.T("第 {0} 期 | 每 {1} 分钟刷新 | 税率 {2:0.0}%", "Epoch {0}  |  refresh every {1} min  |  tax {2:0.0}%"), (long)num, Plugin.PricePeriodMinutes.Value, value * 100.0), hintStyle);
				num3 += 26f;
				GUI.Label(new Rect(32f, num3, 528f, 18f), L10N.T("最便宜星系(适合买入能量币,然后运到贵星系卖出)", "Cheapest systems (buy coins here, sell elsewhere)"), hintStyle);
				num3 += 22f;
				DrawRanking(16f, num3, 560f, cheapest, cheapestPrice);
				num3 += 78f;
				GUI.Label(new Rect(32f, num3, 528f, 18f), L10N.T("最贵星系(适合卖出能量币)", "Dearest systems (sell coins here)"), hintStyle);
				num3 += 22f;
				DrawRanking(16f, num3, 560f, dearest, dearestPrice);
				GUI.Label(new Rect(32f, 372f, 528f, 18f), L10N.T("点击星系名称可在星图上添加/取消导航线", "Click a system name to toggle its navigation marker"), hintStyle);
			}
		}

		private static void DrawRanking(float x, float ty, float w, List<StarData> stars, List<double> prices)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			float num = (w - 40f) * 0.5f;
			for (int i = 0; i < stars.Count && i < 6; i++)
			{
				int num2 = i / 3;
				int num3 = i % 3;
				float num4 = x + 18f + (float)num2 * num;
				float num5 = ty + (float)num3 * 22f;
				GUI.Label(new Rect(num4, num5, num - 8f, 22f), $"{i + 1}. {ShortName(stars[i])}", rowStyle);
				GUI.Label(new Rect(num4 + num - 92f, num5, 60f, 22f), prices[i].ToString("0.00"), textStyle);
				marketStarRects.Add(new Rect(num4, num5, num - 8f, 22f));
				marketStarTargets.Add(stars[i]);
			}
		}

		private void DrawChartPanel()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0424: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			StarData localStar = GameMain.localStar;
			if (localStar == null)
			{
				return;
			}
			float num = (float)Screen.width - 372f - 16f;
			GUI.Box(new Rect(num, 16f, 372f, 236f), GUIContent.none, panelStyle);
			GUI.Label(new Rect(num + 14f, 24f, 312f, 22f), L10N.T("光子证券交易所 · K 线 · ", "Photon Exchange · Chart · ") + ShortName(localStar), titleStyle);
			DrawCloseButton(num + 372f - 30f, 25f, out chartCloseRect, out hasChartClose);
			long epoch = PriceService.GetEpoch();
			double priceAtContinuous = PriceService.GetPriceAtContinuous(localStar, epoch);
			double[] array = new double[36];
			double[] array2 = new double[36];
			double[] array3 = new double[36];
			double[] array4 = new double[36];
			double num2 = double.MaxValue;
			double num3 = double.MinValue;
			for (int i = 0; i < 36; i++)
			{
				double num4 = epoch - (35 - i);
				array[i] = PriceService.GetPriceAtContinuous(localStar, num4);
				array2[i] = PriceService.GetPriceAtContinuous(localStar, num4 + 0.999);
				array3[i] = Math.Max(array[i], array2[i]);
				array4[i] = Math.Min(array[i], array2[i]);
				for (int j = 1; j < 8; j++)
				{
					double priceAtContinuous2 = PriceService.GetPriceAtContinuous(localStar, num4 + (double)j / 8.0);
					if (priceAtContinuous2 > array3[i])
					{
						array3[i] = priceAtContinuous2;
					}
					if (priceAtContinuous2 < array4[i])
					{
						array4[i] = priceAtContinuous2;
					}
				}
				if (array4[i] < num2)
				{
					num2 = array4[i];
				}
				if (array3[i] > num3)
				{
					num3 = array3[i];
				}
			}
			double num5 = Math.Max(0.02, (num3 - num2) * 0.08);
			num2 -= num5;
			num3 += num5;
			float num6 = num + 40f;
			float num7 = 72f;
			Color color = default(Color);
			((Color)(ref color))..ctor(1f, 1f, 1f, 0.08f);
			for (int k = 0; k <= 3; k++)
			{
				float num8 = num7 + 144f * (float)k / 3f;
				DrawRect(new Rect(num6, num8, 316f, 1f), color);
				double num9 = num3 - (num3 - num2) * (double)k / 3.0;
				GUI.Label(new Rect(num + 4f, num8 - 8f, 34f, 16f), num9.ToString("0.00"), hintStyle);
			}
			float num10 = 8.777778f;
			float num11 = Math.Max(3f, num10 * 0.55f);
			for (int l = 0; l < 36; l++)
			{
				float num12 = num6 + (float)l * num10 + num10 * 0.5f;
				Color color2 = ((array2[l] >= array[l]) ? new Color(0.95f, 0.3f, 0.28f) : new Color(0.3f, 0.85f, 0.45f));
				float num13 = PriceToY(array3[l], num2, num3, num7, 144f);
				float num14 = PriceToY(array4[l], num2, num3, num7, 144f);
				DrawRect(new Rect(num12 - 0.5f, num13, 1.5f, Math.Max(1f, num14 - num13)), color2);
				float num15 = PriceToY(array[l], num2, num3, num7, 144f);
				float num16 = PriceToY(array2[l], num2, num3, num7, 144f);
				float num17 = Math.Min(num15, num16);
				float num18 = Math.Max(1.5f, Math.Abs(num16 - num15));
				DrawRect(new Rect(num12 - num11 * 0.5f, num17, num11, num18), color2);
			}
			float num19 = PriceToY(priceAtContinuous, num2, num3, num7, 144f);
			DrawRect(new Rect(num6, num19, 316f, 1f), new Color(1f, 0.85f, 0.3f, 0.55f));
			GUI.Label(new Rect(num + 14f, 226f, 344f, 18f), string.Format(L10N.T("现价 {0:0.00} | 每格 {1} 分钟 | 红涨绿跌 | 共 {2} 格", "Now {0:0.00} | {1} min/bar | red up, green down | {2} bars"), priceAtContinuous, Math.Max(1, Plugin.PricePeriodMinutes.Value), 36), hintStyle);
		}

		private static float PriceToY(double price, double min, double max, float py, float plotH)
		{
			if (max - min < 1E-09)
			{
				return py + plotH * 0.5f;
			}
			double num = (price - min) / (max - min);
			return (float)((double)py + (double)plotH * (1.0 - num));
		}

		private void DrawOpenExchangePanel()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			UIFractionatorWindow openFractionatorWindow = GetOpenFractionatorWindow();
			if (!((Object)(object)openFractionatorWindow == (Object)null) && ExchangeLogic.TryGetExchange(openFractionatorWindow.factorySystem, openFractionatorWindow.fractionatorId, out var frac))
			{
				FactorySystem factorySystem = openFractionatorWindow.factorySystem;
				StarData val = ((factorySystem.planet != null) ? factorySystem.planet.star : null);
				if (val != null)
				{
					int fractionatorId = openFractionatorWindow.fractionatorId;
					int mode = ExchangeLogic.GetMode(in frac);
					double price = PriceService.GetPrice(val);
					PriceService.GetQuotes(price, out var sailsPerCoin, out var sailsPerCoinSold);
					int num = Math.Max(1, Plugin.PhotonCoinCost.Value);
					int fluidInputCount = frac.fluidInputCount;
					int productOutputCount = frac.productOutputCount;
					float powerRatio = ExchangeLogic.GetPowerRatio(factorySystem, in frac);
					string arg = ((powerRatio <= 0.1f) ? L10N.T("未供电", "No power") : ((powerRatio < 0.99f) ? L10N.T("电力不足", "Low power") : L10N.T("已通电", "Powered")));
					float num2 = (marketVisible ? 404f : 16f);
					GUI.Box(new Rect(16f, num2, 620f, 344f), GUIContent.none, panelStyle);
					float num3 = 16f + 14f;
					float num4 = num2 + 8f;
					GUI.Label(new Rect(num3, num4, 556f, 24f), string.Format(L10N.T("光子证券交易所 #{0} · {1}", "Photon Stock Exchange #{0} · {1}"), fractionatorId, ShortName(val)), titleStyle);
					DrawCloseButton(16f + 620f - 34f, num2 + 8f, out exchangeCloseRect, out hasExchangeClose);
					num4 += 30f;
					GUI.Label(new Rect(num3, num4, 590f, 24f), string.Format(L10N.T("状态:{0}    模式:{1}", "Status: {0}    Mode: {1}"), arg, ExchangeLogic.ModeName(mode)), goldStyle);
					num4 += 27f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), string.Format(L10N.T("基准价:1 能量币 = {0:0.00} 太阳帆", "Base price: 1 coin = {0:0.00} sails"), price), textStyle);
					num4 += 26f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), string.Format(L10N.T("税后:买币 {0} 帆 = 1 币", "After tax: buy {0} sails = 1 coin"), sailsPerCoin), textStyle);
					num4 += 26f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), string.Format(L10N.T("税后:卖币 1 币 = {0:0.000} 帆", "After tax: sell 1 coin = {0:0.000} sails"), sailsPerCoinSold), textStyle);
					num4 += 26f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), string.Format(L10N.T("兑换光子:{0} 能量币 = 1 光子(不计税)", "Photons: {0} coins = 1 photon (tax free)"), num), textStyle);
					num4 += 26f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), string.Format(L10N.T("仓内:输入 {0} 件 | 产出 {1} 件", "Buffered: input {0}  |  output {1}"), fluidInputCount, productOutputCount), hintStyle);
					num4 += 30f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), L10N.T("切换模式(仓内物品会退还给你):", "Switch mode (buffered items are refunded to you):"), hintStyle);
					num4 += 26f;
					DrawModeButton(new Rect(num3, num4, 168f, 28f), L10N.T("卖出币(币→帆)", "Sell coins (coins->sails)"), TradeMode.SellSails, mode);
					DrawModeButton(new Rect(num3 + 176f, num4, 168f, 28f), L10N.T("买入币(帆→币)", "Buy coins (sails->coins)"), TradeMode.BuySails, mode);
					DrawModeButton(new Rect(num3 + 352f, num4, 196f, 28f), L10N.T("兑换光子(币→光子)", "Buy photons (coins->photons)"), TradeMode.BuyPhotons, mode);
					num4 += 34f;
					GUI.Label(new Rect(num3, num4, 590f, 22f), L10N.T("两侧传送带进货,中间传送带出货(无延迟)。", "Side belts = input, middle belt = output (no delay)."), hintStyle);
				}
			}
		}

		private static void DrawModeButton(Rect rect, string label, TradeMode target, int currentMode)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			string text = ((target == (TradeMode)currentMode) ? ("> " + label + " <") : label);
			GUI.Button(rect, text, buttonStyle);
			exchangeButtonRects.Add(rect);
			exchangeButtonModes.Add(target);
		}

		private static UIFractionatorWindow GetOpenFractionatorWindow()
		{
			try
			{
				UIGame val = (((Object)(object)UIRoot.instance != (Object)null) ? UIRoot.instance.uiGame : null);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				UIFractionatorWindow fractionatorWindow = val.fractionatorWindow;
				if ((Object)(object)fractionatorWindow == (Object)null || !((ManualBehaviour)fractionatorWindow).active || fractionatorWindow.fractionatorId <= 0 || fractionatorWindow.factorySystem == null)
				{
					return null;
				}
				return fractionatorWindow;
			}
			catch
			{
				return null;
			}
		}

		private static string ShortName(StarData star)
		{
			if (star == null)
			{
				return "?";
			}
			string text = star.displayName;
			if (string.IsNullOrEmpty(text))
			{
				text = star.name;
			}
			if (string.IsNullOrEmpty(text))
			{
				return "#" + star.index;
			}
			if (text.Length > 6)
			{
				return text.Substring(0, 6);
			}
			return text;
		}

		private static void RefreshMarketCache()
		{
			long epoch = PriceService.GetEpoch();
			if (epoch == cachedEpoch && cheapest.Count > 0)
			{
				return;
			}
			cachedEpoch = epoch;
			cheapest.Clear();
			dearest.Clear();
			cheapestPrice.Clear();
			dearestPrice.Clear();
			GalaxyData galaxy = GameMain.galaxy;
			if (galaxy == null || galaxy.stars == null)
			{
				return;
			}
			int starCount = galaxy.starCount;
			for (int i = 0; i < starCount; i++)
			{
				StarData val = galaxy.stars[i];
				if (val != null)
				{
					double priceAt = PriceService.GetPriceAt(val, epoch);
					InsertSorted(val, priceAt, cheapest, cheapestPrice, ascending: true);
					InsertSorted(val, priceAt, dearest, dearestPrice, ascending: false);
				}
			}
		}

		private static void InsertSorted(StarData star, double price, List<StarData> stars, List<double> prices, bool ascending)
		{
			int num = prices.Count;
			int num2 = 6;
			for (int i = 0; i < prices.Count; i++)
			{
				if (ascending ? (price < prices[i]) : (price > prices[i]))
				{
					num = i;
					break;
				}
			}
			if (num < num2)
			{
				prices.Insert(num, price);
				stars.Insert(num, star);
				if (prices.Count > num2)
				{
					prices.RemoveAt(prices.Count - 1);
					stars.RemoveAt(stars.Count - 1);
				}
			}
		}

		private static void DrawCloseButton(float x, float y, out Rect rect, out bool has)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			rect = new Rect(x, y, 22f, 22f);
			has = true;
			GUI.Box(rect, GUIContent.none, closeStyle);
			if ((Object)(object)closeTex == (Object)null)
			{
				closeTex = MakeCloseTexture();
			}
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 5f, ((Rect)(ref rect)).y + 5f, 12f, 12f), (Texture)(object)closeTex);
		}

		private static Texture2D MakeCloseTexture()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(12, 12, (TextureFormat)4, false);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 1f, 1f, 0f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(1f, 0.38f, 0.33f, 1f);
			for (int i = 0; i < 12; i++)
			{
				for (int j = 0; j < 12; j++)
				{
					bool flag = Mathf.Abs(j - i) <= 1;
					bool flag2 = Mathf.Abs(j - (11 - i)) <= 1;
					bool flag3 = (j < 2 && i < 2) || (j < 2 && i > 9) || (j > 9 && i < 2) || (j > 9 && i > 9);
					val.SetPixel(j, i, ((flag || flag2) && !flag3) ? val3 : val2);
				}
			}
			val.Apply();
			return val;
		}

		private static void DrawRect(Rect rect, Color color)
		{
			//IL_0036: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)whiteTex == (Object)null)
			{
				whiteTex = new Texture2D(1, 1, (TextureFormat)4, false);
				whiteTex.SetPixel(0, 0, Color.white);
				whiteTex.Apply();
			}
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)whiteTex);
			GUI.color = color2;
		}

		private static Texture2D MakeTex(Color color)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixel(0, 0, color);
			val.Apply();
			return val;
		}

		private static void EnsureStyles()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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_0154: Expected O, but got Unknown
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: 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_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Expected O, but got Unknown
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Expected O, but got Unknown
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			if (!stylesReady)
			{
				stylesReady = true;
				try
				{
					cjkFont = Font.CreateDynamicFontFromOSFont(new string[5] { "Microsoft YaHei", "Microsoft YaHei UI", "SimHei", "Noto Sans CJK SC", "Arial Unicode MS" }, 14);
				}
				catch
				{
					cjkFont = null;
				}
				panelStyle = new GUIStyle(GUI.skin.box);
				panelStyle.normal.background = MakeTex(new Color(0.04f, 0.05f, 0.07f, 0.9f));
				titleStyle = MakeLabel(15, (FontStyle)1, new Color(1f, 0.85f, 0.3f));
				goldStyle = MakeLabel(13, (FontStyle)1, new Color(1f, 0.78f, 0.25f));
				textStyle = MakeLabel(12, (FontStyle)0, Color.white);
				hintStyle = MakeLabel(11, (FontStyle)0, new Color(0.72f, 0.78f, 0.84f));
				rowStyle = MakeLabel(12, (FontStyle)0, new Color(0.95f, 0.92f, 0.85f));
				buttonStyle = new GUIStyle(GUI.skin.button)
				{
					fontSize = 12,
					alignment = (TextAnchor)4,
					wordWrap = false
				};
				if ((Object)(object)cjkFont != (Object)null)
				{
					buttonStyle.font = cjkFont;
				}
				GUIStyle val = new GUIStyle(GUI.skin.button)
				{
					fontSize = 15,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4,
					padding = new RectOffset(0, 0, 0, 0),
					border = new RectOffset(0, 0, 0, 0)
				};
				val.normal.textColor = new Color(1f, 0.42f, 0.38f);
				val.hover.textColor = new Color(1f, 0.25f, 0.2f);
				val.active.textColor = new Color(1f, 0.2f, 0.15f);
				closeStyle = val;
				if ((Object)(object)cjkFont != (Object)null)
				{
					closeStyle.font = cjkFont;
				}
				closeLabelStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 16,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4,
					padding = new RectOffset(0, 0, 0, 0),
					wordWrap = false
				};
				closeLabelStyle.normal.textColor = new Color(1f, 0.42f, 0.38f);
				if ((Object)(object)cjkFont != (Object)null)
				{
					closeLabelStyle.font = cjkFont;
				}
			}
		}

		private static GUIStyle MakeLabel(int size, FontStyle style, Color color)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = size,
				fontStyle = style,
				wordWrap = false
			};
			val.normal.textColor = color;
			if ((Object)(object)cjkFont != (Object)null)
			{
				val.font = cjkFont;
			}
			return val;
		}
	}
	internal static class Patches
	{
		[HarmonyPatch(typeof(FactorySystem), "GameTick")]
		internal static class FactorySystemGameTickPostfix
		{
			[HarmonyPostfix]
			internal static void Postfix(FactorySystem __instance)
			{
				try
				{
					ExchangeLogic.TickFactory(__instance);
				}
				catch (Exception e)
				{
					Plugin.LogError("GameTick postfix failed", e);
				}
			}
		}

		[HarmonyPatch(typeof(GameHistoryData), "UnlockTech")]
		internal static class UnlockTechPostfix
		{
			[HarmonyPostfix]
			internal static void Postfix(GameHistoryData __instance, int techId)
			{
				try
				{
					if (techId == Plugin.UnlockTechId.Value)
					{
						ExchangeLogic.EnsureRecipeUnlocked();
					}
				}
				catch (Exception e)
				{
					Plugin.LogError("UnlockTech postfix failed", e);
				}
			}
		}

		[HarmonyPatch(typeof(FactorySystem), "TakeBackItems_Fractionator")]
		internal static class TakeBackItemsFractionatorPrefix
		{
			[HarmonyPrefix]
			internal static void Prefix(FactorySystem __instance, Player player, int fracId)
			{
				try
				{
					if (TryGetExchange(__instance, fracId, out var _))
					{
						ref FractionatorComponent frac2 = ref __instance.fractionatorPool[fracId];
						Plugin.LogInfo($"[refund] TakeBackItems_Fractionator path, fracId={fracId}");
						ExchangeLogic.RefundPending(ref frac2, player);
					}
				}
				catch (Exception e)
				{
					Plugin.LogError("TakeBackItems prefix failed", e);
				}
			}
		}

		[HarmonyPatch(typeof(PlanetFactory), "ClearItemsInEntity")]
		internal static class ClearItemsInEntityPrefix
		{
			[HarmonyPrefix]
			internal static void Prefix(PlanetFactory __instance, int entityId)
			{
				try
				{
					if (__instance == null || __instance.entityPool == null || entityId <= 0 || entityId >= __instance.entityPool.Length || __instance.entityPool[entityId].protoId != 6009)
					{
						return;
					}
					FactorySystem factorySystem = __instance.factorySystem;
					if (factorySystem != null && factorySystem.fractionatorPool != null)
					{
						int fractionatorId = __instance.entityPool[entityId].fractionatorId;
						if (TryGetExchange(factorySystem, fractionatorId, out var _))
						{
							ref FractionatorComponent frac2 = ref factorySystem.fractionatorPool[fractionatorId];
							Plugin.LogInfo($"[refund] ClearItemsInEntity path, entityId={entityId} fracId={fractionatorId}");
							ExchangeLogic.RefundPending(ref frac2, GameMain.mainPlayer);
						}
					}
				}
				catch (Exception e)
				{
					Plugin.LogError("ClearItemsInEntity prefix failed", e);
				}
			}
		}

		[HarmonyPatch(typeof(UIFractionatorWindow), "_OnUpdate")]
		internal static class FractionatorWindowUpdatePostfix
		{
			[HarmonyPostfix]
			internal static void Postfix(UIFractionatorWindow __instance)
			{
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)__instance == (Object)null || __instance.fractionatorId <= 0 || __instance.factorySystem == null || !ExchangeLogic.TryGetExchange(__instance.factorySystem, __instance.fractionatorId, out var frac))
					{
						return;
					}
					FactorySystem factorySystem = __instance.factorySystem;
					StarData val = ((factorySystem.planet != null) ? factorySystem.planet.star : null);
					if (val != null)
					{
						int mode = ExchangeLogic.GetMode(in frac);
						PriceService.GetQuotes(PriceService.GetPrice(val), out var sailsPerCoin, out var sailsPerCoinSold);
						float powerRatio = ExchangeLogic.GetPowerRatio(factorySystem, in frac);
						string text = ((powerRatio <= 0.1f) ? L10N.T("未供电", "No power") : ((powerRatio < 0.99f) ? L10N.T("电力不足", "Low power") : ((frac.fluidInputCount <= 0 && frac.productOutputCount <= 0) ? L10N.T("待机(等待原料)", "Idle (waiting for input)") : L10N.T("运转中", "Running"))));
						if ((Object)(object)__instance.titleText != (Object)null)
						{
							__instance.titleText.text = L10N.T("光子证券交易所", "Photon Stock Exchange");
						}
						HideProductWidgets(__instance);
						Text remindText = __instance.remindText;
						if ((Object)(object)__instance.stateText != (Object)null)
						{
							__instance.stateText.text = ((powerRatio < 0.99f) ? text : string.Empty);
							ApplyPlainStyle(__instance.stateText, remindText);
							__instance.stateText.fontSize = 14;
						}
						if ((Object)(object)__instance.remindText != (Object)null)
						{
							((Behaviour)__instance.remindText).enabled = false;
							__instance.remindText.text = string.Empty;
						}
						if ((Object)(object)__instance.historyText != (Object)null)
						{
							((Behaviour)__instance.historyText).enabled = true;
							ApplyPlainStyle(__instance.historyText, remindText);
							__instance.historyText.fontSize = 13;
							__instance.historyText.alignment = (TextAnchor)0;
							__instance.historyText.lineSpacing = 1.25f;
							__instance.historyText.horizontalOverflow = (HorizontalWrapMode)0;
							__instance.historyText.verticalOverflow = (VerticalWrapMode)1;
							__instance.historyText.text = string.Format(L10N.T("当前模式:{0}", "Mode: {0}"), ExchangeLogic.ModeName(mode)) + "\r\n" + string.Format(L10N.T("税后:买币 {0} 帆 = 1 币", "After tax: buy {0} sails = 1 coin"), sailsPerCoin) + "\r\n" + string.Format(L10N.T("税后:卖币 1 币 = {0:0.000} 帆", "After tax: sell 1 coin = {0:0.000} sails"), sailsPerCoinSold) + "\r\n" + L10N.T("两侧传送带进货,中间传送带出货(无延迟)。", "Side belts = input, middle belt = output (no delay).");
							AlignTextLeftToTitle(__instance);
						}
					}
				}
				catch (Exception e)
				{
					Plugin.LogError("FractionatorWindow postfix failed", e);
				}
			}
		}

		internal static void AlignTextLeftToTitle(UIFractionatorWindow window)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Transform transform = ((Component)window).transform;
				RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				RectTransform val2 = (((Object)(object)window.titleText != (Object)null) ? ((Graphic)window.titleText).rectTransform : null);
				RectTransform val3 = (((Object)(object)window.historyText != (Object)null) ? ((Graphic)window.historyText).rectTransform : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null))
				{
					Rect rect = val.rect;
					float num = ((Rect)(ref rect)).width;
					if (num < 80f)
					{
						num = 420f;
					}
					float num2 = Mathf.Max(140f, num - 56f);
					val3.SetSizeWithCurrentAnchors((Axis)0, num2);
					Vector3 val4 = ((Transform)val).InverseTransformPoint(((Transform)val2).position);
					Vector3 val5 = ((Transform)val).InverseTransformPoint(((Transform)val3).position);
					float x = val4.x;
					rect = val2.rect;
					float num3 = x - ((Rect)(ref rect)).width * val2.pivot.x;
					float num4 = val5.x - num2 * val3.pivot.x;
					float num5 = num3 - num4;
					float num6 = Mathf.Max(12f, (float)window.historyText.fontSize * Mathf.Max(1f, window.historyText.lineSpacing) + 3f) * 4f;
					RectTransform val6 = (((Object)(object)window.powerText != (Object)null) ? ((Graphic)window.powerText).rectTransform : null);
					float num7;
					if (!((Object)(object)val6 != (Object)null))
					{
						rect = val.rect;
						num7 = ((Rect)(ref rect)).yMax - 90f;
					}
					else
					{
						float y = ((Transform)val).InverseTransformPoint(((Transform)val6).position).y;
						rect = val6.rect;
						num7 = y - ((Rect)(ref rect)).height * 0.5f - 6f;
					}
					float num8 = num7;
					rect = val.rect;
					float num9 = ((Rect)(ref rect)).yMin + 14f;
					if (num9 > num8 - num6)
					{
						num9 = num8 - num6;
					}
					float num10 = (num8 + num9) * 0.5f + (val3.pivot.y - 0.5f) * num6;
					val3.SetSizeWithCurrentAnchors((Axis)1, num6);
					((Transform)val3).position = ((Transform)val).TransformPoint(new Vector3(val5.x + num5, num10, val5.z));
				}
			}
			catch (Exception e)
			{
				Plugin.LogError("align text failed", e);
			}
		}

		internal static void HideProductWidgets(UIFractionatorWindow window)
		{
			try
			{
				if ((Object)(object)window.productBox != (Object)null)
				{
					window.productBox.SetActive(false);
				}
				if ((Object)(object)window.oriProductBox != (Object)null)
				{
					window.oriProductBox.SetActive(false);
				}
				if ((Object)(object)window.productButton != (Object)null)
				{
					((Component)window.productButton).gameObject.SetActive(false);
				}
				if ((Object)(object)window.oriProductButton != (Object)null)
				{
					((Component)window.oriProductButton).gameObject.SetActive(false);
				}
				if ((Object)(object)window.needIcon != (Object)null)
				{
					((Behaviour)window.needIcon).enabled = false;
				}
				if ((Object)(object)window.productIcon != (Object)null)
				{
					((Behaviour)window.productIcon).enabled = false;
				}
				if ((Object)(object)window.oriProductIcon != (Object)null)
				{
					((Behaviour)window.oriProductIcon).enabled = false;
				}
				if (window.needIncs != null)
				{
					for (int i = 0; i < window.needIncs.Length; i++)
					{
						if ((Object)(object)window.needIncs[i] != (Object)null)
						{
							((Behaviour)window.needIncs[i]).enabled = false;
						}
					}
				}
				if (window.oriProductIncs != null)
				{
					for (int j = 0; j < window.oriProductIncs.Length; j++)
					{
						if ((Object)(object)window.oriProductIncs[j] != (Object)null)
						{
							((Behaviour)window.oriProductIncs[j]).enabled = false;
						}
					}
				}
				if (window.speedArrows == null)
				{
					return;
				}
				for (int k = 0; k < window.speedArrows.Length; k++)
				{
					if ((Object)(object)window.speedArrows[k] != (Object)null)
					{
						((Behaviour)window.speedArrows[k]).enabled = false;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.LogError("hide product widgets failed", e);
			}
		}

		internal static void ApplyPlainStyle(Text target, Text styleSource)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null) && !((Object)(object)styleSource == (Object)null))
			{
				target.font = styleSource.font;
				((Graphic)target).material = ((Graphic)styleSource).material;
				((Graphic)target).color = ((Graphic)styleSource).color;
				target.fontSize = styleSource.fontSize;
				target.lineSpacing = 1.1f;
				target.supportRichText = false;
			}
		}

		internal static bool TryGetExchange(FactorySystem fs, int fracId, out FractionatorComponent frac)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			frac = default(FractionatorComponent);
			if (fs == null || fs.factory == null || fs.fractionatorPool == null)
			{
				return false;
			}
			if (fracId <= 0 || fracId >= fs.fractionatorPool.Length)
			{
				return false;
			}
			ref FractionatorComponent reference = ref fs.fractionatorPool[fracId];
			if (reference.id != fracId || reference.entityId <= 0)
			{
				return false;
			}
			EntityData[] entityPool = fs.factory.entityPool;
			if (reference.entityId >= entityPool.Length || entityPool[reference.entityId].protoId != 6009)
			{
				return false;
			}
			frac = reference;
			return true;
		}
	}
	[BepInPlugin("com.xcm.dsp.stockexchange", "Photon Stock Exchange", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[CommonAPISubmoduleDependency(new string[] { "ProtoRegistry", "LocalizationModule", "CustomKeyBindSystem" })]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.xcm.dsp.stockexchange";

		public const string NAME = "Photon Stock Exchange";

		public const string VERSION = "0.1.1";

		public const int ItemCoin = 6008;

		public const int ItemExchange = 6009;

		public const int RecipeExchange = 6010;

		public const int ModelExchange = 667;

		public const int BuildIndexExchange = 410;

		public const int VanillaItemFractionator = 2314;

		public const int VanillaModelFractionator = 119;

		public const int ItemSunSail = 1501;

		public const int ItemSmallRocket = 1503;

		public const int ItemCriticalPhoton = 1208;

		private static readonly int[] ExchangeRecipeInputs = new int[4] { 1103, 1108, 1110, 1303 };

		private static readonly int[] ExchangeRecipeCounts = new int[4] { 8, 4, 4, 1 };

		internal static ItemProto CoinItem;

		internal static ItemProto ExchangeItem;

		internal static RecipeProto ExchangeRecipe;

		internal static ModelProto ExchangeModel;

		public static PressKeyBind ToggleMarketKey;

		public static PressKeyBind ToggleChartKey;

		public static ConfigEntry<double> TaxRate;

		public static ConfigEntry<double> BasePrice;

		public static ConfigEntry<double> RegionSpread;

		public static ConfigEntry<double> Volatility;

		public static ConfigEntry<int> PricePeriodMinutes;

		public static ConfigEntry<int> PhotonCoinCost;

		public static ConfigEntry<int> UnlockTechId;

		public static ConfigEntry<bool> EnableTint;

		public static ConfigEntry<bool> VerboseLog;

		public static ConfigEntry<bool> RequirePower;

		private static int errorLogged;

		private const string CoinIconResource = "StockExchange.coin.png";

		private static Sprite goldExchangeIconSprite;

		private static Sprite coinIconSprite;

		public static Plugin Instance { get; private set; }

		public static bool Registered { get; private set; }

		private void Awake()
		{
			Instance = this;
			RegisterLocalizedStrings();
			TaxRate = ((BaseUnityPlugin)this).Config.Bind<double>("Economy", "TaxRate", 0.02, "买卖印花税比例(0~0.2)。买入需要多付、卖出会少得。");
			BasePrice = ((BaseUnityPlugin)this).Config.Bind<double>("Economy", "BasePrice", 1.0, "全局基准价:1 能量币 值多少太阳帆(未计地区与涨跌)。");
			RegionSpread = ((BaseUnityPlugin)this).Config.Bind<double>("Economy", "RegionSpread", 0.3, "星系间地区价差幅度:0.3 表示各星系价格在 0.7~1.3 倍之间浮动。");
			Volatility = ((BaseUnityPlugin)this).Config.Bind<double>("Economy", "Volatility", 0.15, "时间涨跌幅度:0.15 表示价格每 5 分钟在 ±15% 内波动。");
			PricePeriodMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("Economy", "PricePeriodMinutes", 10, "价格刷新周期(分钟)。默认 10 分钟。");
			PhotonCoinCost = ((BaseUnityPlugin)this).Config.Bind<int>("Economy", "PhotonCoinCost", 1, "买入 1 枚临界光子需要多少能量币。默认 1 币 = 1 光子(暂定)。");
			UnlockTechId = ((BaseUnityPlugin)this).Config.Bind<int>("Unlock", "UnlockTechId", 1508, "解锁本建筑配方的科技 ID。1508 = 任务完成!(通关科技);填 0 表示开局即可用。");
			EnableTint = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "EnableTint", true, "把交易所建筑染成金色,便于与木色分馏塔区分。");
			VerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLog", false, "输出交易明细日志。");
			RequirePower = ((BaseUnityPlugin)this).Config.Bind<bool>("Economy", "RequirePower", true, "交易所是否必须通电才工作(与原版建筑一致)。开发期可临时关掉。");
			try
			{
				RegisterProtos();
			}
			catch (Exception e)
			{
				LogError("RegisterProtos failed", e);
			}
			try
			{
				Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "com.xcm.dsp.stockexchange");
			}
			catch (Exception e2)
			{
				LogError("Harmony patch failed", e2);
			}
			try
			{
				RegisterKeyBind();
			}
			catch (Exception e3)
			{
				LogError("keybind register failed", e3);
			}
			try
			{
				((Component)this).gameObject.AddComponent<MarketOverlay>();
			}
			catch (Exception e4)
			{
				LogError("MarketOverlay attach failed", e4);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded (ids: coin={2}, building={3})", "Photon Stock Exchange", "0.1.1", 6008, 6009));
		}

		private static void RegisterKeyBind()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			ToggleMarketKey = CustomKeyBindSystem.RegisterKeyBindWithReturn<PressKeyBind>(new BuiltinKey
			{
				name = "OpenEnergyCoinMarket",
				key = new CombineKey(51, (byte)4, (ECombineKeyAction)0, false),
				canOverride = true,
				conflictGroup = 2821
			});
			ToggleChartKey = CustomKeyBindSystem.RegisterKeyBindWithReturn<PressKeyBind>(new BuiltinKey
			{
				name = "OpenEnergyCoinChart",
				key = new CombineKey(52, (byte)4, (ECombineKeyAction)0, false),
				canOverride = true,
				conflictGroup = 2821
			});
			try
			{
				LocalizationModule.RegisterTranslation("OpenEnergyCoinMarket", "Exchange Market", "交易所行情", "Marché");
				LocalizationModule.RegisterTranslation("KEYOpenEnergyCoinMarket", "Exchange Market", "交易所行情", "Marché");
				LocalizationModule.RegisterTranslation("OpenEnergyCoinChart", "Exchange Chart", "交易所K线", "Graphique");
				LocalizationModule.RegisterTranslation("KEYOpenEnergyCoinChart", "Exchange Chart", "交易所K线", "Graphique");
			}
			catch (Exception ex)
			{
				LogInfo("keybind string register skipped: " + ex.Message);
			}
		}

		private static void RegisterLocalizedStrings()
		{
			try
			{
				LocalizationModule.RegisterTranslation("光子证券交易所", "Photon Stock Exchange", "光子证券交易所", "Bourse photonique");
				LocalizationModule.RegisterTranslation("能量币", "Energy Coin", "能量币", "Pièce d'énergie");
				LocalizationModule.RegisterTranslation("传送带式证券交易所:两侧进料、中间出料。价格随所在星系不同,并定时刷新。", "Belt-fed stock exchange: the side belts feed in, the middle belt outputs. Prices differ per star system and refresh periodically.", "传送带式证券交易所:两侧进料、中间出料。价格随所在星系不同,并定时刷新。", "Bourse à convoyeurs : entrées latérales, sortie centrale, prix variables selon le système.");
				LocalizationModule.RegisterTranslation("建造一座光子证券交易所。", "Build a Photon Stock Exchange.", "建造一座光子证券交易所。", "Construire une Bourse photonique.");
			}
			catch (Exception ex)
			{
				LogInfo("localized strings register skipped: " + ex.Message);
			}
		}

		private static void RegisterProtos()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			using (ProtoRegistry.StartModLoad("com.xcm.dsp.stockexchange"))
			{
				CoinItem = ProtoRegistry.RegisterItem(6008, "能量币", "星际股票交易所的通用货币。可在不同星系之间低买高卖。", "Icons/ItemRecipe/assembler-4", ProtoRegistry.GetGridIndex(4, 11, 10), 500, (EItemType)2, ProtoRegistry.GetDefaultIconDesc(new Color(1f, 0.85f, 0.2f), new Color(0.95f, 0.62f, 0.1f)));
				CoinItem.UnlockKey = -1;
				CoinItem.IconTag = "coin";
				ExchangeItem = ProtoRegistry.RegisterItem(6009, "光子证券交易所", "传送带式证券交易所:两侧进料、中间出料。价格随所在星系不同,并定时刷新。", "Icons/ItemRecipe/fractionator", ProtoRegistry.GetGridIndex(4, 10, 3), 20, (EItemType)6, ProtoRegistry.GetDefaultIconDesc(new Color(1f, 0.78f, 0.25f), new Color(0.42f, 0.3f, 0.1f)));
				ExchangeItem.IconTag = "exchange";
				ExchangeRecipe = ProtoRegistry.RegisterRecipe(6010, (ERecipeType)4, 180, ExchangeRecipeInputs, ExchangeRecipeCounts, new int[1] { 6009 }, new int[1] { 1 }, "建造一座光子证券交易所。", UnlockTechId.Value, 0, "光子证券交易所", "");
				ExchangeRecipe.Handcraft = false;
				ExchangeModel = ProtoRegistry.RegisterModel(667, ExchangeItem, "Entities/Prefabs/fractionator", (Material[])null, new int[5] { 53, 11, 12, 1, 40 }, 0);
				ExchangeItem.BuildIndex = 410;
				ExchangeItem.UnlockKey = 0;
				ProtoRegistry.onLoadingFinished += OnLoadingFinished;
			}
			Registered = true;
		}

		private static void OnLoadingFinished()
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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_0123: 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)
			try
			{
				ModelProto val = ExchangeModel ?? ((ProtoSet<ModelProto>)(object)LDB.models).Select(667);
				ModelProto val2 = ((ProtoSet<ModelProto>)(object)LDB.models).Select(119);
				if (val != null && val.prefabDesc != null && val2 != null && val2.prefabDesc != null)
				{
					val.HpMax = val2.HpMax;
					val.prefabDesc.workEnergyPerTick = val2.prefabDesc.workEnergyPerTick;
					val.prefabDesc.idleEnergyPerTick = val2.prefabDesc.idleEnergyPerTick;
					val.prefabDesc.fracFluidInputMax = 0;
					val.prefabDesc.fracProductOutputMax = 0;
					val.prefabDesc.fracFluidOutputMax = 0;
					if (EnableTint != null && EnableTint.Value)
					{
						TintModel(val, new Color(1f, 0.78f, 0.25f));
					}
				}
				TryApplyGoldFractionatorIcon();
				try
				{
					Sprite val3 = LoadEmbeddedSprite("StockExchange.coin.png");
					if ((Object)(object)val3 != (Object)null && CoinItem != null)
					{
						SetItemIconSprite(CoinItem, val3);
						Rect rect = val3.rect;
						string text = ((Rect)(ref rect)).width.ToString();
						rect = val3.rect;
						LogInfo("coin icon replaced: " + text + "x" + ((Rect)(ref rect)).height);
					}
				}
				catch (Exception e)
				{
					LogError("coin icon load failed", e);
				}
				Plugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogInfo((object)"protos ready: energy-coin exchange registered");
				}
			}
			catch (Exception e2)
			{
				LogError("OnLoadingFinished failed", e2);
			}
		}

		private static void TintModel(ModelProto model, Color color)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			PrefabDesc prefabDesc = model.prefabDesc;
			if (prefabDesc == null)
			{
				return;
			}
			if (prefabDesc.lodMaterials != null)
			{
				for (int i = 0; i < prefabDesc.lodMaterials.Length; i++)
				{
					Material[] array = prefabDesc.lodMaterials[i];
					if (array == null)
					{
						continue;
					}
					for (int j = 0; j < array.Length; j++)
					{
						if (j == 0 && !((Object)(object)array[j] == (Object)null))
						{
							Material val = new Material(array[j])
							{
								color = color
							};
							prefabDesc.lodMaterials[i][j] = val;
						}
					}
				}
			}
			if (prefabDesc.materials != null && prefabDesc.materials.Length != 0 && (Object)(object)prefabDesc.materials[0] != (Object)null)
			{
				prefabDesc.materials[0] = new Material(prefabDesc.materials[0])
				{
					color = color
				};
			}
		}

		private static void TryApplyGoldFractionatorIcon()
		{
			//IL_00b1: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_01d0: 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)
			try
			{
				ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2314);
				Sprite val2 = ((val != null) ? val.iconSprite : null);
				if ((Object)(object)val2 == (Object)null)
				{
					LogInfo("[icon] vanilla fractionator sprite missing");
					return;
				}
				Texture2D texture = val2.texture;
				LogInfo(string.Format("[icon] frac sprite tex={0} readable={1} size={2}x{3} rect={4}", ((Object)(object)texture != (Object)null) ? ((Object)texture).name : "null", (Object)(object)texture != (Object)null && ((Texture)texture).isReadable, ((Object)(object)texture != (Object)null) ? ((Texture)texture).width : 0, ((Object)(object)texture != (Object)null) ? ((Texture)texture).height : 0, val2.rect));
				if (!((Object)(object)texture == (Object)null) && ((Texture)texture).isReadable)
				{
					Rect rect = val2.rect;
					int num = (int)((Rect)(ref rect)).width;
					rect = val2.rect;
					int num2 = (int)((Rect)(ref rect)).height;
					rect = val2.rect;
					int num3 = (int)((Rect)(ref rect)).x;
					rect = val2.rect;
					Color[] pixels = texture.GetPixels(num3, (int)((Rect)(ref rect)).y, num, num2);
					for (int i = 0; i < pixels.Length; i++)
					{
						Color val3 = pixels[i];
						float num4 = ((val3.r > val3.g) ? ((val3.r > val3.b) ? val3.r : val3.b) : ((val3.g > val3.b) ? val3.g : val3.b));
						num4 = (val3.r = Math.Min(1f, num4 * 1.12f));
						val3.g = num4 * 0.78f;
						val3.b = num4 * 0.24f;
						pixels[i] = val3;
					}
					Texture2D val4 = new Texture2D(num, num2, (TextureFormat)4, false);
					val4.SetPixels(pixels);
					val4.Apply();
					goldExchangeIconSprite = Sprite.Create(val4, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), 100f);
					if (ExchangeItem != null)
					{
						SetItemIconSprite(ExchangeItem, goldExchangeIconSprite);
					}
					LogInfo("[icon] gold fractionator icon applied: " + num + "x" + num2);
				}
			}
			catch (Exception e)
			{
				LogError("fractionator icon tint failed", e);
			}
		}

		private static void SetItemIconSprite(ItemProto item, Sprite sprite)
		{
			FieldInfo field = typeof(ItemProto).GetField("_iconSprite", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(item, sprite);
			}
		}

		private static Sprite LoadEmbeddedSprite(string resourceName)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//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)
			if ((Object)(object)coinIconSprite != (Object)null)
			{
				return coinIconSprite;
			}
			using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream(resourceName);
			if (stream == null || stream.Length == 0L)
			{
				return null;
			}
			byte[] array = new byte[stream.Length];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				return null;
			}
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			coinIconSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			return coinIconSprite;
		}

		internal static void LogError(string what, Exception e)
		{
			if (errorLogged++ <= 20)
			{
				Plugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogError((object)(what + ": " + e.GetType().Name + ": " + e.Message + "\n" + e.StackTrace));
				}
			}
		}

		internal static void LogInfo(string msg)
		{
			if (VerboseLog != null && VerboseLog.Value)
			{
				Plugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogInfo((object)msg);
				}
			}
		}

		internal static void LogAlways(string msg)
		{
			Plugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogInfo((object)msg);
			}
		}
	}
}