Decompiled source of LwfTaxLedger v1.0.0

BepInEx/plugins/LwfTaxLedger.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BaseSystem;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Buff.Debuffs;
using GameState;
using GameState.StaticStateHolders;
using HarmonyLib;
using Harvestable;
using Harvestable.HarvestableManagerHelper;
using Items;
using Items.Craft;
using Items.Delivery;
using Items.Tag;
using Items.ValueCountSettings;
using Map.MapObjects.PureClass;
using Map.MapObjects.PureClass.FamObjects;
using R3;
using TMPro;
using Tax;
using UI.SelectableWindow.Managers;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Localization.Components;
using UnityEngine.UI;
using Utility.LWFApp;
using Utility.Localization;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace LwfTaxLedger;

[BepInPlugin("kiyonakanata.lwftaxledger", "LWF Tax Ledger", "1.0.0")]
public sealed class TaxLedgerPlugin : BaseUnityPlugin
{
	internal const string PluginGuid = "kiyonakanata.lwftaxledger";

	internal const string PluginName = "LWF Tax Ledger";

	internal const string PluginVersion = "1.0.0";

	internal static ManualLogSource Log;

	private Harmony _harmony;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<int> FontSize;

	internal static ConfigEntry<int> Padding;

	internal static ConfigEntry<int> IconSize;

	internal static ConfigEntry<int> RowSpacing;

	internal static ConfigEntry<int> ColumnSpacing;

	internal static ConfigEntry<int> Indent;

	internal static ConfigEntry<int> MarkerWidth;

	internal static ConfigEntry<bool> ExpandBreakdown;

	internal static ConfigEntry<int> ValueWidth;

	internal static ConfigEntry<int> ResourceWidth;

	internal static ConfigEntry<int> ScrollStep;

	internal static ConfigEntry<int> NameShrink;

	internal static ConfigEntry<int> BackgroundDarken;

	internal static ConfigEntry<int> ScrollbarWidth;

	internal static ConfigEntry<int> ResourceColumns;

	internal static ConfigEntry<int> NumberGap;

	internal static ConfigEntry<int> SubStep;

	internal static ConfigEntry<bool> DevMode;

	internal static ConfigEntry<string> PreviewKey;

	internal static ConfigEntry<string> DumpKey;

	internal static ConfigEntry<string> DevTaxes;

	private Key _previewKeyCode;

	private Key _dumpKeyCode;

	private int _dummySet;

	private float _nextResultPoll;

	private void Awake()
	{
		//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0305: Unknown result type (might be due to invalid IL or missing references)
		//IL_030a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0315: Unknown result type (might be due to invalid IL or missing references)
		//IL_031f: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enabled", true, "");
		FontSize = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Font size", 24, "");
		Padding = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Padding", 12, "");
		IconSize = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Icon size", 28, "");
		RowSpacing = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Row spacing", 2, "");
		ColumnSpacing = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Column spacing", 6, "");
		Indent = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Item indent", 20, "");
		MarkerWidth = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Marker width", 20, "");
		ExpandBreakdown = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Expand breakdown", false, "");
		ValueWidth = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Value width", 88, "");
		ResourceWidth = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Resource width", 76, "");
		ScrollStep = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Scroll step", 30, "");
		NameShrink = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Name shrink", 8, "");
		BackgroundDarken = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Background brightness (%)", 25, "");
		ScrollbarWidth = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Scrollbar width", 20, "");
		ResourceColumns = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Resource columns", 2, "");
		NumberGap = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Resource number gap", 8, "");
		SubStep = ((BaseUnityPlugin)this).Config.Bind<int>("2. Layout", "Breakdown size step", 4, "");
		DevMode = ((BaseUnityPlugin)this).Config.Bind<bool>("9. Dev", "Enabled", false, "");
		PreviewKey = ((BaseUnityPlugin)this).Config.Bind<string>("9. Dev", "Preview key", "F7", "");
		DumpKey = ((BaseUnityPlugin)this).Config.Bind<string>("9. Dev", "Dump key", "F5", "");
		DevTaxes = ((BaseUnityPlugin)this).Config.Bind<string>("9. Dev", "Taxes", "", "LongerCraft, SampleProvision, SlowConveyor, HarvestRockPenalty, HarvestTreePenalty, ReduceTagCraftResult, ReduceItemCraftResult, CutLocalTag, CutBuffCash, Centralization, FamCountPenalty, LandCountPenalty, LockRandomPatron, NoTagRandomPatron, OrderExecutePenalty");
		_previewKeyCode = ParseKey(PreviewKey.Value, (Key)100);
		_dumpKeyCode = ParseKey(DumpKey.Value, (Key)98);
		_harmony = new Harmony("kiyonakanata.lwftaxledger");
		TaxHooks.Init(_harmony);
		DevTax.Init();
		_harmony.PatchAll(typeof(TaxLedgerPlugin).Assembly);
		int num = 0;
		foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
		{
			_ = patchedMethod;
			num++;
		}
		Log.LogInfo((object)("[boot] LWF Tax Ledger 1.0.0 patches=" + num));
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	private void Update()
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		if (!Enabled.Value)
		{
			return;
		}
		if (Time.unscaledTime >= _nextResultPoll)
		{
			_nextResultPoll = Time.unscaledTime + 0.5f;
			LedgerView.TrackResult();
		}
		if (!DevMode.Value)
		{
			return;
		}
		Keyboard current = Keyboard.current;
		if (current == null)
		{
			return;
		}
		if (((ButtonControl)current[_dumpKeyCode]).wasPressedThisFrame && (((ButtonControl)current.leftShiftKey).isPressed || ((ButtonControl)current.rightShiftKey).isPressed))
		{
			EndRunNow();
			return;
		}
		if (((ButtonControl)current[_dumpKeyCode]).wasPressedThisFrame)
		{
			Ledger.Dump();
			TaxHooks.LogCheck();
			LedgerFile.Save();
		}
		if (((ButtonControl)current[_previewKeyCode]).wasPressedThisFrame)
		{
			if (((ButtonControl)current.leftAltKey).isPressed || ((ButtonControl)current.rightAltKey).isPressed)
			{
				DevTax.Toggle();
				return;
			}
			if (((ButtonControl)current.leftShiftKey).isPressed || ((ButtonControl)current.rightShiftKey).isPressed)
			{
				Ledger.DummyPayTag = LedgerView.PayTag();
				Ledger.FillDummy(_dummySet);
				Log.LogInfo((object)("[dev] dummy set " + (_dummySet % Ledger.DummySetCount + 1) + "/" + Ledger.DummySetCount));
				_dummySet++;
			}
			else
			{
				Ledger.DropDummy();
				if (Ledger.Entries.Count == 0)
				{
					LedgerFile.Load();
				}
				Log.LogInfo((object)("[dev] preview: entries=" + Ledger.Entries.Count));
			}
			if (LedgerView.IsResultWindowUp())
			{
				LedgerView.Reattach();
			}
			else
			{
				LedgerView.ShowOrRefreshPreview();
			}
		}
		if (LedgerView.IsPreviewShown && ((ButtonControl)current[(Key)60]).wasPressedThisFrame)
		{
			LedgerView.TogglePreview();
		}
	}

	private void OnGUI()
	{
		if (DevMode.Value)
		{
			DevTax.Draw();
		}
	}

	private static void EndRunNow()
	{
		GameStateManager instance = GameStateManager.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			Log.LogWarning((object)"[dev] not in a shift");
			return;
		}
		bool flag = instance.DebugLose();
		Log.LogInfo((object)(flag ? "[dev] ending the shift now" : "[dev] the shift cannot be ended yet"));
	}

	internal static void Trace(string line)
	{
		if (DevMode != null && DevMode.Value)
		{
			Log.LogInfo((object)line);
		}
	}

	private static Key ParseKey(string name, Key fallback)
	{
		//IL_0011: 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_001a: 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_001e: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return (Key)Enum.Parse(typeof(Key), name, ignoreCase: true);
		}
		catch (Exception)
		{
			return fallback;
		}
	}
}
internal sealed class ItemLoss
{
	public string ItemID;

	public int Count;

	public readonly Dictionary<string, int> Resources = new Dictionary<string, int>();

	public void Add(int count, string tag1, int c1, string tag2, int c2, string tag3, int c3)
	{
		Count += count;
		AddTag(tag1, c1 * count);
		AddTag(tag2, c2 * count);
		AddTag(tag3, c3 * count);
	}

	public void AddTag(string tag, int amount)
	{
		if (!string.IsNullOrEmpty(tag) && !(tag == "None") && amount != 0)
		{
			Resources.TryGetValue(tag, out var value);
			Resources[tag] = value + amount;
		}
	}
}
internal sealed class TaxEntry
{
	public string EffectID;

	public int Slot;

	public int Points;

	public readonly Dictionary<string, int> LostResources = new Dictionary<string, int>();

	public int CancelledSales;

	public int PatronID = -1;

	public readonly Dictionary<string, ItemLoss> Items = new Dictionary<string, ItemLoss>();

	public int ExtraHits;

	public string RateText;

	public float ActiveSeconds;

	public bool IsEmpty
	{
		get
		{
			if (Points == 0 && LostResources.Count == 0 && CancelledSales == 0 && Items.Count == 0 && ExtraHits == 0)
			{
				return string.IsNullOrEmpty(RateText);
			}
			return false;
		}
	}

	public ItemLoss GetItem(string itemID)
	{
		if (!Items.TryGetValue(itemID, out var value))
		{
			value = new ItemLoss();
			value.ItemID = itemID;
			Items[itemID] = value;
		}
		return value;
	}

	public void AddLostResource(string tag, int amount)
	{
		if (!string.IsNullOrEmpty(tag) && !(tag == "None") && amount != 0)
		{
			LostResources.TryGetValue(tag, out var value);
			LostResources[tag] = value + amount;
		}
	}
}
internal static class Ledger
{
	public static readonly List<TaxEntry> Entries = new List<TaxEntry>();

	public static bool IsDummy;

	public static string DummyPayTag = "Cash";

	private static readonly string[][] DummySets = new string[5][]
	{
		new string[3] { "LongerCraft", "ReduceItemCraftResult", "SlowConveyor" },
		new string[3] { "LandCountPenalty", "CutBuffCash", "HarvestRockPenalty" },
		new string[3] { "OrderExecutePenalty", "Centralization", "LockRandomPatron" },
		new string[3] { "CutLocalTag", "SampleProvision", "HarvestTreePenalty" },
		new string[3] { "NoTagRandomPatron", "ReduceTagCraftResult", "FamCountPenalty" }
	};

	public static int DummySetCount => DummySets.Length;

	public static void Reset()
	{
		Entries.Clear();
		IsDummy = false;
	}

	public static void DropDummy()
	{
		if (IsDummy)
		{
			Reset();
			TaxLedgerPlugin.Trace("[ledger] dropped the dummy; recording the real shift");
		}
	}

	public static TaxEntry Get(string effectID, int slot)
	{
		for (int i = 0; i < Entries.Count; i++)
		{
			if (Entries[i].Slot == slot && Entries[i].EffectID == effectID)
			{
				return Entries[i];
			}
		}
		TaxEntry taxEntry = new TaxEntry();
		taxEntry.EffectID = effectID;
		taxEntry.Slot = slot;
		Entries.Add(taxEntry);
		Entries.Sort((TaxEntry a, TaxEntry b) => a.Slot.CompareTo(b.Slot));
		return taxEntry;
	}

	public static void Dump()
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("[ledger] entries=").Append(Entries.Count);
		for (int i = 0; i < Entries.Count; i++)
		{
			TaxEntry taxEntry = Entries[i];
			stringBuilder.Append('\n').Append("  slot").Append(taxEntry.Slot)
				.Append(' ')
				.Append(taxEntry.EffectID);
			if (taxEntry.Points != 0)
			{
				stringBuilder.Append(" points=").Append(taxEntry.Points);
			}
			if (taxEntry.CancelledSales != 0)
			{
				stringBuilder.Append(" sales=").Append(taxEntry.CancelledSales);
			}
			if (taxEntry.ExtraHits != 0)
			{
				stringBuilder.Append(" hits=").Append(taxEntry.ExtraHits);
			}
			if (!string.IsNullOrEmpty(taxEntry.RateText))
			{
				stringBuilder.Append(" rate=").Append(taxEntry.RateText);
			}
			if (taxEntry.PatronID > 0)
			{
				stringBuilder.Append(" patron=").Append(taxEntry.PatronID);
			}
			foreach (KeyValuePair<string, int> lostResource in taxEntry.LostResources)
			{
				stringBuilder.Append(' ').Append(lostResource.Key).Append('=')
					.Append(lostResource.Value);
			}
			foreach (KeyValuePair<string, ItemLoss> item in taxEntry.Items)
			{
				stringBuilder.Append('\n').Append("    ").Append(item.Key)
					.Append(" x")
					.Append(item.Value.Count);
				foreach (KeyValuePair<string, int> resource in item.Value.Resources)
				{
					stringBuilder.Append(' ').Append(resource.Key).Append('=')
						.Append(resource.Value);
				}
			}
		}
		TaxLedgerPlugin.Log.LogInfo((object)stringBuilder.ToString());
	}

	public static void FillDummy(int setIndex)
	{
		Reset();
		IsDummy = true;
		string[] array = DummySets[(setIndex % DummySets.Length + DummySets.Length) % DummySets.Length];
		Random rng = new Random(setIndex * 7919 + 17);
		for (int i = 0; i < array.Length; i++)
		{
			TaxEntry taxEntry = Get(array[i], i);
			taxEntry.ActiveSeconds = 600f;
			FillDummyEntry(taxEntry, rng);
		}
	}

	private static void FillDummyEntry(TaxEntry e, Random rng)
	{
		switch (e.EffectID)
		{
		case "FamCountPenalty":
			e.Points = 160 * (40 + rng.Next(60));
			e.AddLostResource(DummyPayTag, e.Points * (1 + rng.Next(6)));
			break;
		case "LandCountPenalty":
			e.Points = 800 * (20 + rng.Next(30));
			e.AddLostResource(DummyPayTag, e.Points * (1 + rng.Next(6)));
			break;
		case "OrderExecutePenalty":
			e.Points = 500 * (8 + rng.Next(30));
			e.AddLostResource(DummyPayTag, e.Points * (1 + rng.Next(4)));
			break;
		case "CutBuffCash":
			e.AddLostResource("Cash", 8000 + rng.Next(90000));
			break;
		case "NoTagRandomPatron":
			e.PatronID = 2;
			e.AddLostResource("Construction", 4000 + rng.Next(60000));
			break;
		case "CutLocalTag":
			e.AddLostResource("Luxury", 2000 + rng.Next(40000));
			break;
		case "Centralization":
			FillDummyItems(e, rng);
			{
				foreach (KeyValuePair<string, ItemLoss> item in e.Items)
				{
					e.CancelledSales += item.Value.Count;
				}
				break;
			}
		case "LockRandomPatron":
			e.PatronID = 8;
			FillDummyItems(e, rng);
			break;
		case "HarvestRockPenalty":
		case "HarvestTreePenalty":
			e.ExtraHits = 3000 + rng.Next(90000);
			break;
		case "SlowConveyor":
			e.RateText = "-90%";
			break;
		default:
			FillDummyItems(e, rng);
			break;
		}
	}

	private static void FillDummyItems(TaxEntry e, Random rng)
	{
		AddDummyItem(e, rng, "Gold", 40, "Luxury", 50, "Cash", 10, "None", 0);
		AddDummyItem(e, rng, "Iron", 200, "Construction", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "Lemonade", 60, "Grocery", 1, "Cash", 5, "None", 0);
		AddDummyItem(e, rng, "Nitro", 30, "Fuel", 100, "Cash", 10, "None", 0);
		AddDummyItem(e, rng, "Soda", 25, "Chemical", 100, "Cash", 10, "None", 0);
		AddDummyItem(e, rng, "Wax", 80, "Chemical", 1, "Grocery", 1, "Fuel", 1);
		AddDummyItem(e, rng, "Mercury", 90, "Magic", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "Lye", 45, "Chemical", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "MagicChunk", 55, "Magic", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "Gunpowder", 35, "Fuel", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "Compost", 120, "Fertilizer", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "GemPowder", 20, "Magic", 20, "Cash", 1, "None", 0);
		AddDummyItem(e, rng, "Pickaxe", 8, "Construction", 100, "Cash", 10, "None", 0);
		AddDummyItem(e, rng, "Adamantite", 6, "Fuel", 2000, "Cash", 500, "None", 0);
		AddDummyItem(e, rng, "Summon-Worker", 12, "None", 0, "None", 0, "None", 0);
	}

	private static void AddDummyItem(TaxEntry e, Random rng, string itemID, int scale, string t1, int c1, string t2, int c2, string t3, int c3)
	{
		int count = scale / 2 + rng.Next(scale * 2);
		e.GetItem(itemID).Add(count, t1, c1, t2, c2, t3, c3);
	}
}
internal static class LedgerView
{
	private const string BodyName = "AchievementBody";

	private const string TitleName = "AchievementTitle";

	private const string PlaceholderName = "TMPTemporary";

	private const string FrameName = "FrameAchievement";

	private const string RowsName = "TaxLedgerRows";

	private const string PreviewName = "TaxLedgerPreview";

	private const string CashTag = "Cash";

	private const string FixedCostTag = "RepaymentLoseCash";

	private const string HitItem = "Pickaxe";

	private const string ConveyorItem = "Summon-Conveyor";

	private const string GehennaSmile = "portrait_patron_gehenna_smile";

	private const string BackdropName = "TaxLedgerBackdrop";

	private static string _payTag = "Cash";

	private static readonly string[] ResourceOrder = new string[7] { "Construction", "Grocery", "Luxury", "Fertilizer", "Chemical", "Magic", "Fuel" };

	private static readonly Color NameColor = LWFColors.HEADER_COLOR;

	private static readonly Color SectionColor = Fade(LWFColors.HEADER_COLOR, 0.72f);

	private static readonly Color ValueColor = Fade(LWFColors.RED_COLOR, 0.85f);

	private static readonly Color SubColor = Fade(LWFColors.HEADER_COLOR, 0.7f);

	private static readonly Color SubValueColor = Fade(LWFColors.HEADER_COLOR, 0.92f);

	private static GameObject _preview;

	private static bool _attached;

	private static TextMeshProUGUI _template;

	private static ResultUIManager _result;

	private static CanvasGroup[] _dimmed;

	private static readonly Dictionary<string, Sprite> SpriteCache = new Dictionary<string, Sprite>();

	public static bool IsPreviewShown => (Object)(object)_preview != (Object)null;

	private static Color Fade(Color c, float alpha)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		return new Color(c.r, c.g, c.b, alpha);
	}

	public static bool IsResultWindowUp()
	{
		ResultUIManager val = Result();
		if ((Object)(object)val != (Object)null)
		{
			return ((Component)val).gameObject.activeInHierarchy;
		}
		return false;
	}

	private static ResultUIManager Result()
	{
		if ((Object)(object)_result != (Object)null)
		{
			return _result;
		}
		try
		{
			ResultUIManager[] array = Object.FindObjectsByType<ResultUIManager>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			_result = ((array.Length > 0) ? array[0] : null);
		}
		catch (Exception)
		{
			_result = null;
		}
		return _result;
	}

	public static void Reattach()
	{
		_attached = false;
		_dimmed = null;
		TrackResult();
	}

	public static void TrackResult()
	{
		if (!IsResultWindowUp())
		{
			_attached = false;
			_dimmed = null;
			return;
		}
		if (_attached)
		{
			Undim();
			return;
		}
		if (!IsTaxRun() && !TaxLedgerPlugin.DevMode.Value)
		{
			_attached = true;
			return;
		}
		Transform val = FindResultBody();
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		_attached = true;
		if (Ledger.Entries.Count == 0)
		{
			TaxLedgerPlugin.Trace("[view] nothing to show; left the frame untouched");
			return;
		}
		try
		{
			Build(val, isPreview: false);
			_dimmed = ((Component)val).GetComponentsInChildren<CanvasGroup>(true);
			Undim();
			TaxLedgerPlugin.Trace("[view] attached to the result frame (" + _dimmed.Length + " canvas groups)");
			if (TaxLedgerPlugin.DevMode.Value)
			{
				LedgerFile.Save();
			}
		}
		catch (Exception ex)
		{
			TaxLedgerPlugin.Log.LogWarning((object)("[view] cannot build the result frame: " + ex.Message));
		}
	}

	private static bool IsTaxRun()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return TaxUnlockPolicy.CanApplyRuntimeEffects(CurrentGameMode.Get);
		}
		catch (Exception)
		{
			return false;
		}
	}

	private static void DarkenFrame(Transform frame)
	{
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Expected O, but got Unknown
		//IL_00cf: 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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: 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)
		if ((Object)(object)frame == (Object)null)
		{
			return;
		}
		Transform val = frame.Find("TaxLedgerBackdrop");
		while ((Object)(object)val != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
			val = frame.Find("TaxLedgerBackdrop");
		}
		float num = 1f - Mathf.Clamp01((float)TaxLedgerPlugin.BackgroundDarken.Value / 100f);
		if (!(num <= 0f))
		{
			Image component = ((Component)frame).GetComponent<Image>();
			if (!((Object)(object)component != (Object)null) || !(((Graphic)component).color.r + ((Graphic)component).color.g + ((Graphic)component).color.b < 0.2f))
			{
				GameObject val2 = new GameObject("TaxLedgerBackdrop", new Type[1] { typeof(RectTransform) });
				RectTransform component2 = val2.GetComponent<RectTransform>();
				((Transform)component2).SetParent(frame, false);
				((Transform)component2).localScale = Vector3.one;
				Stretch(component2);
				Image val3 = val2.AddComponent<Image>();
				((Graphic)val3).color = new Color(0f, 0f, 0f, num);
				((Graphic)val3).raycastTarget = false;
				((Transform)component2).SetSiblingIndex(0);
			}
		}
	}

	private static void Undim()
	{
		if (_dimmed == null)
		{
			return;
		}
		for (int i = 0; i < _dimmed.Length; i++)
		{
			CanvasGroup val = _dimmed[i];
			if (!((Object)(object)val == (Object)null))
			{
				if (val.alpha < 1f)
				{
					val.alpha = 1f;
				}
				if (!val.interactable)
				{
					val.interactable = true;
				}
				if (!val.blocksRaycasts)
				{
					val.blocksRaycasts = true;
				}
			}
		}
	}

	private static Transform FindResultBody()
	{
		ResultUIManager val = Result();
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		return FindChildRecursive(((Component)val).transform, "AchievementBody");
	}

	public static void TogglePreview()
	{
		if ((Object)(object)_preview != (Object)null)
		{
			Object.Destroy((Object)(object)_preview);
			_preview = null;
		}
		else
		{
			ShowPreview();
		}
	}

	public static void ShowOrRefreshPreview()
	{
		if ((Object)(object)_preview != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)_preview);
			_preview = null;
		}
		ShowPreview();
	}

	private static void ShowPreview()
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Expected O, but got Unknown
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected O, but got Unknown
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: 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_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		Transform val = FindResultBody();
		if ((Object)(object)val == (Object)null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[preview] AchievementBody not found (ResultUIManager missing in this scene)");
			return;
		}
		GameObject val2 = GameObject.Find("TaxLedgerPreview");
		if ((Object)(object)val2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)val2);
		}
		_preview = new GameObject("TaxLedgerPreview");
		Canvas val3 = _preview.AddComponent<Canvas>();
		val3.renderMode = (RenderMode)0;
		val3.sortingOrder = 5000;
		CopyScaler(val, _preview.AddComponent<CanvasScaler>());
		_preview.AddComponent<GraphicRaycaster>();
		GameObject val4 = new GameObject("Dim");
		val4.transform.SetParent(_preview.transform, false);
		Image val5 = val4.AddComponent<Image>();
		((Graphic)val5).color = new Color(0f, 0f, 0f, 0.75f);
		Stretch(val4.GetComponent<RectTransform>());
		Transform val6 = FindChildRecursive(val.parent, "AchievementTitle");
		RectTransform val7 = (RectTransform)(object)((val is RectTransform) ? val : null);
		? val8;
		if (!((Object)(object)val7 != (Object)null))
		{
			val8 = new Vector2(600f, 420f);
		}
		else
		{
			Rect rect = val7.rect;
			val8 = ((Rect)(ref rect)).size;
		}
		Vector2 size = (Vector2)val8;
		float num = 0f;
		if ((Object)(object)val6 != (Object)null)
		{
			GameObject go = CloneInto(val6, _preview.transform, "Title");
			Rect rect2 = ((RectTransform)((val6 is RectTransform) ? val6 : null)).rect;
			RectTransform val9 = Center(go, ((Rect)(ref rect2)).size);
			Rect rect3 = val9.rect;
			num = ((Rect)(ref rect3)).height;
			val9.anchoredPosition = new Vector2(0f, size.y * 0.5f + num * 0.5f);
			SetTitleText(val9);
		}
		RectTransform val10 = Center(CloneInto(val, _preview.transform, "Body"), size);
		val10.anchoredPosition = new Vector2(0f, (0f - num) * 0.5f);
		CanvasGroup[] componentsInChildren = ((Component)val10).GetComponentsInChildren<CanvasGroup>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			componentsInChildren[i].alpha = 1f;
			componentsInChildren[i].interactable = true;
			componentsInChildren[i].blocksRaycasts = true;
		}
		Build((Transform)(object)val10, isPreview: true);
		TaxLedgerPlugin.Trace("[preview] shown (" + size.x + "x" + size.y + ")");
	}

	private static void CopyScaler(Transform body, CanvasScaler mine)
	{
		//IL_003a: 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_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		CanvasScaler componentInParent = ((Component)body).GetComponentInParent<CanvasScaler>();
		if ((Object)(object)componentInParent == (Object)null)
		{
			mine.uiScaleMode = (ScaleMode)1;
			mine.referenceResolution = new Vector2(1920f, 1080f);
			mine.matchWidthOrHeight = 1f;
		}
		else
		{
			mine.uiScaleMode = componentInParent.uiScaleMode;
			mine.referenceResolution = componentInParent.referenceResolution;
			mine.screenMatchMode = componentInParent.screenMatchMode;
			mine.matchWidthOrHeight = componentInParent.matchWidthOrHeight;
			mine.referencePixelsPerUnit = componentInParent.referencePixelsPerUnit;
		}
	}

	private static GameObject CloneInto(Transform source, Transform parent, string name)
	{
		GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject, parent, false);
		((Object)val).name = name;
		val.SetActive(true);
		DisableLocalizers(val);
		return val;
	}

	private static RectTransform Center(GameObject go, Vector2 size)
	{
		//IL_0022: 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_004c: 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_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = go.GetComponent<RectTransform>();
		if ((Object)(object)val == (Object)null)
		{
			val = go.AddComponent<RectTransform>();
		}
		val.anchorMin = new Vector2(0.5f, 0.5f);
		val.anchorMax = new Vector2(0.5f, 0.5f);
		val.pivot = new Vector2(0.5f, 0.5f);
		val.sizeDelta = size;
		val.anchoredPosition = Vector2.zero;
		((Transform)val).localScale = Vector3.one;
		return val;
	}

	private static void Stretch(RectTransform r)
	{
		//IL_0001: 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_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		r.anchorMin = Vector2.zero;
		r.anchorMax = Vector2.one;
		r.offsetMin = Vector2.zero;
		r.offsetMax = Vector2.zero;
	}

	private static void Build(Transform body, bool isPreview)
	{
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Expected O, but got Unknown
		//IL_01bf: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: 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_0277: Expected O, but got Unknown
		//IL_03c1: 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_03ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
		Transform val = FindChildRecursive(body, "TMPTemporary");
		_template = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TextMeshProUGUI>() : null);
		if ((Object)(object)_template == (Object)null)
		{
			_template = ((Component)body).GetComponentInChildren<TextMeshProUGUI>(true);
			TaxLedgerPlugin.Log.LogWarning((object)("[view] TMPTemporary not found; using " + (((Object)(object)_template != (Object)null) ? ((Object)_template).name : "nothing") + " as the text template"));
		}
		if ((Object)(object)_template == (Object)null)
		{
			throw new InvalidOperationException("no TextMeshProUGUI under AchievementBody");
		}
		_payTag = CurrentPayTag();
		TaxLedgerPlugin.Trace("[view] pay tag = " + _payTag);
		Transform val2 = FindChildRecursive(body, "FrameAchievement");
		ScrollRect componentInChildren = ((Component)(((Object)(object)val2 != (Object)null) ? val2 : body)).GetComponentInChildren<ScrollRect>(true);
		if (!isPreview)
		{
			Transform val3 = FindChildRecursive(body.parent, "AchievementTitle");
			if ((Object)(object)val3 != (Object)null)
			{
				SetTitleText((RectTransform)(object)((val3 is RectTransform) ? val3 : null));
			}
		}
		if ((Object)(object)val2 != (Object)null)
		{
			((Component)val2).gameObject.SetActive(true);
		}
		if ((Object)(object)componentInChildren != (Object)null)
		{
			((Component)componentInChildren).gameObject.SetActive(true);
		}
		HideOthers(body, val2);
		RectTransform val4 = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.viewport : null);
		if ((Object)(object)val4 == (Object)null)
		{
			val4 = (RectTransform)(object)((body is RectTransform) ? body : null);
		}
		Transform val5 = ((Transform)val4).Find("TaxLedgerRows");
		while ((Object)(object)val5 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)((Component)val5).gameObject);
			val5 = ((Transform)val4).Find("TaxLedgerRows");
		}
		GameObject val6 = new GameObject("TaxLedgerRows", new Type[1] { typeof(RectTransform) });
		RectTransform component = val6.GetComponent<RectTransform>();
		((Transform)component).SetParent((Transform)(object)val4, false);
		component.anchorMin = new Vector2(0f, 1f);
		component.anchorMax = new Vector2(1f, 1f);
		component.pivot = new Vector2(0f, 1f);
		component.anchoredPosition = Vector2.zero;
		component.offsetMin = new Vector2(0f, component.offsetMin.y);
		component.offsetMax = new Vector2(0f, component.offsetMax.y);
		((Transform)component).localScale = Vector3.one;
		VerticalLayoutGroup val7 = val6.AddComponent<VerticalLayoutGroup>();
		int value = TaxLedgerPlugin.Padding.Value;
		((LayoutGroup)val7).padding = new RectOffset(value, value + BarWidth(componentInChildren), value, value);
		((HorizontalOrVerticalLayoutGroup)val7).spacing = TaxLedgerPlugin.RowSpacing.Value;
		((HorizontalOrVerticalLayoutGroup)val7).childForceExpandHeight = false;
		((HorizontalOrVerticalLayoutGroup)val7).childForceExpandWidth = true;
		((HorizontalOrVerticalLayoutGroup)val7).childControlHeight = true;
		((HorizontalOrVerticalLayoutGroup)val7).childControlWidth = true;
		((LayoutGroup)val7).childAlignment = (TextAnchor)0;
		ContentSizeFitter val8 = val6.AddComponent<ContentSizeFitter>();
		val8.verticalFit = (FitMode)2;
		val8.horizontalFit = (FitMode)0;
		BuildRows(component);
		DarkenFrame(val2);
		DarkenFrame((Transform)(object)val4);
		if ((Object)(object)componentInChildren != (Object)null)
		{
			RectTransform content = componentInChildren.content;
			if ((Object)(object)content != (Object)null && (Object)(object)content != (Object)(object)component)
			{
				((Component)content).gameObject.SetActive(false);
			}
			componentInChildren.content = component;
			componentInChildren.horizontal = false;
			componentInChildren.vertical = true;
			componentInChildren.movementType = (MovementType)2;
			componentInChildren.inertia = false;
			componentInChildren.elasticity = 0f;
			componentInChildren.scrollSensitivity = TaxLedgerPlugin.ScrollStep.Value;
			componentInChildren.verticalScrollbarVisibility = (ScrollbarVisibility)1;
			componentInChildren.verticalNormalizedPosition = 1f;
		}
		object[] array = new object[14]
		{
			"[view] template=",
			((Object)_template).name,
			" size=",
			((TMP_Text)_template).fontSize,
			" holder=",
			((Object)val4).name,
			" (",
			null,
			null,
			null,
			null,
			null,
			null,
			null
		};
		Rect rect = val4.rect;
		array[7] = ((Rect)(ref rect)).width.ToString("0");
		array[8] = "x";
		Rect rect2 = val4.rect;
		array[9] = ((Rect)(ref rect2)).height.ToString("0");
		array[10] = ") bar=";
		array[11] = BarWidth(componentInChildren);
		array[12] = " entries=";
		array[13] = Ledger.Entries.Count;
		TaxLedgerPlugin.Trace(string.Concat(array));
	}

	private static void HideOthers(Transform parent, Transform keep)
	{
		for (int i = 0; i < parent.childCount; i++)
		{
			Transform child = parent.GetChild(i);
			if (!((Object)(object)child == (Object)(object)keep) && !(((Object)child).name == "TaxLedgerRows") && ((Component)child).gameObject.activeSelf)
			{
				((Component)child).gameObject.SetActive(false);
				TaxLedgerPlugin.Trace("[view] hid " + ((Object)parent).name + "/" + ((Object)child).name);
			}
		}
	}

	private static void BuildRows(RectTransform rows)
	{
		//IL_004f: 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_0182: Unknown result type (might be due to invalid IL or missing references)
		List<TaxEntry> entries = Ledger.Entries;
		for (int i = 0; i < entries.Count; i++)
		{
			TaxEntry taxEntry = entries[i];
			if (i > 0)
			{
				AddSeparator(rows);
			}
			RectTransform val = NewRow(rows, 0, TaxLedgerPlugin.IconSize.Value);
			TextMeshProUGUI marker = AddMarker(val);
			AddFixedText(val, SectionName(taxEntry.Slot), TaxLedgerPlugin.FontSize.Value, SectionColor);
			AddName(val, TaxName(taxEntry.EffectID), TaxLedgerPlugin.FontSize.Value);
			if (taxEntry.PatronID > 0)
			{
				AddIcon(val, PatronSprite(taxEntry.PatronID), null, TaxLedgerPlugin.IconSize.Value, TaxLedgerPlugin.FontSize.Value);
			}
			AddHeadValue(val, taxEntry);
			int font = SubFontSize();
			int num = SubIconSize();
			List<GameObject> list = new List<GameObject>();
			foreach (KeyValuePair<string, ItemLoss> item in taxEntry.Items)
			{
				ItemLoss value = item.Value;
				RectTransform val2 = NewRow(rows, TaxLedgerPlugin.Indent.Value, num);
				AddIcon(val2, ItemSprite(value.ItemID), value.ItemID, num, font);
				AddFixedText(val2, "x" + Format(value.Count), font, SubValueColor);
				AddFlex(val2);
				AddOtherResources(val2, value.Resources, font, num);
				AddValue(val2, TagSprite(_payTag), _payTag, "-" + Format(Pay(value.Resources)), font, num, SubValueColor);
				list.Add(((Component)val2).gameObject);
			}
			MakeExpandable(val, marker, list);
		}
	}

	private static TextMeshProUGUI AddMarker(RectTransform row)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = NewText(row, " ", TaxLedgerPlugin.FontSize.Value, SectionColor, bold: false);
		((Object)val).name = "Marker";
		TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).alignment = (TextAlignmentOptions)4098;
		LayoutElement val2 = val.AddComponent<LayoutElement>();
		int value = TaxLedgerPlugin.MarkerWidth.Value;
		val2.preferredWidth = value;
		val2.minWidth = value;
		return component;
	}

	private static void MakeExpandable(RectTransform head, TextMeshProUGUI marker, List<GameObject> rows)
	{
		//IL_006f: 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_00c2: Expected O, but got Unknown
		if (rows.Count == 0)
		{
			return;
		}
		bool value = TaxLedgerPlugin.ExpandBreakdown.Value;
		for (int i = 0; i < rows.Count; i++)
		{
			rows[i].SetActive(value);
		}
		((TMP_Text)marker).text = (value ? "-" : "+");
		Image val = ((Component)head).gameObject.AddComponent<Image>();
		((Graphic)val).color = new Color(1f, 1f, 1f, 0f);
		((Graphic)val).raycastTarget = true;
		Button val2 = ((Component)head).gameObject.AddComponent<Button>();
		((Selectable)val2).transition = (Transition)0;
		((Selectable)val2).targetGraphic = (Graphic)(object)val;
		List<GameObject> captured = rows;
		TextMeshProUGUI capturedMarker = marker;
		((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
		{
			bool flag = captured.Count > 0 && !captured[0].activeSelf;
			for (int j = 0; j < captured.Count; j++)
			{
				captured[j].SetActive(flag);
			}
			((TMP_Text)capturedMarker).text = (flag ? "-" : "+");
		});
	}

	private static void AddHeadValue(RectTransform row, TaxEntry e)
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		int value = TaxLedgerPlugin.FontSize.Value;
		int value2 = TaxLedgerPlugin.IconSize.Value;
		int childCount = ((Transform)row).childCount;
		if (e.Points != 0)
		{
			AddValue(row, TagSprite("RepaymentLoseCash"), "RepaymentLoseCash", "+" + Format(e.Points), value, value2, SubValueColor);
		}
		foreach (KeyValuePair<string, int> lostResource in e.LostResources)
		{
			AddValue(row, TagSprite(lostResource.Key), lostResource.Key, "-" + Format(lostResource.Value), value, value2, ValueColor);
		}
		if (e.CancelledSales != 0)
		{
			AddValue(row, SpriteByName("portrait_patron_gehenna_smile"), null, "x" + Format(e.CancelledSales), value, value2, ValueColor);
		}
		if (e.ExtraHits != 0)
		{
			AddShrinkingLabel(row, Message("RequireMiningHit"), value);
			AddValue(row, ItemSprite("Pickaxe"), null, "+" + Format(e.ExtraHits), value, value2, ValueColor);
		}
		if (!string.IsNullOrEmpty(e.RateText))
		{
			Sprite sprite = ((e.EffectID == "SlowConveyor") ? ItemSprite("Summon-Conveyor") : null);
			AddValue(row, sprite, null, e.RateText, value, value2, ValueColor);
		}
		if (e.Items.Count > 0)
		{
			AddValue(row, TagSprite(_payTag), _payTag, "-" + Format(TotalPay(e)), value, value2, ValueColor);
		}
		if (((Transform)row).childCount == childCount)
		{
			AddValue(row, null, null, "-", value, value2, SubColor);
		}
	}

	private static int TotalPay(TaxEntry e)
	{
		int num = 0;
		foreach (KeyValuePair<string, ItemLoss> item in e.Items)
		{
			num += Pay(item.Value.Resources);
		}
		return num;
	}

	internal static string PayTag()
	{
		return CurrentPayTag();
	}

	private static string CurrentPayTag()
	{
		try
		{
			GameStateManager instance = GameStateManager.Instance;
			WinCondition val = (((Object)(object)instance != (Object)null) ? instance.GetWinCondition() : null);
			string text = ((val != null) ? val.GetTargetTag() : null);
			if (string.IsNullOrEmpty(text) || text == "None")
			{
				return "Cash";
			}
			return text;
		}
		catch (Exception)
		{
			return "Cash";
		}
	}

	private static int Pay(Dictionary<string, int> res)
	{
		res.TryGetValue(_payTag, out var value);
		return value;
	}

	private static void AddOtherResources(RectTransform row, Dictionary<string, int> res, int font, int icon)
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		int value = TaxLedgerPlugin.ResourceColumns.Value;
		int num = 0;
		for (int i = 0; i < ResourceOrder.Length; i++)
		{
			if (num >= value)
			{
				break;
			}
			string text = ResourceOrder[i];
			if (!(text == _payTag) && res.TryGetValue(text, out var value2) && value2 != 0)
			{
				AddIcon(row, TagSprite(text), text, icon, font);
				AddNumber(row, "-" + Format(value2), font, SubValueColor, TaxLedgerPlugin.ResourceWidth.Value, TaxLedgerPlugin.NumberGap.Value);
				num++;
			}
		}
		int num2 = value - num;
		int width = icon + TaxLedgerPlugin.ColumnSpacing.Value + TaxLedgerPlugin.ResourceWidth.Value + TaxLedgerPlugin.NumberGap.Value;
		for (int j = 0; j < num2; j++)
		{
			AddGap(row, width);
		}
	}

	private static Sprite SpriteByName(string name)
	{
		if (SpriteCache.TryGetValue(name, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		try
		{
			Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null && ((Object)array[i]).name == name)
				{
					SpriteCache[name] = array[i];
					return array[i];
				}
			}
		}
		catch (Exception)
		{
		}
		TaxLedgerPlugin.Log.LogWarning((object)("[view] sprite not loaded: " + name));
		return null;
	}

	private static Sprite PatronSprite(int patronID)
	{
		try
		{
			return Patrons.GetFaceIcon((Patron)patronID);
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static int SubFontSize()
	{
		return Mathf.Max(8, TaxLedgerPlugin.FontSize.Value - TaxLedgerPlugin.SubStep.Value);
	}

	private static int SubIconSize()
	{
		return Mathf.Max(8, TaxLedgerPlugin.IconSize.Value - TaxLedgerPlugin.SubStep.Value);
	}

	private static string Format(int value)
	{
		int num = ((value < 0) ? (-value) : value);
		string text = ((value < 0) ? "-" : "");
		if (num < 10000)
		{
			return value.ToString("N0");
		}
		if (num < 1000000)
		{
			return text + ((float)num / 1000f).ToString("0.#") + "K";
		}
		return text + ((float)num / 1000000f).ToString("0.##") + "M";
	}

	private static void AddValue(RectTransform row, Sprite sprite, string fallbackID, string value, int font, int icon, Color color)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)sprite != (Object)null)
		{
			AddIcon(row, sprite, fallbackID, icon, font);
		}
		else if (fallbackID != null)
		{
			AddLabel(row, Name(fallbackID), font);
			AddGap(row, icon);
		}
		else
		{
			AddGap(row, icon);
		}
		AddNumber(row, value, font, color);
	}

	private static void AddName(RectTransform row, string value, int font)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = NewText(row, value, font, NameColor, bold: true);
		TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
		int num = Mathf.Max(10, font - TaxLedgerPlugin.NameShrink.Value);
		((TMP_Text)component).enableAutoSizing = true;
		((TMP_Text)component).fontSizeMax = font;
		((TMP_Text)component).fontSizeMin = num;
		((TMP_Text)component).overflowMode = (TextOverflowModes)1;
		float x = ((TMP_Text)component).GetPreferredValues(value).x;
		LayoutElement val2 = val.AddComponent<LayoutElement>();
		val2.flexibleWidth = 1f;
		val2.preferredWidth = x;
		val2.minWidth = x * (float)num / (float)Mathf.Max(1, font);
	}

	private static void AddShrinkingLabel(RectTransform row, string value, int font)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		if (!string.IsNullOrEmpty(value))
		{
			GameObject val = NewText(row, value, font, SubColor, bold: false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			float x = ((TMP_Text)component).GetPreferredValues(value).x;
			((TMP_Text)component).enableAutoSizing = true;
			((TMP_Text)component).fontSizeMax = font;
			((TMP_Text)component).fontSizeMin = Mathf.Max(9, font - TaxLedgerPlugin.NameShrink.Value * 2);
			((TMP_Text)component).overflowMode = (TextOverflowModes)1;
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			val2.preferredWidth = x;
			val2.minWidth = 0f;
			val2.flexibleWidth = 0f;
		}
	}

	private static void AddLabel(RectTransform row, string value, int font)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		AddFixedText(row, value, font, SubColor);
	}

	private static void AddFixedText(RectTransform row, string value, int font, Color color)
	{
		//IL_000c: 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)
		if (!string.IsNullOrEmpty(value))
		{
			GameObject val = NewText(row, value, font, color, bold: false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			float x = ((TMP_Text)component).GetPreferredValues(value).x;
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			val2.minWidth = x;
			val2.preferredWidth = x;
		}
	}

	private static void AddNumber(RectTransform row, string value, int font, Color color)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		AddNumber(row, value, font, color, TaxLedgerPlugin.ValueWidth.Value);
	}

	private static void AddNumber(RectTransform row, string value, int font, Color color, int width)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		AddNumber(row, value, font, color, width, 0);
	}

	private static void AddNumber(RectTransform row, string value, int font, Color color, int width, int rightGap)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = NewText(row, value, font, color, bold: false);
		TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).alignment = (TextAlignmentOptions)4100;
		((TMP_Text)component).margin = new Vector4(0f, 0f, (float)rightGap, 0f);
		LayoutElement val2 = val.AddComponent<LayoutElement>();
		val2.preferredWidth = width + rightGap;
		val2.minWidth = width + rightGap;
	}

	private static void AddGap(RectTransform row, int width)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		GameObject val = new GameObject("Gap", new Type[1] { typeof(RectTransform) });
		((Transform)val.GetComponent<RectTransform>()).SetParent((Transform)(object)row, false);
		LayoutElement val2 = val.AddComponent<LayoutElement>();
		val2.preferredWidth = width;
		val2.minWidth = width;
	}

	private static void AddSeparator(RectTransform rows)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("Separator", new Type[1] { typeof(RectTransform) });
		((Transform)val.GetComponent<RectTransform>()).SetParent((Transform)(object)rows, false);
		Image val2 = val.AddComponent<Image>();
		Color hEADER_COLOR = LWFColors.HEADER_COLOR;
		hEADER_COLOR.a = 0.14f;
		((Graphic)val2).color = hEADER_COLOR;
		((Graphic)val2).raycastTarget = false;
		LayoutElement val3 = val.AddComponent<LayoutElement>();
		val3.preferredHeight = 1f;
		val3.minHeight = 1f;
	}

	private static RectTransform NewRow(RectTransform parent, int indent, int height)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		//IL_0033: 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)
		//IL_0087: Expected O, but got Unknown
		GameObject val = new GameObject("Row", new Type[1] { typeof(RectTransform) });
		RectTransform component = val.GetComponent<RectTransform>();
		((Transform)component).SetParent((Transform)(object)parent, false);
		((Transform)component).localScale = Vector3.one;
		HorizontalLayoutGroup val2 = val.AddComponent<HorizontalLayoutGroup>();
		((HorizontalOrVerticalLayoutGroup)val2).spacing = TaxLedgerPlugin.ColumnSpacing.Value;
		((HorizontalOrVerticalLayoutGroup)val2).childForceExpandWidth = false;
		((HorizontalOrVerticalLayoutGroup)val2).childForceExpandHeight = false;
		((HorizontalOrVerticalLayoutGroup)val2).childControlWidth = true;
		((HorizontalOrVerticalLayoutGroup)val2).childControlHeight = true;
		((LayoutGroup)val2).childAlignment = (TextAnchor)3;
		((LayoutGroup)val2).padding = new RectOffset(indent, 0, 0, 0);
		LayoutElement val3 = val.AddComponent<LayoutElement>();
		val3.minHeight = height;
		return component;
	}

	private static void AddText(RectTransform row, string value, int font, Color color, bool bold)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		NewText(row, value, font, color, bold);
	}

	private static GameObject NewText(RectTransform row, string value, int font, Color color, bool bold)
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(((Component)_template).gameObject, (Transform)(object)row, false);
		((Object)val).name = "Text";
		val.SetActive(true);
		DisableLocalizers(val);
		StripLayout(val);
		TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).text = value;
		((Graphic)component).color = color;
		((TMP_Text)component).fontSize = font;
		((TMP_Text)component).fontStyle = (FontStyles)(bold ? 1 : 0);
		((TMP_Text)component).alignment = (TextAlignmentOptions)4097;
		((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
		((TMP_Text)component).overflowMode = (TextOverflowModes)0;
		((Graphic)component).raycastTarget = false;
		((TMP_Text)component).margin = Vector4.zero;
		((Transform)val.GetComponent<RectTransform>()).localScale = Vector3.one;
		return val;
	}

	private static void AddIcon(RectTransform row, Sprite sprite, string fallbackID, int size, int font)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)sprite == (Object)null)
		{
			if (fallbackID != null)
			{
				AddText(row, Name(fallbackID), font, NameColor, bold: false);
			}
			return;
		}
		GameObject val = new GameObject("Icon", new Type[1] { typeof(RectTransform) });
		RectTransform component = val.GetComponent<RectTransform>();
		((Transform)component).SetParent((Transform)(object)row, false);
		((Transform)component).localScale = Vector3.one;
		Image val2 = val.AddComponent<Image>();
		val2.sprite = sprite;
		val2.preserveAspect = true;
		((Graphic)val2).raycastTarget = false;
		LayoutElement val3 = val.AddComponent<LayoutElement>();
		val3.preferredWidth = size;
		val3.preferredHeight = size;
		val3.minWidth = size;
	}

	private static void AddFlex(RectTransform row)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		GameObject val = new GameObject("Flex", new Type[1] { typeof(RectTransform) });
		((Transform)val.GetComponent<RectTransform>()).SetParent((Transform)(object)row, false);
		LayoutElement val2 = val.AddComponent<LayoutElement>();
		val2.flexibleWidth = 1f;
		val2.minWidth = TaxLedgerPlugin.ColumnSpacing.Value;
	}

	private static void StripLayout(GameObject go)
	{
		ContentSizeFitter component = go.GetComponent<ContentSizeFitter>();
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		LayoutElement component2 = go.GetComponent<LayoutElement>();
		if ((Object)(object)component2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
		for (int num = go.transform.childCount - 1; num >= 0; num--)
		{
			Object.DestroyImmediate((Object)(object)((Component)go.transform.GetChild(num)).gameObject);
		}
	}

	private static int BarWidth(ScrollRect scroll)
	{
		//IL_0041: 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_0055: Unknown result type (might be due to invalid IL or missing references)
		int value = TaxLedgerPlugin.ScrollbarWidth.Value;
		if ((Object)(object)scroll == (Object)null || (Object)(object)scroll.verticalScrollbar == (Object)null)
		{
			return value;
		}
		Transform transform = ((Component)scroll.verticalScrollbar).transform;
		RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
		if ((Object)(object)val == (Object)null)
		{
			return value;
		}
		Rect rect = val.rect;
		int num = (int)((Rect)(ref rect)).width;
		if (num <= 0)
		{
			num = (int)val.sizeDelta.x;
		}
		if (num <= 0)
		{
			return value;
		}
		return num;
	}

	private static void SetTitleText(RectTransform title)
	{
		if (!((Object)(object)title == (Object)null))
		{
			TextMeshProUGUI componentInChildren = ((Component)title).GetComponentInChildren<TextMeshProUGUI>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				DisableLocalizers(((Component)title).gameObject);
				((TMP_Text)componentInChildren).text = Message("Tax");
			}
		}
	}

	private static string SectionName(int slot)
	{
		return Message("TaxSection" + slot);
	}

	private static string Message(string key)
	{
		return Safe(() => LocalizedTextGetter.GetMessageData(key), key);
	}

	private static string TaxName(string effectID)
	{
		return Safe(() => StripRichText(LocalizedTextGetter.GetTaxData(effectID)), effectID);
	}

	private static string Name(string id)
	{
		return Safe(delegate
		{
			string s = (TagParamGetter.HasTag(id) ? TagParamGetter.GetName(id) : ItemParamGetter.GetName(id));
			return StripRichText(s);
		}, id);
	}

	private static Sprite TagSprite(string tagID)
	{
		try
		{
			return TagParamGetter.GetSprite(tagID);
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static Sprite ItemSprite(string itemID)
	{
		try
		{
			return ItemParamGetter.GetSprite(itemID);
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static string StripRichText(string s)
	{
		if (string.IsNullOrEmpty(s))
		{
			return s;
		}
		StringBuilder stringBuilder = new StringBuilder(s.Length);
		bool flag = false;
		foreach (char c in s)
		{
			switch (c)
			{
			case '<':
				flag = true;
				continue;
			case '>':
				flag = false;
				continue;
			}
			if (!flag)
			{
				stringBuilder.Append(c);
			}
		}
		return stringBuilder.ToString();
	}

	private static string Safe(Func<string> get, string fallback)
	{
		try
		{
			string text = get();
			return string.IsNullOrEmpty(text) ? fallback : text;
		}
		catch (Exception)
		{
			return fallback;
		}
	}

	private static Transform FindChildRecursive(Transform root, string name)
	{
		if ((Object)(object)root == (Object)null)
		{
			return null;
		}
		for (int i = 0; i < root.childCount; i++)
		{
			Transform child = root.GetChild(i);
			if (string.Equals(((Object)child).name, name, StringComparison.Ordinal))
			{
				return child;
			}
			Transform val = FindChildRecursive(child, name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		return null;
	}

	private static void DisableLocalizers(GameObject go)
	{
		LocalizeStringEvent[] componentsInChildren = go.GetComponentsInChildren<LocalizeStringEvent>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			((Behaviour)componentsInChildren[i]).enabled = false;
		}
	}

	public static void DumpResultFrame()
	{
		Transform val = FindResultBody();
		if ((Object)(object)val == (Object)null)
		{
			TaxLedgerPlugin.Log.LogInfo((object)"[dump] AchievementBody not found");
			return;
		}
		Transform t = (((Object)(object)val.parent != (Object)null) ? val.parent : val);
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("[dump] ").Append(GetPath(t)).Append('\n');
		Dump(t, 0, stringBuilder);
		TaxLedgerPlugin.Log.LogInfo((object)stringBuilder.ToString());
	}

	private static void Dump(Transform t, int depth, StringBuilder sb)
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null);
		sb.Append(' ', depth * 2).Append(((Object)t).name).Append(((Component)t).gameObject.activeSelf ? "" : " (off)");
		if ((Object)(object)val != (Object)null)
		{
			StringBuilder stringBuilder = sb.Append(" ");
			Rect rect = val.rect;
			StringBuilder stringBuilder2 = stringBuilder.Append(((Rect)(ref rect)).width.ToString("0")).Append('x');
			Rect rect2 = val.rect;
			stringBuilder2.Append(((Rect)(ref rect2)).height.ToString("0"));
		}
		Component[] components = ((Component)t).GetComponents<Component>();
		for (int i = 0; i < components.Length; i++)
		{
			if (!((Object)(object)components[i] == (Object)null) && !(components[i] is Transform))
			{
				sb.Append(" [").Append(((object)components[i]).GetType().Name).Append(']');
				Component obj = components[i];
				TextMeshProUGUI val2 = (TextMeshProUGUI)(object)((obj is TextMeshProUGUI) ? obj : null);
				if ((Object)(object)val2 != (Object)null)
				{
					sb.Append(" \"").Append(((TMP_Text)val2).text).Append("\" ")
						.Append(((TMP_Text)val2).fontSize);
				}
			}
		}
		sb.Append('\n');
		for (int j = 0; j < t.childCount; j++)
		{
			Dump(t.GetChild(j), depth + 1, sb);
		}
	}

	private static string GetPath(Transform t)
	{
		string text = ((Object)t).name;
		while ((Object)(object)t.parent != (Object)null)
		{
			t = t.parent;
			text = ((Object)t).name + "/" + text;
		}
		return text;
	}
}
internal static class TaxHooks
{
	[HarmonyPatch(typeof(TaxRuntimeController), "StartRuntime")]
	private static class StartRuntimePatch
	{
		private static void Prefix()
		{
			DevTax.ForceNone();
			Ledger.Reset();
			_controller = null;
			_loggedHarvest = false;
			Tries.Clear();
			Hits.Clear();
			ActiveSlots.Clear();
			SlotByEffect.Clear();
			BaseCountCache.Clear();
			SlowCarry.Clear();
			LockCarry.Clear();
			LastSeenCount.Clear();
			TaxLedgerPlugin.Trace("[ledger] cleared for a new shift");
		}
	}

	[HarmonyPatch]
	private static class ApplyPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			List<MethodBase> list = new List<MethodBase>();
			Type[] types = typeof(ITaxEffect).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (!type.IsInterface && !type.IsAbstract && typeof(ITaxEffect).IsAssignableFrom(type))
				{
					MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "Apply", new Type[2]
					{
						typeof(TaxEffectContext),
						typeof(int)
					}, (Type[])null);
					if (methodInfo != null)
					{
						list.Add(methodInfo);
					}
				}
			}
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(RecipeTaxEffectBase), "Apply", new Type[2]
			{
				typeof(TaxEffectContext),
				typeof(int)
			}, (Type[])null);
			if (methodInfo2 != null)
			{
				list.Add(methodInfo2);
			}
			MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(RepaymentLoseCashPenaltyTaxEffectBase), "Apply", new Type[2]
			{
				typeof(TaxEffectContext),
				typeof(int)
			}, (Type[])null);
			if (methodInfo3 != null)
			{
				list.Add(methodInfo3);
			}
			return list;
		}

		private static void Postfix(object __instance, TaxEffectContext context, int slotIndex)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected I4, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected I4, but got Unknown
			ITaxEffect val = (ITaxEffect)((__instance is ITaxEffect) ? __instance : null);
			if (val == null)
			{
				return;
			}
			if (context != null && context.RecipeModifiers != null)
			{
				_recipeModifiers = context.RecipeModifiers;
			}
			string effectID = val.EffectID;
			ActiveSlots[effectID] = slotIndex;
			SlotByEffect[__instance] = slotIndex;
			Ledger.DropDummy();
			TaxEntry taxEntry = Ledger.Get(effectID, slotIndex);
			if (effectID == "SlowConveyor" || effectID == "LockRandomPatron")
			{
				try
				{
					taxEntry.RateText = val.GetValueText(slotIndex);
				}
				catch (Exception)
				{
				}
			}
			if (_appliedAmountField != null && __instance is RepaymentLoseCashPenaltyTaxEffectBase)
			{
				try
				{
					taxEntry.Points = (int)_appliedAmountField.GetValue(__instance);
				}
				catch (Exception)
				{
				}
			}
			if (effectID == "NoTagRandomPatron")
			{
				taxEntry.PatronID = (int)TaxPatronResourceCutService.TargetPatron;
			}
			else if (effectID == "LockRandomPatron")
			{
				taxEntry.PatronID = (int)TaxPatronLockService.LockedPatron;
			}
			TaxLedgerPlugin.Trace("[tax] apply " + effectID + " slot=" + slotIndex + ((taxEntry.Points != 0) ? (" points=" + taxEntry.Points) : ""));
		}
	}

	[HarmonyPatch]
	private static class RemovePatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			List<MethodBase> list = new List<MethodBase>();
			Type[] types = typeof(ITaxEffect).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (!type.IsInterface && !type.IsAbstract && typeof(ITaxEffect).IsAssignableFrom(type))
				{
					MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "Remove", new Type[1] { typeof(TaxEffectContext) }, (Type[])null);
					if (methodInfo != null)
					{
						list.Add(methodInfo);
					}
				}
			}
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(RecipeTaxEffectBase), "Remove", new Type[1] { typeof(TaxEffectContext) }, (Type[])null);
			if (methodInfo2 != null)
			{
				list.Add(methodInfo2);
			}
			MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(RepaymentLoseCashPenaltyTaxEffectBase), "Remove", new Type[1] { typeof(TaxEffectContext) }, (Type[])null);
			if (methodInfo3 != null)
			{
				list.Add(methodInfo3);
			}
			return list;
		}

		private static void Postfix(object __instance)
		{
			ITaxEffect val = (ITaxEffect)((__instance is ITaxEffect) ? __instance : null);
			if (val != null)
			{
				if (ActiveSlots.Remove(val.EffectID))
				{
					TaxLedgerPlugin.Trace("[tax] remove " + val.EffectID);
				}
				SlotByEffect.Remove(__instance);
			}
		}
	}

	[HarmonyPatch(typeof(OrderExecutePenaltyTaxEffect), "AddPenalty")]
	private static class OrderPenaltyPatch
	{
		private static void Postfix(object __instance)
		{
			if (_penaltyTagField == null)
			{
				return;
			}
			try
			{
				object? value = _penaltyTagField.GetValue(__instance);
				TagCount val = (TagCount)((value is TagCount) ? value : null);
				if (!(val == (TagCount)null) && ((ValueCount)val).Count > 0)
				{
					Entry("OrderExecutePenalty").Points += ((ValueCount)val).Count;
				}
			}
			catch (Exception)
			{
			}
		}
	}

	[HarmonyPatch(typeof(DebuffRelicRepaymentLoseCash), "Execute")]
	private static class RepaymentPenaltyPatch
	{
		private static void Postfix(object __instance)
		{
			if (_repayTagField == null)
			{
				return;
			}
			TagCount val = null;
			try
			{
				object? value = _repayTagField.GetValue(__instance);
				val = (TagCount)((value is TagCount) ? value : null);
			}
			catch (Exception)
			{
				return;
			}
			if (val == (TagCount)null || ((ValueCount)val).Count >= 0)
			{
				return;
			}
			int num = -((ValueCount)val).Count;
			string tagID = val.TagID;
			List<TaxEntry> entries = Ledger.Entries;
			for (int i = 0; i < entries.Count; i++)
			{
				if (num <= 0)
				{
					break;
				}
				TaxEntry taxEntry = entries[i];
				if (taxEntry.Points > 0)
				{
					int num2 = ((taxEntry.Points < num) ? taxEntry.Points : num);
					taxEntry.AddLostResource(tagID, num2);
					num -= num2;
				}
			}
		}
	}

	[HarmonyPatch(typeof(TaxPatronResourceCutService), "ShouldCancelResourceAdd")]
	private static class PatronCutPatch
	{
		private static void Postfix(bool __result, string tagID, int actualDelta)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected I4, but got Unknown
			_patronCutHit = __result;
			if (IsTargetTag(TaxPatronResourceCutService.TargetPatron, tagID))
			{
				Count("NoTagRandomPatron", __result);
			}
			if (__result)
			{
				TaxEntry taxEntry = Entry("NoTagRandomPatron");
				taxEntry.AddLostResource(tagID, actualDelta);
				taxEntry.PatronID = (int)TaxPatronResourceCutService.TargetPatron;
			}
		}
	}

	[HarmonyPatch(typeof(TaxResourceRecordCutService), "ShouldCancelResourceAdd")]
	private static class BuffCashCutPatch
	{
		private static void Prefix()
		{
			_patronCutHit = false;
		}

		private static void Postfix(bool __result, string tagID, int actualDelta, StatsCashReason statsCashReason)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (tagID == "Cash" && actualDelta > 0 && (int)statsCashReason == 3)
			{
				Count("CutBuffCash", __result && !_patronCutHit);
			}
			if (__result && !_patronCutHit)
			{
				Entry("CutBuffCash").AddLostResource(tagID, actualDelta);
			}
		}
	}

	[HarmonyPatch(typeof(TaxResourceRecordCutService), "ShouldCancelSaleTag")]
	private static class SaleTagCutPatch
	{
		private static void Postfix(bool __result, string tagID)
		{
			if (tagID == LocalTagTarget())
			{
				Count("CutLocalTag", __result);
			}
			if (__result)
			{
				Entry("CutLocalTag").AddLostResource(tagID, TagAmountOfDepositItem(tagID));
			}
		}
	}

	[HarmonyPatch(typeof(TaxDeliveryCancellationService), "ShouldCancelDelivery")]
	private static class DeliveryCancelPatch
	{
		private static void Postfix(bool __result, bool isDirectDeliveryBoxSale)
		{
			if (!isDirectDeliveryBoxSale)
			{
				Count("Centralization", __result);
			}
			if (__result && _depositItemID != null)
			{
				TaxEntry taxEntry = Entry("Centralization");
				taxEntry.CancelledSales++;
				AddItemLoss(taxEntry, _depositItemID, _depositCount);
			}
		}
	}

	[HarmonyPatch(typeof(DeliveryDepositor), "DepositInternal")]
	private static class DepositInternalPatch
	{
		private static void Prefix(ItemCount itemCount)
		{
			if (itemCount == (ItemCount)null)
			{
				_depositItemID = null;
				_depositCount = 0;
			}
			else
			{
				_depositItemID = itemCount.ItemID;
				_depositCount = ((ValueCount)itemCount).Count;
			}
		}

		private static void Postfix()
		{
			_depositItemID = null;
			_depositCount = 0;
		}
	}

	[HarmonyPatch(typeof(CrafterFamObjectBase), "TryExecuteCraft")]
	private static class CraftPatch
	{
		private static void Postfix(bool __result, CrafterFamObjectBase __instance)
		{
			if (!__result || __instance == null)
			{
				return;
			}
			Recipe onGoingRecipe = __instance.OnGoingRecipe;
			if (onGoingRecipe == null || onGoingRecipe.Result == (ValueCount)null)
			{
				return;
			}
			int count = onGoingRecipe.Result.Count;
			int num = BaseResultCount(onGoingRecipe) - count;
			if (num > 0)
			{
				string text = ActiveResultCutTax();
				if (text != null)
				{
					AddResultLoss(Entry(text), onGoingRecipe, num);
				}
			}
			if (count > 0 && IsActive("LongerCraft") && IsSlowedNow(__instance, onGoingRecipe))
			{
				float num2 = TaxEffectParameters.LONGER_CRAFT_REQUIRE_TIME_MULTIPLIERS[Clamp3(SlotOf("LongerCraft"))];
				AddResultLoss(Entry("LongerCraft"), onGoingRecipe, Carry(SlowCarry, onGoingRecipe, (float)count * (num2 - 1f)));
			}
			if (count > 0 && IsActive("LockRandomPatron") && IsLockedFam(__instance))
			{
				float workSpeedMultiplier = LockRandomPatronTaxEffect.GetWorkSpeedMultiplier(Clamp3(SlotOf("LockRandomPatron")));
				if (workSpeedMultiplier > 0f)
				{
					AddResultLoss(Entry("LockRandomPatron"), onGoingRecipe, Carry(LockCarry, onGoingRecipe, (float)count * (1f / workSpeedMultiplier - 1f)));
				}
			}
		}
	}

	[HarmonyPatch(typeof(TakenDamageCalculator), "CheckProduceTimes")]
	private static class HarvestPatch
	{
		private static void Postfix(int __result, TakenDamageCalculator __instance)
		{
			//IL_0058: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (__result <= 0 || _propField == null)
			{
				return;
			}
			try
			{
				object? value = _propField.GetValue(__instance);
				HarvestablePropertyKeeper val = (HarvestablePropertyKeeper)((value is HarvestablePropertyKeeper) ? value : null);
				if (val == (HarvestablePropertyKeeper)null)
				{
					return;
				}
				HarvestableParameters parameters = val.GetParameters();
				if (parameters == null)
				{
					return;
				}
				int num = parameters.GetEffectiveToughness() - parameters.Toughness;
				if (num <= 0)
				{
					return;
				}
				string text = (HarvestableDB.IsTypeRock(parameters.Type) ? "HarvestRockPenalty" : (HarvestableDB.IsTypePlant(parameters.Type) ? "HarvestTreePenalty" : null));
				if (text != null && IsActive(text))
				{
					Entry(text).ExtraHits += num * __result;
					if (!_loggedHarvest)
					{
						_loggedHarvest = true;
						TaxLedgerPlugin.Trace(string.Concat("[harvest] ", parameters.Type, " toughness ", parameters.Toughness, " -> ", parameters.GetEffectiveToughness(), " (+", num, " per item)"));
					}
				}
			}
			catch (Exception)
			{
			}
		}
	}

	private static readonly Dictionary<string, int> ActiveSlots = new Dictionary<string, int>();

	private static readonly Dictionary<object, int> SlotByEffect = new Dictionary<object, int>();

	private static TaxRuntimeController _controller;

	private static FieldInfo _cachedSlotsField;

	private static FieldInfo _contextField;

	private static FieldInfo _activeEffectIDField;

	private static FieldInfo _appliedAmountField;

	private static FieldInfo _penaltyTagField;

	private static FieldInfo _repayTagField;

	private static FieldInfo _localTagTargetField;

	private static FieldInfo _snapshotsField;

	private static FieldInfo _propField;

	private static PropertyInfo _baseResultCountProp;

	private static RecipeTemporaryModifierService _recipeModifiers;

	private static readonly Dictionary<Recipe, int> BaseCountCache = new Dictionary<Recipe, int>();

	private static readonly Dictionary<Recipe, int> LastSeenCount = new Dictionary<Recipe, int>();

	private static string _depositItemID;

	private static int _depositCount;

	private static bool _patronCutHit;

	private static bool _loggedHarvest;

	private static readonly Dictionary<string, int> Tries = new Dictionary<string, int>();

	private static readonly Dictionary<string, int> Hits = new Dictionary<string, int>();

	private static readonly Dictionary<Recipe, float> SlowCarry = new Dictionary<Recipe, float>();

	private static readonly Dictionary<Recipe, float> LockCarry = new Dictionary<Recipe, float>();

	private static void Count(string effectID, bool hit)
	{
		if (IsActive(effectID))
		{
			Tries.TryGetValue(effectID, out var value);
			Tries[effectID] = value + 1;
			if (hit)
			{
				Hits.TryGetValue(effectID, out value);
				Hits[effectID] = value + 1;
			}
		}
	}

	internal static void Init(Harmony harmony)
	{
		_cachedSlotsField = AccessTools.Field(typeof(TaxRuntimeController), "_cachedSlots");
		_contextField = AccessTools.Field(typeof(TaxRuntimeController), "_context");
		_activeEffectIDField = AccessTools.Field(typeof(TaxRuntimeController), "_activeEffectID");
		_appliedAmountField = AccessTools.Field(typeof(RepaymentLoseCashPenaltyTaxEffectBase), "_appliedAmount");
		_penaltyTagField = AccessTools.Field(typeof(OrderExecutePenaltyTaxEffect), "_penaltyTagCount");
		_repayTagField = AccessTools.Field(typeof(DebuffRelicRepaymentLoseCash), "_penaltyTagCount");
		_localTagTargetField = AccessTools.Field(typeof(TaxResourceRecordCutService), "_localTagTargetID");
		_snapshotsField = AccessTools.Field(typeof(RecipeTemporaryModifierService), "_snapshots");
		_propField = AccessTools.Field(typeof(TakenDamageCalculator), "_prop");
		Type type = AccessTools.Inner(typeof(RecipeTemporaryModifierService), "RecipeSnapshot");
		_baseResultCountProp = ((type != null) ? AccessTools.Property(type, "BaseResultCount") : null);
		if (_appliedAmountField == null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[hook] cannot read _appliedAmount");
		}
		if (_penaltyTagField == null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[hook] cannot read _penaltyTagCount");
		}
		if (_snapshotsField == null || _baseResultCountProp == null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[hook] cannot read the recipe snapshots; craft losses stay 0");
		}
		if (_propField == null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[hook] cannot read _prop; extra hits stay 0");
		}
		if (_repayTagField == null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[hook] cannot read the repayment penalty");
		}
	}

	internal static int SlotOf(string effectID)
	{
		TaxSlotData[] array = Slots();
		if (array != null)
		{
			for (int i = 0; i < array.Length; i++)
			{
				if (((TaxSlotData)(ref array[i])).EffectID == effectID)
				{
					return i;
				}
			}
		}
		if (ActiveSlots.TryGetValue(effectID, out var value))
		{
			return value;
		}
		return 0;
	}

	internal static bool IsActive(string effectID)
	{
		TaxRuntimeController val = Controller();
		if ((Object)(object)val != (Object)null)
		{
			try
			{
				if (_activeEffectIDField != null)
				{
					string text = _activeEffectIDField.GetValue(val) as string;
					if (text == effectID)
					{
						return true;
					}
				}
			}
			catch (Exception)
			{
			}
		}
		return ActiveSlots.ContainsKey(effectID);
	}

	private static TaxRuntimeController Controller()
	{
		if ((Object)(object)_controller != (Object)null)
		{
			return _controller;
		}
		try
		{
			_controller = Object.FindAnyObjectByType<TaxRuntimeController>();
		}
		catch (Exception)
		{
			_controller = null;
		}
		return _controller;
	}

	internal static TaxEffectContext Context()
	{
		TaxRuntimeController val = Controller();
		if ((Object)(object)val == (Object)null || _contextField == null)
		{
			return null;
		}
		try
		{
			object? value = _contextField.GetValue(val);
			return (TaxEffectContext)((value is TaxEffectContext) ? value : null);
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static TaxSlotData[] Slots()
	{
		TaxRuntimeController val = Controller();
		if ((Object)(object)val == (Object)null || _cachedSlotsField == null)
		{
			return null;
		}
		try
		{
			return _cachedSlotsField.GetValue(val) as TaxSlotData[];
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static TaxEntry Entry(string effectID)
	{
		Ledger.DropDummy();
		return Ledger.Get(effectID, SlotOf(effectID));
	}

	private static bool IsSlowedNow(CrafterFamObjectBase crafter, Recipe recipe)
	{
		try
		{
			float workSpeedPerSec = ((FamObject)crafter).GetWorkSpeedPerSec();
			if (workSpeedPerSec <= 0f)
			{
				return false;
			}
			return TaxRecipeCraftTimeService.GetEffectiveRequireTime(recipe, workSpeedPerSec) > recipe.RequireTime;
		}
		catch (Exception)
		{
			return false;
		}
	}

	private static bool IsLockedFam(CrafterFamObjectBase crafter)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Invalid comparison between Unknown and I4
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		Patron lockedPatron = TaxPatronLockService.LockedPatron;
		if ((int)lockedPatron == -1)
		{
			return false;
		}
		if (!Patrons.FAM.TryGetValue(lockedPatron, out var value))
		{
			return false;
		}
		return ((FamObject)crafter).GetFamType() == value;
	}

	private static string ActiveResultCutTax()
	{
		if (IsActive("SampleProvision"))
		{
			return "SampleProvision";
		}
		if (IsActive("ReduceItemCraftResult"))
		{
			return "ReduceItemCraftResult";
		}
		if (IsActive("ReduceTagCraftResult"))
		{
			return "ReduceTagCraftResult";
		}
		return null;
	}

	private static int BaseResultCount(Recipe recipe)
	{
		int count = recipe.Result.Count;
		if (LastSeenCount.TryGetValue(recipe, out var value) && value == count && BaseCountCache.TryGetValue(recipe, out var value2))
		{
			return value2;
		}
		int num = count;
		if (_snapshotsField != null && _baseResultCountProp != null && _recipeModifiers != null)
		{
			try
			{
				if (_snapshotsField.GetValue(_recipeModifiers) is IDictionary dictionary && dictionary.Contains(recipe))
				{
					object obj = dictionary[recipe];
					if (obj != null)
					{
						num = (int)_baseResultCountProp.GetValue(obj, null);
					}
				}
			}
			catch (Exception)
			{
			}
		}
		LastSeenCount[recipe] = count;
		BaseCountCache[recipe] = num;
		return num;
	}

	private static void AddResultLoss(TaxEntry entry, Recipe recipe, int lostCount)
	{
		if (lostCount <= 0)
		{
			return;
		}
		ValueCount result = recipe.Result;
		ItemCount val = (ItemCount)(object)((result is ItemCount) ? result : null);
		if (val != (ItemCount)null)
		{
			AddItemLoss(entry, val.ItemID, lostCount);
			return;
		}
		ValueCount result2 = recipe.Result;
		TagCount val2 = (TagCount)(object)((result2 is TagCount) ? result2 : null);
		if (val2 != (TagCount)null)
		{
			entry.AddLostResource(val2.TagID, lostCount);
		}
	}

	private static int Clamp3(int slot)
	{
		if (slot < 0)
		{
			return 0;
		}
		if (slot > 2)
		{
			return 2;
		}
		return slot;
	}

	private static int Carry(Dictionary<Recipe, float> carried, Recipe recipe, float lost)
	{
		if (lost <= 0f)
		{
			return 0;
		}
		carried.TryGetValue(recipe, out var value);
		value += lost;
		int num = (int)value;
		carried[recipe] = value - (float)num;
		return num;
	}

	internal static void LogCheck()
	{
		List<string> list = new List<string>();
		List<int> list2 = new List<int>();
		TaxSlotData[] array = Slots();
		if (array != null)
		{
			for (int i = 0; i < array.Length; i++)
			{
				list.Add(((TaxSlotData)(ref array[i])).EffectID);
				list2.Add(i);
			}
		}
		foreach (KeyValuePair<string, int> activeSlot in ActiveSlots)
		{
			if (!list.Contains(activeSlot.Key))
			{
				list.Add(activeSlot.Key);
				list2.Add(activeSlot.Value);
			}
		}
		StringBuilder stringBuilder = new StringBuilder("[check]");
		if (list.Count == 0)
		{
			stringBuilder.Append(" nothing applied (not in a shift?)");
			TaxLedgerPlugin.Log.LogInfo((object)stringBuilder.ToString());
			return;
		}
		for (int j = 0; j < list.Count; j++)
		{
			string text = list[j];
			stringBuilder.Append('\n').Append("  ").Append(Verdict(text))
				.Append(' ')
				.Append(text)
				.Append(" slot")
				.Append(list2[j])
				.Append(IsActive(text) ? "" : " [off]");
			stringBuilder.Append(" expected=").Append(Expected(text, list2[j]));
			Tries.TryGetValue(text, out var value);
			Hits.TryGetValue(text, out var value2);
			if (value > 0)
			{
				stringBuilder.Append(" observed=").Append(value2).Append('/')
					.Append(value)
					.Append(" (")
					.Append((100f * (float)value2 / (float)value).ToString("0.0"))
					.Append("%)");
			}
		}
		TaxLedgerPlugin.Log.LogInfo((object)stringBuilder.ToString());
	}

	private static string Verdict(string effectID)
	{
		for (int i = 0; i < Ledger.Entries.Count; i++)
		{
			TaxEntry taxEntry = Ledger.Entries[i];
			if (!(taxEntry.EffectID != effectID) && (taxEntry.Points != 0 || taxEntry.ExtraHits != 0 || taxEntry.CancelledSales != 0 || taxEntry.LostResources.Count > 0 || taxEntry.Items.Count > 0))
			{
				return "o";
			}
		}
		return ".";
	}

	private static string Expected(string effectID, int slot)
	{
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
		int num = ((slot >= 0) ? ((slot > 2) ? 2 : slot) : 0);
		return effectID switch
		{
			"CutLocalTag" => TaxEffectParameters.CUT_LOCAL_TAG_CHANCE_PERCENTS[num] + "% of " + LocalTagTarget(), 
			"CutBuffCash" => TaxEffectParameters.CUT_BUFF_CASH_CHANCE_PERCENTS[num] + "% of buff cash", 
			"NoTagRandomPatron" => TaxEffectParameters.NO_TAG_RANDOM_PATRON_CHANCE_PERCENTS[num] + "% of " + TaxPatronResourceCutService.TargetPatron, 
			"Centralization" => TaxEffectParameters.CENTRALIZATION_DELIVERY_CANCELLATION_CHANCE_PERCENTS[num] + "% of sales", 
			"HarvestRockPenalty" => "toughness x" + TaxEffectParameters.HARVEST_ROCK_TOUGHNESS_MULTIPLIERS[num], 
			"HarvestTreePenalty" => "toughness x" + TaxEffectParameters.HARVEST_TREE_TOUGHNESS_MULTIPLIERS[num], 
			"LongerCraft" => "time x" + TaxEffectParameters.LONGER_CRAFT_REQUIRE_TIME_MULTIPLIERS[num] + " over " + TaxEffectParameters.LONGER_CRAFT_REQUIRE_TIME_THRESHOLDS[num] + "s", 
			"SampleProvision" => "result -> 1 when >= " + TaxEffectParameters.SAMPLE_PROVISION_RESULT_COUNT_THRESHOLDS[num], 
			"ReduceTagCraftResult" => "result " + TaxEffectParameters.REDUCE_TAG_CRAFT_RESULT_COUNT_DELTAS[num], 
			"ReduceItemCraftResult" => "result " + TaxEffectParameters.REDUCE_ITEM_CRAFT_RESULT_COUNT_DELTAS[num], 
			"SlowConveyor" => "conveyor -" + TaxEffectParameters.SLOW_CONVEYOR_REDUCTION_RATES[num] * 100f + "%", 
			"LockRandomPatron" => "work speed x" + TaxEffectParameters.LOCK_RANDOM_PATRON_WORK_SPEED_MULTIPLIERS[num] + " on " + TaxPatronLockService.LockedPatron, 
			"FamCountPenalty" => "+" + TaxEffectParameters.FAM_COUNT_PENALTIES_PER_FAM[num] + " per fam", 
			"LandCountPenalty" => "+" + TaxEffectParameters.LAND_COUNT_PENALTIES_PER_LAND[num] + " per land", 
			"OrderExecutePenalty" => "+" + TaxEffectParameters.ORDER_EXECUTE_PENALTIES_PER_ORDER[num] + " per order", 
			_ => "-", 
		};
	}

	private static string LocalTagTarget()
	{
		if (_localTagTargetField == null)
		{
			return "None";
		}
		try
		{
			return _localTagTargetField.GetValue(null) as string;
		}
		catch (Exception)
		{
			return "None";
		}
	}

	private static bool IsTargetTag(Patron patron, string tagID)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		if ((int)patron == -1)
		{
			return false;
		}
		if (!Patrons.TAG.TryGetValue(patron, out var value))
		{
			return false;
		}
		return value == tagID;
	}

	internal static void AddItemLoss(TaxEntry entry, string itemID, int count)
	{
		if (!string.IsNullOrEmpty(itemID) && count > 0)
		{
			Item val = null;
			try
			{
				val = ItemDB.GetItemByID(itemID);
			}
			catch (Exception)
			{
			}
			ItemLoss item = entry.GetItem(itemID);
			if ((Object)(object)val == (Object)null)
			{
				item.Count += count;
			}
			else
			{
				item.Add(count, val.tag1Runtime, val.tag1CountRuntime, val.tag2Runtime, val.tag2CountRuntime, val.tag3Runtime, val.tag3CountRuntime);
			}
		}
	}

	private static int TagAmountOfDepositItem(string tagID)
	{
		if (_depositItemID == null || _depositCount <= 0)
		{
			return 0;
		}
		Item val = null;
		try
		{
			val = ItemDB.GetItemByID(_depositItemID);
		}
		catch (Exception)
		{
		}
		if ((Object)(object)val == (Object)null)
		{
			return 0;
		}
		int num = 0;
		if (val.tag1Runtime == tagID)
		{
			num += val.tag1CountRuntime;
		}
		if (val.tag2Runtime == tagID)
		{
			num += val.tag2CountRuntime;
		}
		if (val.tag3Runtime == tagID)
		{
			num += val.tag3CountRuntime;
		}
		return num * _depositCount;
	}
}
internal static class DevTax
{
	[HarmonyPatch(typeof(TaxSlotService), "GetOrCreateSlots")]
	private static class SlotsPatch
	{
		private static bool Prepare()
		{
			return TaxLedgerPlugin.DevMode.Value;
		}

		private static void Postfix(ref TaxSlotData[] __result)
		{
			string value = TaxLedgerPlugin.DevTaxes.Value;
			if (value != _parsedFrom)
			{
				Parse(value);
			}
			if (_slots != null)
			{
				__result = _slots;
			}
		}
	}

	private static TaxSlotData[] _slots;

	private static string _parsedFrom;

	private static FieldInfo _slotsChangedField;

	private static readonly string[] Picked = new string[3] { "", "", "" };

	private static readonly Dictionary<string, ITaxEffect> Forced = new Dictionary<string, ITaxEffect>();

	private static int _forceSlot;

	private static readonly string[] ResultCutIDs = new string[3] { "SampleProvision", "ReduceItemCraftResult", "ReduceTagCraftResult" };

	private static bool _open;

	private static Rect _window = new Rect(40f, 40f, 420f, 520f);

	private static Vector2 _scroll;

	private static GUIStyle _rowStyle;

	internal static bool IsOpen => _open;

	internal static void Init()
	{
		if (TaxLedgerPlugin.DevMode.Value)
		{
			_slotsChangedField = AccessTools.Field(typeof(TaxSlotService), "SlotsChangedSubject");
			if (_slotsChangedField == null)
			{
				TaxLedgerPlugin.Log.LogWarning((object)"[dev] cannot notify the slot change; restart the shift to apply");
			}
			Parse(TaxLedgerPlugin.DevTaxes.Value);
		}
	}

	private static void Notify()
	{
		//IL_004a: 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)
		if (_slotsChangedField == null)
		{
			return;
		}
		try
		{
			object value = _slotsChangedField.GetValue(null);
			if (value != null)
			{
				MethodInfo methodInfo = AccessTools.Method(value.GetType(), "OnNext", (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					methodInfo.Invoke(value, new object[1] { (object)default(Unit) });
				}
			}
		}
		catch (Exception ex)
		{
			TaxLedgerPlugin.Log.LogWarning((object)("[dev] cannot notify the slot change: " + ex.Message));
		}
	}

	private static void Parse(string value)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		_parsedFrom = value;
		_slots = null;
		if (string.IsNullOrEmpty(value))
		{
			return;
		}
		string[] array = value.Split(',');
		List<TaxSlotData> list = new List<TaxSlotData>();
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length != 0)
			{
				if (!TaxEffectRegistry.IsKnownEffectID(text))
				{
					TaxLedgerPlugin.Log.LogWarning((object)("[dev] unknown tax id: " + text));
					return;
				}
				list.Add(new TaxSlotData(text));
			}
		}
		if (list.Count != 3)
		{
			TaxLedgerPlugin.Log.LogWarning((object)("[dev] Taxes needs 3 ids, got " + list.Count));
			return;
		}
		_slots = list.ToArray();
		for (int j = 0; j < 3; j++)
		{
			Picked[j] = ((TaxSlotData)(ref _slots[j])).EffectID;
		}
		TaxLedgerPlugin.Log.LogInfo((object)("[dev] taxes fixed to " + value));
	}

	internal static void Force(string effectID, int slot)
	{
		Unforce(effectID);
		TaxEffectContext val = TaxHooks.Context();
		if (val == null)
		{
			TaxLedgerPlugin.Log.LogWarning((object)"[dev] no context yet; start a shift first");
			return;
		}
		ITaxEffect val2 = TaxEffectRegistry.Create(effectID);
		if (val2 == null)
		{
			return;
		}
		try
		{
			val2.Apply(val, slot);
			Forced[effectID] = val2;
		}
		catch (Exception ex)
		{
			TaxLedgerPlugin.Log.LogWarning((object)("[dev] cannot force " + effectID + ": " + ex.Message));
		}
	}

	internal static void Unforce(string effectID)
	{
		if (!Forced.TryGetValue(effectID, out var value))
		{
			return;
		}
		Forced.Remove(effectID);
		try
		{
			value.Remove(TaxHooks.Context());
		}
		catch (Exception)
		{
		}
	}

	internal static bool IsForced(string effectID)
	{
		return Forced.ContainsKey(effectID);
	}

	private static string ForcedResultCut()
	{
		for (int i = 0; i < ResultCutIDs.Length; i++)
		{
			if (Forced.ContainsKey(ResultCutIDs[i]))
			{
				return ResultCutIDs[i];
			}
		}
		return "";
	}

	internal static void ForceAll(int slot)
	{
		string text = ForcedResultCut();
		if (text.Length == 0)
		{
			text = ResultCutIDs[0];
		}
		IReadOnlyList<string> effectIDs = TaxEffectRegistry.EffectIDs;
		int num = 0;
		for (int i = 0; i < effectIDs.Count; i++)
		{
			string text2 = effectIDs[i];
			if (Array.IndexOf(ResultCutIDs, text2) < 0 || !(text2 != text))
			{
				Force(text2, slot);
				num++;
			}
		}
		TaxLedgerPlugin.Log.LogInfo((object)("[dev] forced " + num + " taxes at slot" + slot + " (result cut: " + text + ")"));
	}

	internal static void ForceNone()
	{
		if (Forced.Count != 0)
		{
			List<string> list = new List<string>(Forced.Keys);
			for (int i = 0; i < list.Count; i++)
			{
				Unforce(list[i]);
			}
			TaxLedgerPlugin.Log.LogInfo((object)"[dev] forced taxes cleared");
		}
	}

	internal static void Toggle()
	{
		_open = !_open;
	}

	internal static void Draw()
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (_open)
		{
			_window = GUI.Window(31358, _window, new WindowFunction(DrawWindow), "Tax Ledger — dev");
		}
	}

	private static void DrawWindow(int id)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_032e: Unknown result type (might be due to invalid IL or missing references)
		if (_rowStyle == null)
		{
			_rowStyle = new GUIStyle(GUI.skin.label);
			_rowStyle.alignment = (TextAnchor)3;
			_rowStyle.wordWrap = false;
		}
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		for (int i = 0; i < 3; i++)
		{
			GUILayout.Label(i + 1 + ": " + ((Picked[i].Length == 0) ? "-" : Name(Picked[i])), _rowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(126f) });
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("force at", _rowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(52f) });
		for (int j = 0; j < 3; j++)
		{
			if (GUILayout.Toggle(_forceSlot == j, (j + 1).ToString(), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) }))
			{
				_forceSlot = j;
			}
		}
		if (GUILayout.Button("All", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ForceAll(_forceSlot);
		}
		if (GUILayout.Button("Clear", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ForceNone();
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			Commit();
		}
		if (GUILayout.Button("Random", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			for (int k = 0; k < 3; k++)
			{
				Picked[k] = "";
			}
			Commit();
		}
		if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_open = false;
		}
		GUILayout.EndHorizontal();
		_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		IReadOnlyList<string> effectIDs = TaxEffectRegistry.EffectIDs;
		for (int l = 0; l < effectIDs.Count; l++)
		{
			string text = effectIDs[l];
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label(Name(text), _rowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) });
			for (int m = 0; m < 3; m++)
			{
				bool flag = Picked[m] == text;
				bool flag2 = GUILayout.Toggle(flag, (m + 1).ToString(), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) });
				if (flag2 != flag)
				{
					if (flag2)
					{
						Pick(text, m);
					}
					else
					{
						Picked[m] = "";
					}
				}
			}
			bool flag3 = Forced.ContainsKey(text);
			bool flag4 = GUILayout.Toggle(flag3, "F", GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) });
			if (flag4 != flag3)
			{
				if (flag4)
				{
					ForceSingle(text);
				}
				else
				{
					Unforce(text);
				}
			}
			GUILayout.EndHorizontal();
		}
		GUILayout.EndScrollView();
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
	}

	private static void ForceSingle(string effectID)
	{
		if (Array.IndexOf(ResultCutIDs, effectID) >= 0)
		{
			for (int i = 0; i < ResultCutIDs.Length; i++)
			{
				if (ResultCutIDs[i] != effectID)
				{
					Unforce(ResultCutIDs[i]);
				}
			}
		}
		Force(effectID, _forceSlot);
	}

	private static void Pick(string effectID, int slot)
	{
		for (int i = 0; i < 3; i++)
		{
			if (Picked[i] == effectID)
			{
				Picked[i] = "";
			}
		}
		Picked[slot] = effectID;
	}

	private static void Commit()
	{
		int num = 0;
		for (int i = 0; i < 3; i++)
		{
			if (Picked[i].Length > 0)
			{
				num++;
			}
		}
		string text = ((num == 3) ? (Picked[0] + "," + Picked[1] + "," + Picked[2]) : "");
		TaxLedgerPlugin.DevTaxes.Value = text;
		Parse(text);
		Notify();
		if (text.Length == 0)
		{
			TaxLedgerPlugin.Log.LogInfo((object)"[dev] taxes back to random");
		}
	}

	private static string Name(string effectID)
	{
		try
		{
			string taxData = LocalizedTextGetter.GetTaxData(effectID);
			if (string.IsNullOrEmpty(taxData))
			{
				return effectID;
			}
			StringBuilder stringBuilder = new StringBuilder(taxData.Length);
			bool flag = false;
			foreach (char c in taxData)
			{
				switch (c)
				{
				case '<':
					flag = true;
					continue;
				case '>':
					flag = false;
					continue;
				}
				if (!flag)
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}
		catch (Exception)
		{
			return effectID;
		}
	}
}
internal static class LedgerFile
{
	private const string FileName = "LwfTaxLedger-last.txt";

	private const char Sep = '\t';

	private static string Path()
	{
		try
		{
			return System.IO.Path.Combine(Paths.BepInExRootPath, "LwfTaxLedger-last.txt");
		}
		catch (Exception)
		{
			return "LwfTaxLedger-last.txt";
		}
	}

	internal static void Save()
	{
		if (Ledger.Entries.Count == 0 || Ledger.IsDummy)
		{
			return;
		}
		try
		{
			StringBuilder stringBuilder = new StringBuilder(1024);
			for (int i = 0; i < Ledger.Entries.Count; i++)
			{
				TaxEntry taxEntry = Ledger.Entries[i];
				stringBuilder.Append("entry").Append('\t').Append(taxEntry.Slot)
					.Append('\t')
					.Append(taxEntry.EffectID)
					.Append('\t')
					.Append(taxEntry.Points)
					.Append('\t')
					.Append(taxEntry.CancelledSales)
					.Append('\t')
					.Append(taxEntry.PatronID)
					.Append('\t')
					.Append(taxEntry.ExtraHits)
					.Append('\t')
					.Append(taxEntry.ActiveSeconds.ToString("0.###", CultureInfo.InvariantCulture))
					.Append('\t')
					.Append((taxEntry.RateText == null) ? "" : taxEntry.RateText)
					.Append('\n');
				foreach (KeyValuePair<string, int> lostResource in taxEntry.LostResources)
				{
					stringBuilder.Append("res").Append('\t').Append(lostResource.Key)
						.Append('\t')
						.Append(lostResource.Value)
						.Append('\n');
				}
				foreach (KeyValuePair<string, ItemLoss> item in taxEntry.Items)
				{
					ItemLoss value = item.Value;
					stringBuilder.Append("item").Append('\t').Append(value.ItemID)
						.Append('\t')
						.Append(value.Count)
						.Append('\n');
					foreach (KeyValuePair<string, int> resource in value.Resources)
					{
						stringBuilder.Append("itemres").Append('\t').Append(resource.Key)
							.Append('\t')
							.Append(resource.Value)
							.Append('\n');
					}
				}
			}
			File.WriteAllText(Path(), stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			TaxLedgerPlugin.Trace("[dev] saved the ledger to LwfTaxLedger-last.txt");
		}
		catch (Exception ex)
		{
			TaxLedgerPlugin.Log.LogWarning((object)("[dev] cannot save the ledger: " + ex.Message));
		}
	}

	internal static bool Load()
	{
		string path = Path();
		try
		{
			if (!File.Exists(path))
			{
				return false;
			}
			string[] array = File.ReadAllLines(path);
			Ledger.Reset();
			TaxEntry taxEntry = null;
			ItemLoss itemLoss = null;
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split('\t');
				if (array2.Length < 2)
				{
					continue;
				}
				switch (array2[0])
				{
				case "entry":
					if (array2.Length >= 9)
					{
						taxEntry = Ledger.Get(array2[2], Int(array2[1]));
						taxEntry.Points = Int(array2[3]);
						taxEntry.CancelledSales = Int(array2[4]);
						taxEntry.PatronID = Int(array2[5]);
						taxEntry.ExtraHits = Int(array2[6]);
						taxEntry.ActiveSeconds = Float(array2[7]);
						taxEntry.RateText = ((array2[8].Length > 0) ? array2[8] : null);
						itemLoss = null;
					}
					break;
				case "res":
					if (taxEntry != null && array2.Length >= 3)
					{
						taxEntry.AddLostResource(array2[1], Int(array2[2]));
					}
					break;
				case "item":
					if (taxEntry != null && array2.Length >= 3)
					{
						itemLoss = taxEntry.GetItem(array2[1]);
						itemLoss.Count += Int(array2[2]);
					}
					break;
				case "itemres":
					if (itemLoss != null && array2.Length >= 3)
					{
						itemLoss.AddTag(array2[1], Int(array2[2]));
					}
					break;
				}
			}
			TaxLedgerPlugin.Log.LogInfo((object)("[dev] loaded the last ledger: entries=" + Ledger.Entries.Count));
			return Ledger.Entries.Count > 0;
		}
		catch (Exception ex)
		{
			TaxLedgerPlugin.Log.LogWarning((object)("[dev] cannot load the ledger: " + ex.Message));
			return false;
		}
	}

	private static int Int(string s)
	{
		if (!int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
		{
			return 0;
		}
		return result;
	}

	private static float Float(string s)
	{
		if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
		{
			return 0f;
		}
		return result;
	}
}