Decompiled source of IcarusGardening v1.4.3

DSPNormalModeVegetation.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("DSPNormalModeVegetation")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.3.0")]
[assembly: AssemblyInformationalVersion("1.4.3")]
[assembly: AssemblyProduct("DSPNormalModeVegetation")]
[assembly: AssemblyTitle("DSPNormalModeVegetation")]
[assembly: AssemblyVersion("1.4.3.0")]
namespace DSPNormalModeVegetation;

[BepInPlugin("Zincon.DSPNormalModeVegetation", "Icarus Gardening", "1.4.3")]
[BepInProcess("DSPGAME.exe")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "Zincon.DSPNormalModeVegetation";

	public const string PluginName = "Icarus Gardening";

	public const string PluginVersion = "1.4.3";

	private Harmony harmony;

	internal static ManualLogSource Log { get; private set; }

	private void Awake()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			VegetationModePatches.ValidateTargets();
			harmony = new Harmony("Zincon.DSPNormalModeVegetation");
			harmony.PatchAll(typeof(VegetationModePatches));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Icarus Gardening 1.4.3 loaded. Native vegetation placement, removal, and scaling are available in regular games.");
		}
		catch (Exception ex)
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			harmony = null;
			((BaseUnityPlugin)this).Logger.LogError((object)("Failed to enable normal-mode vegetation placement. No sandbox or abnormality flags were changed.\n" + ex));
		}
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		harmony = null;
		Log = null;
	}
}
internal static class VegetationCategoryCatalog
{
	internal const int FirstCategory = 1;

	internal const int LastCategory = 6;

	internal const int NativeVegetationCategory = 3;

	internal const int NativeRemovalCategory = 10;

	private const int LocalCategory = 1;

	private const int OrganicCategory = 2;

	private const int TerrestrialCategory = 3;

	private const int UninhabitableCategory = 4;

	private const int OtherCategory = 5;

	internal const int GalacticScaleCategory = 6;

	private const int LastVanillaThemeId = 25;

	private static readonly int[] BundledGalacticScaleVegetationIds = new int[34]
	{
		25, 26, 32, 36, 37, 39, 41, 42, 43, 45,
		46, 47, 101, 102, 103, 104, 106, 121, 124, 125,
		126, 601, 602, 603, 604, 605, 1001, 1002, 1003, 1004,
		1005, 1006, 1007, 1023
	};

	private static readonly Dictionary<int, int> VanillaThemeCategoriesById = CreateVanillaThemeCategoriesById();

	private static readonly Dictionary<string, int> VanillaThemeCategoriesByName = CreateVanillaThemeCategoriesByName();

	private static readonly HashSet<string> VanillaGalacticScaleThemeNames = CreateVanillaGalacticScaleThemeNames();

	private static readonly HashSet<string> KnownCustomGalacticScaleThemeNames = CreateKnownCustomGalacticScaleThemeNames();

	private static Dictionary<int, HashSet<int>> categoryVegetationIds;

	private static string lastClassificationDiagnostic;

	internal static bool IsCustomCategory(int category)
	{
		if (category >= 1)
		{
			return category <= 6;
		}
		return false;
	}

	internal static string GetTitle(int category)
	{
		bool isZHCN = Localization.isZHCN;
		switch (category)
		{
		case 1:
			if (!isZHCN)
			{
				return "Local Vegetation";
			}
			return "本地植被";
		case 2:
			if (!isZHCN)
			{
				return "Organic Planet Vegetation";
			}
			return "有机行星植被";
		case 3:
			if (!isZHCN)
			{
				return "Terrestrial Planets";
			}
			return "类地行星";
		case 4:
			if (!isZHCN)
			{
				return "Uninhabitable";
			}
			return "不适宜生存";
		case 5:
			if (!isZHCN)
			{
				return "Other";
			}
			return "其它";
		case 6:
			return "GalacticScale";
		default:
			return string.Empty;
		}
	}

	internal static void Rebuild()
	{
		categoryVegetationIds = new Dictionary<int, HashSet<int>>();
		for (int i = 1; i <= 6; i++)
		{
			categoryVegetationIds.Add(i, new HashSet<int>());
		}
		AddBundledGalacticScaleVegetation(categoryVegetationIds[6]);
		PlanetData localPlanet = GameMain.localPlanet;
		if (localPlanet != null && (Object)(object)LDB.themes != (Object)null)
		{
			AddThemeVegetation(((ProtoSet<ThemeProto>)(object)LDB.themes).Select(localPlanet.theme), categoryVegetationIds[1]);
		}
		HashSet<int> hashSet = new HashSet<int>();
		HashSet<string> hashSet2 = new HashSet<string>(KnownCustomGalacticScaleThemeNames, StringComparer.OrdinalIgnoreCase);
		HashSet<string> vanillaVegetationSignatures = CollectVanillaVegetationSignatures();
		int num = CollectDspAddPlanetThemeIds(hashSet);
		int num2 = CollectGalacticScaleLibrary(hashSet, hashSet2, categoryVegetationIds[6], vanillaVegetationSignatures);
		int[] array = new int[7];
		int num3 = 0;
		List<string> list = new List<string>();
		if ((Object)(object)LDB.themes != (Object)null && ((ProtoSet<ThemeProto>)(object)LDB.themes).dataArray != null)
		{
			ThemeProto[] dataArray = ((ProtoSet<ThemeProto>)(object)LDB.themes).dataArray;
			foreach (ThemeProto val in dataArray)
			{
				if (val == null)
				{
					continue;
				}
				bool flag = hashSet.Contains(((Proto)val).ID) || ContainsThemeName(hashSet2, ((Proto)val).Name) || ContainsThemeName(hashSet2, ((Proto)val).name);
				int num4 = (flag ? 6 : GetThemeCategory(val));
				bool flag2 = !flag || IsCustomVegetationSet(GetThemeVegetationIds(val), vanillaVegetationSignatures);
				if (flag2)
				{
					AddThemeVegetation(val, categoryVegetationIds[num4]);
					if (flag)
					{
						num3++;
					}
				}
				array[num4]++;
				list.Add($"{((Proto)val).ID}:{GetThemeDiagnosticName(val)}" + "->" + GetDiagnosticCategoryName(num4) + $"[{CountThemeVegetation(val)}]" + ((!flag) ? string.Empty : (flag2 ? "(GS-custom)" : "(GS-clone)")));
			}
		}
		string text = string.Join("; ", list.ToArray());
		if (!string.Equals(text, lastClassificationDiagnostic, StringComparison.Ordinal))
		{
			lastClassificationDiagnostic = text;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Vegetation theme classification: " + text));
			}
		}
		ManualLogSource log2 = Plugin.Log;
		if (log2 != null)
		{
			log2.LogInfo((object)("Vegetation categories rebuilt from vanilla theme IDs and external registries: " + $"bundled-gs-vegetation={BundledGalacticScaleVegetationIds.Length}, " + $"vanilla-organic-themes={array[2]}, " + $"vanilla-terrestrial-themes={array[3]}, " + $"vanilla-uninhabitable-themes={array[4]}, " + $"other-themes={array[5]}, " + $"gs-themes={array[6]}, " + $"gs-custom-vegetation-themes={num3}, " + $"dspaddplanet-registry={num}, " + $"gs-library={num2}; " + $"local={categoryVegetationIds[1].Count}, " + $"organic={categoryVegetationIds[2].Count}, " + $"terrestrial={categoryVegetationIds[3].Count}, " + $"uninhabitable={categoryVegetationIds[4].Count}, " + $"other={categoryVegetationIds[5].Count}, " + $"galactic-scale={categoryVegetationIds[6].Count}."));
		}
	}

	private static void AddBundledGalacticScaleVegetation(HashSet<int> vegetationIds)
	{
		int[] bundledGalacticScaleVegetationIds = BundledGalacticScaleVegetationIds;
		foreach (int item in bundledGalacticScaleVegetationIds)
		{
			vegetationIds.Add(item);
		}
	}

	internal static HashSet<int> CollectVegetationIds(int category)
	{
		if (categoryVegetationIds == null)
		{
			Rebuild();
		}
		if (!categoryVegetationIds.TryGetValue(category, out var value))
		{
			return new HashSet<int>();
		}
		return value;
	}

	private static int GetThemeCategory(ThemeProto theme)
	{
		if (theme == null)
		{
			return 5;
		}
		if (VanillaThemeCategoriesById.TryGetValue(((Proto)theme).ID, out var value) || TryGetVanillaThemeCategory(((Proto)theme).Name, out value) || TryGetVanillaThemeCategory(((Proto)theme).name, out value))
		{
			return value;
		}
		if (ContainsThemeName(KnownCustomGalacticScaleThemeNames, ((Proto)theme).Name) || ContainsThemeName(KnownCustomGalacticScaleThemeNames, ((Proto)theme).name))
		{
			return 6;
		}
		return 5;
	}

	private static bool TryGetVanillaThemeCategory(string themeName, out int category)
	{
		if (!string.IsNullOrWhiteSpace(themeName) && VanillaThemeCategoriesByName.TryGetValue(themeName.Trim(), out category))
		{
			return true;
		}
		category = 5;
		return false;
	}

	private static Dictionary<int, int> CreateVanillaThemeCategoriesById()
	{
		return new Dictionary<int, int>
		{
			[1] = 2,
			[2] = 5,
			[3] = 5,
			[4] = 5,
			[5] = 5,
			[6] = 3,
			[7] = 4,
			[8] = 2,
			[9] = 4,
			[10] = 4,
			[11] = 3,
			[12] = 3,
			[13] = 4,
			[14] = 2,
			[15] = 2,
			[16] = 2,
			[17] = 4,
			[18] = 2,
			[19] = 3,
			[20] = 4,
			[21] = 5,
			[22] = 2,
			[23] = 3,
			[24] = 4,
			[25] = 2
		};
	}

	private static Dictionary<string, int> CreateVanillaThemeCategoriesByName()
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
		AddThemes(dictionary, 2, "Ocean 1", "Ocean 2", "Ocean 3", "Ocean 4", "Ocean 5", "Ocean 6", "Desert 8", "Desert 11");
		AddThemes(dictionary, 3, "Desert 1", "Desert 3", "Desert 4", "Desert 6", "Desert 9");
		AddThemes(dictionary, 4, "Lava 1", "Volcanic 1", "Desert 5");
		AddThemes(dictionary, 4, "Desert 2", "Ice 1", "Desert 7", "Desert 10");
		AddThemes(dictionary, 5, "Gas 1", "Gas 2", "Gas 3", "Gas 4", "Gas 5");
		return dictionary;
	}

	private static HashSet<string> CreateVanillaGalacticScaleThemeNames()
	{
		return new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"Mediterranean", "GasGiant", "GasGiant2", "IceGiant", "IceGiant2", "AridDesert", "AshenGelisol", "OceanicJungle", "Lava", "IceGelisol",
			"Barren", "Gobi", "VolcanicAsh", "RedStone", "Prairie", "OceanWorld", "IceLake", "Hurricane", "SaltLake", "Sakura",
			"GasGiant3", "GasGiant4", "IceGiant3", "IceGiant4", "GasGiant5", "AridDesert2", "IceGelisol2", "IceGelisol3", "Savanna", "CrystalDesert",
			"FrozenTundra", "PandoraSwamp", "PandoraSwamp2"
		};
	}

	private static HashSet<string> CreateKnownCustomGalacticScaleThemeNames()
	{
		return new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"AridDesertsmol", "AridDesert2smol", "AshenGelisolsmol", "Barrensmol", "BarrenSatellite", "Beach", "BeachCold", "Center", "Comet", "Comet11",
			"Comet12", "Comet13", "Comet14", "CrystalDesertsmol", "DwarfPlanet", "FrozenTundrasmol", "GiganticForest", "GiganticForestCold", "Gobismol", "HotObsidian",
			"Hurricanesmol", "IceGelisolsmol", "IceGelisol2smol", "IceGelisol3smol", "IceLakesmol", "IceMalusol", "IceMalusmol", "Inferno", "Lavasmol", "MoltenWorld",
			"Obsidian", "OilGiant", "Pandora", "PandoraCold", "RedForest", "RedForestCold", "RemovedSmallPlanetTheme34", "RemovedSmallPlanetTheme35", "RemovedSmallPlanetTheme36", "SaltLakesmol",
			"SulfurSea", "VolcanicAshsmol", "AcidGreenhouse"
		};
	}

	private static void AddThemes(Dictionary<string, int> categories, int category, params string[] themeNames)
	{
		foreach (string key in themeNames)
		{
			categories.Add(key, category);
		}
	}

	private static int CollectDspAddPlanetThemeIds(HashSet<int> themeIds)
	{
		try
		{
			if (!((FindLoadedType("DSPAddPlanet.GalacticScaleThemeRegistry")?.GetProperty("ThemeNameToId", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null, null) is IEnumerable enumerable))
			{
				return 0;
			}
			foreach (object item in enumerable)
			{
				if (TryReadIntMember(item, "Value", out var value) && value > 0)
				{
					themeIds.Add(value);
				}
			}
			return themeIds.Count;
		}
		catch (Exception ex)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Could not read DspAddplanet's GalacticScale theme registry: " + ex.Message));
			}
			return 0;
		}
	}

	private static int CollectGalacticScaleLibrary(HashSet<int> customThemeIds, HashSet<string> customThemeNames, HashSet<int> vegetationIds, HashSet<string> vanillaVegetationSignatures)
	{
		try
		{
			if (!((FindLoadedType("GalacticScale.GSSettings")?.GetProperty("ThemeLibrary", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null, null) is IEnumerable enumerable))
			{
				return 0;
			}
			int num = 0;
			foreach (object item in enumerable)
			{
				object obj = ReadMember(item, "Key");
				object obj2 = ReadMember(item, "Value");
				if (obj2 == null)
				{
					continue;
				}
				num++;
				string text = obj as string;
				string text2 = ReadMember(obj2, "Name") as string;
				if ((!string.IsNullOrWhiteSpace(text) && !VanillaGalacticScaleThemeNames.Contains(text)) || (!string.IsNullOrWhiteSpace(text2) && !VanillaGalacticScaleThemeNames.Contains(text2)))
				{
					HashSet<int> hashSet = new HashSet<int>();
					AddReflectedThemeVegetation(obj2, hashSet);
					if (IsCustomVegetationSet(hashSet, vanillaVegetationSignatures))
					{
						vegetationIds.UnionWith(hashSet);
					}
					AddThemeName(customThemeNames, text);
					AddThemeName(customThemeNames, text2);
					if (TryReadIntMember(obj2, "LDBThemeId", out var value) && value > 25)
					{
						customThemeIds.Add(value);
					}
				}
			}
			return num;
		}
		catch (Exception ex)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Could not read GalacticScale's theme library: " + ex.Message));
			}
			return 0;
		}
	}

	private static Type FindLoadedType(string fullName)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			Type type = assemblies[i].GetType(fullName, throwOnError: false);
			if (type != null)
			{
				return type;
			}
		}
		return null;
	}

	private static object ReadMember(object instance, string memberName)
	{
		if (instance == null)
		{
			return null;
		}
		Type type = instance.GetType();
		PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (property != null)
		{
			return property.GetValue(instance, null);
		}
		return type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(instance);
	}

	private static bool TryReadIntMember(object instance, string memberName, out int value)
	{
		if (ReadMember(instance, memberName) is int num)
		{
			value = num;
			return true;
		}
		value = 0;
		return false;
	}

	private static void AddReflectedThemeVegetation(object theme, HashSet<int> vegetationIds)
	{
		for (int i = 0; i < 6; i++)
		{
			if (!(ReadMember(theme, "Vegetables" + i) is IEnumerable enumerable))
			{
				continue;
			}
			foreach (object item in enumerable)
			{
				if (item is int num && num > 0)
				{
					vegetationIds.Add(num);
				}
			}
		}
	}

	private static void AddThemeName(HashSet<string> names, string name)
	{
		if (!string.IsNullOrWhiteSpace(name))
		{
			names.Add(name.Trim());
		}
	}

	private static bool ContainsThemeName(HashSet<string> names, string name)
	{
		if (!string.IsNullOrWhiteSpace(name))
		{
			return names.Contains(name.Trim());
		}
		return false;
	}

	private static string GetThemeDiagnosticName(ThemeProto theme)
	{
		string text = ((!string.IsNullOrWhiteSpace(((Proto)theme).Name)) ? ((Proto)theme).Name : ((Proto)theme).name);
		string text2 = ((!string.IsNullOrWhiteSpace(theme.displayName)) ? theme.displayName : theme.DisplayName);
		if (!string.IsNullOrWhiteSpace(text2) && !string.Equals(text, text2, StringComparison.Ordinal))
		{
			return (text ?? "<unnamed>") + "/" + text2;
		}
		return text ?? "<unnamed>";
	}

	private static string GetDiagnosticCategoryName(int category)
	{
		return category switch
		{
			2 => "organic", 
			3 => "terrestrial", 
			4 => "uninhabitable", 
			6 => "galactic-scale", 
			_ => "other", 
		};
	}

	private static int CountThemeVegetation(ThemeProto theme)
	{
		return GetThemeVegetationIds(theme).Count;
	}

	private static HashSet<string> CollectVanillaVegetationSignatures()
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		if (((ProtoSet<ThemeProto>)(object)LDB.themes)?.dataArray == null)
		{
			return hashSet;
		}
		ThemeProto[] dataArray = ((ProtoSet<ThemeProto>)(object)LDB.themes).dataArray;
		foreach (ThemeProto val in dataArray)
		{
			if (val != null && VanillaThemeCategoriesById.ContainsKey(((Proto)val).ID))
			{
				hashSet.Add(GetVegetationSignature(GetThemeVegetationIds(val)));
			}
		}
		return hashSet;
	}

	private static bool IsCustomVegetationSet(HashSet<int> vegetationIds, HashSet<string> vanillaVegetationSignatures)
	{
		if (vegetationIds.Count > 0)
		{
			return !vanillaVegetationSignatures.Contains(GetVegetationSignature(vegetationIds));
		}
		return false;
	}

	private static string GetVegetationSignature(HashSet<int> vegetationIds)
	{
		int[] array = new int[vegetationIds.Count];
		vegetationIds.CopyTo(array);
		Array.Sort(array);
		return string.Join(",", array);
	}

	private static HashSet<int> GetThemeVegetationIds(ThemeProto theme)
	{
		HashSet<int> hashSet = new HashSet<int>();
		AddThemeVegetation(theme, hashSet);
		return hashSet;
	}

	private static void AddThemeVegetation(ThemeProto theme, HashSet<int> vegetationIds)
	{
		if (theme != null)
		{
			AddVegetationArray(theme.Vegetables0, vegetationIds);
			AddVegetationArray(theme.Vegetables1, vegetationIds);
			AddVegetationArray(theme.Vegetables2, vegetationIds);
			AddVegetationArray(theme.Vegetables3, vegetationIds);
			AddVegetationArray(theme.Vegetables4, vegetationIds);
			AddVegetationArray(theme.Vegetables5, vegetationIds);
		}
	}

	private static void AddVegetationArray(int[] source, HashSet<int> vegetationIds)
	{
		if (source == null)
		{
			return;
		}
		foreach (int num in source)
		{
			if (num > 0)
			{
				vegetationIds.Add(num);
			}
		}
	}
}
internal static class VegetationCategoryUi
{
	private static UISandboxMenu snapshotMenu;

	private static bool[] originalButtonActive;

	private static Sprite[] originalIcons;

	private static TipSettings[] originalTips;

	private static Text heading;

	private static string originalHeadingText;

	internal static bool TryApplyRegularChrome(UISandboxMenu menu, int selectedCategory, out string error)
	{
		//IL_0077: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		if (!TryCapture(menu, out error))
		{
			return false;
		}
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 1; i < menu.categoryButtons.Length; i++)
		{
			UIButton val = menu.categoryButtons[i];
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			bool flag = VegetationCategoryCatalog.IsCustomCategory(i);
			bool flag2 = i == 10;
			((Component)val).gameObject.SetActive(flag || flag2);
			val.highlighted = (flag2 ? (menu.currentCategory == 10) : (flag && menu.currentCategory == 3 && selectedCategory == i));
			if (flag)
			{
				TipSettings tips = val.tips;
				tips.tipTitle = VegetationCategoryCatalog.GetTitle(i);
				tips.tipText = string.Empty;
				val.tips = tips;
				int representativeId;
				Sprite val2 = FindRepresentativeSprite(VegetationCategoryCatalog.CollectVegetationIds(i), hashSet, out representativeId);
				if ((Object)(object)val2 != (Object)null)
				{
					hashSet.Add(representativeId);
				}
				menu.categoryIcons[i].sprite = val2 ?? originalIcons[i];
			}
		}
		heading.text = VegetationCategoryCatalog.GetTitle((!VegetationCategoryCatalog.IsCustomCategory(selectedCategory)) ? 1 : selectedCategory);
		return true;
	}

	internal static void RestoreNativeChrome(UISandboxMenu menu)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		if (snapshotMenu != menu || originalButtonActive == null || originalIcons == null || originalTips == null)
		{
			return;
		}
		int num = Math.Min(menu.categoryButtons.Length, originalButtonActive.Length);
		for (int i = 1; i < num; i++)
		{
			UIButton val = menu.categoryButtons[i];
			if (!((Object)(object)val == (Object)null))
			{
				((Component)val).gameObject.SetActive(originalButtonActive[i]);
				val.tips = originalTips[i];
				if (i < menu.categoryIcons.Length && (Object)(object)menu.categoryIcons[i] != (Object)null)
				{
					menu.categoryIcons[i].sprite = originalIcons[i];
				}
			}
		}
		if ((Object)(object)heading != (Object)null)
		{
			heading.text = originalHeadingText;
		}
	}

	internal static void HideCategoryButtons(UISandboxMenu menu)
	{
		if (menu?.categoryButtons == null)
		{
			return;
		}
		for (int i = 1; i < menu.categoryButtons.Length; i++)
		{
			UIButton val = menu.categoryButtons[i];
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}
	}

	internal static bool TrySetVegetationLayout(UISandboxMenu menu, Dictionary<int, UIButton> vegetationButtons, UIButton vegetationButtonPrefab, int selectedCategory, out string error)
	{
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: 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)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		if (!TryCapture(menu, out error))
		{
			return false;
		}
		if (vegetationButtons == null || menu.localVegeButtons == null || menu.otherVegeButtons == null || (Object)(object)menu.localVegeGroup == (Object)null || (Object)(object)menu.otherVegeGroup == (Object)null || (Object)(object)menu.vegeScrollViewConent == (Object)null)
		{
			error = "UISandboxMenu vegetation button storage or layout groups were not found.";
			return false;
		}
		if (!VegetationCategoryCatalog.IsCustomCategory(selectedCategory))
		{
			error = $"Unexpected vegetation category {selectedCategory}.";
			return false;
		}
		if (!EnsureBundledVegetationButtons(menu, vegetationButtons, vegetationButtonPrefab, out error))
		{
			return false;
		}
		HashSet<int> hashSet = VegetationCategoryCatalog.CollectVegetationIds(selectedCategory);
		List<int> orderedButtonIds = GetOrderedButtonIds(vegetationButtons);
		menu.localVegeButtons.Clear();
		menu.otherVegeButtons.Clear();
		((Component)menu.localVegeGroup).gameObject.SetActive(true);
		HideUnselectedVegetationGroup(menu);
		foreach (int item in orderedButtonIds)
		{
			UIButton val = vegetationButtons[item];
			if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).GetComponent<RectTransform>() == (Object)null)
			{
				error = $"Vegetation button {item} is incomplete.";
				return false;
			}
			if (hashSet.Contains(item))
			{
				PlaceButton(val, menu.localVegeGroup, menu.localVegeButtons);
			}
			else
			{
				PlaceButton(val, menu.otherVegeGroup, menu.otherVegeButtons);
			}
		}
		menu.localVegeGroup.sizeDelta = new Vector2(menu.localVegeGroup.sizeDelta.x, (float)((menu.localVegeButtons.Count / 12 + 1) * 50 + 40));
		menu.otherVegeGroup.sizeDelta = new Vector2(menu.otherVegeGroup.sizeDelta.x, (float)((menu.otherVegeButtons.Count / 12 + 1) * 50 + 40));
		menu.vegeScrollViewConent.anchoredPosition = new Vector2(menu.vegeScrollViewConent.anchoredPosition.x, 0f);
		heading.text = VegetationCategoryCatalog.GetTitle(selectedCategory);
		error = null;
		return true;
	}

	private static bool EnsureBundledVegetationButtons(UISandboxMenu menu, Dictionary<int, UIButton> vegetationButtons, UIButton vegetationButtonPrefab, out string error)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Invalid comparison between Unknown and I4
		if ((Object)(object)vegetationButtonPrefab == (Object)null)
		{
			error = "The native vegetation button prefab was not found.";
			return false;
		}
		foreach (int item in VegetationCategoryCatalog.CollectVegetationIds(6))
		{
			if (vegetationButtons.ContainsKey(item))
			{
				continue;
			}
			VegeProto val = ((ProtoSet<VegeProto>)(object)LDB.veges)?.Select(item);
			if (val == null || (Object)(object)val.iconSprite == (Object)null || (int)val.Type == 8)
			{
				continue;
			}
			UIButton val2 = Object.Instantiate<UIButton>(vegetationButtonPrefab, (Transform)(object)menu.otherVegeGroup);
			if ((Object)(object)val2 == (Object)null || ((Component)val2).transform.childCount == 0 || (Object)(object)((Component)((Component)val2).transform.GetChild(0)).GetComponent<Image>() == (Object)null)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val2).gameObject);
				}
				error = $"Could not create the native vegetation button for {item}.";
				return false;
			}
			((Component)((Component)val2).transform.GetChild(0)).GetComponent<Image>().sprite = val.iconSprite;
			val2.data = ((Proto)val).ID;
			((Component)val2).gameObject.SetActive(true);
			val2.onClick += menu.OnChildButtonClick;
			vegetationButtons.Add(((Proto)val).ID, val2);
		}
		error = null;
		return true;
	}

	internal static void HideUnselectedVegetationGroup(UISandboxMenu menu)
	{
		if ((Object)(object)menu?.otherVegeGroup != (Object)null)
		{
			((Component)menu.otherVegeGroup).gameObject.SetActive(false);
		}
	}

	internal static void UpdateScaleDisplay(int selectedCategory, bool hasSelectedVegetation, float scale)
	{
		if (!((Object)(object)heading == (Object)null) && VegetationCategoryCatalog.IsCustomCategory(selectedCategory))
		{
			string title = VegetationCategoryCatalog.GetTitle(selectedCategory);
			heading.text = (hasSelectedVegetation ? (title + (Localization.isZHCN ? " | 倍率 " : " | Scale ") + scale.ToString("0.00") + "x") : title);
		}
	}

	private static bool TryCapture(UISandboxMenu menu, out string error)
	{
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)menu == (Object)null || menu.categoryButtons == null || menu.categoryButtons.Length <= 6 || menu.categoryIcons == null || menu.categoryIcons.Length <= 6 || menu.categoryTips == null || menu.categoryTips.Length <= 6 || (Object)(object)menu.localVegeGroup == (Object)null)
		{
			error = "UISandboxMenu category slots 1-6 or the vegetation group were not found.";
			return false;
		}
		for (int i = 1; i <= 6; i++)
		{
			if ((Object)(object)menu.categoryButtons[i] == (Object)null || (Object)(object)menu.categoryIcons[i] == (Object)null || (Object)(object)menu.categoryTips[i] == (Object)null)
			{
				error = $"UISandboxMenu category slot {i} is incomplete.";
				return false;
			}
		}
		if (snapshotMenu == menu && originalButtonActive != null && (Object)(object)heading != (Object)null)
		{
			error = null;
			return true;
		}
		Text val = FindHeading(menu.localVegeGroup);
		if ((Object)(object)val == (Object)null)
		{
			error = "The native local-vegetation heading was not found.";
			return false;
		}
		snapshotMenu = menu;
		originalButtonActive = new bool[menu.categoryButtons.Length];
		originalIcons = (Sprite[])(object)new Sprite[menu.categoryButtons.Length];
		originalTips = (TipSettings[])(object)new TipSettings[menu.categoryButtons.Length];
		for (int j = 0; j < menu.categoryButtons.Length; j++)
		{
			UIButton val2 = menu.categoryButtons[j];
			if ((Object)(object)val2 != (Object)null)
			{
				originalButtonActive[j] = ((Component)val2).gameObject.activeSelf;
				originalTips[j] = val2.tips;
			}
			if (j < menu.categoryIcons.Length && (Object)(object)menu.categoryIcons[j] != (Object)null)
			{
				originalIcons[j] = menu.categoryIcons[j].sprite;
			}
		}
		heading = val;
		originalHeadingText = heading.text;
		error = null;
		return true;
	}

	private static Text FindHeading(RectTransform group)
	{
		Text[] componentsInChildren = ((Component)group).GetComponentsInChildren<Text>(true);
		foreach (Text val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform.parent == (Object)(object)group)
			{
				return val;
			}
		}
		return null;
	}

	private static List<int> GetOrderedButtonIds(Dictionary<int, UIButton> buttons)
	{
		List<int> list = new List<int>(buttons.Count);
		HashSet<int> hashSet = new HashSet<int>();
		if ((Object)(object)LDB.veges != (Object)null && ((ProtoSet<VegeProto>)(object)LDB.veges).dataArray != null)
		{
			VegeProto[] dataArray = ((ProtoSet<VegeProto>)(object)LDB.veges).dataArray;
			foreach (VegeProto val in dataArray)
			{
				if (val != null && buttons.ContainsKey(((Proto)val).ID) && hashSet.Add(((Proto)val).ID))
				{
					list.Add(((Proto)val).ID);
				}
			}
		}
		foreach (int key in buttons.Keys)
		{
			if (hashSet.Add(key))
			{
				list.Add(key);
			}
		}
		return list;
	}

	private static Sprite FindRepresentativeSprite(HashSet<int> vegetationIds, HashSet<int> excludedIds, out int representativeId)
	{
		representativeId = 0;
		if ((Object)(object)LDB.veges == (Object)null || ((ProtoSet<VegeProto>)(object)LDB.veges).dataArray == null)
		{
			return null;
		}
		return FindRepresentativeSprite(vegetationIds, excludedIds, out representativeId, excludeUsed: true) ?? FindRepresentativeSprite(vegetationIds, excludedIds, out representativeId, excludeUsed: false);
	}

	private static Sprite FindRepresentativeSprite(HashSet<int> vegetationIds, HashSet<int> excludedIds, out int representativeId, bool excludeUsed)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Invalid comparison between Unknown and I4
		representativeId = 0;
		VegeProto[] dataArray = ((ProtoSet<VegeProto>)(object)LDB.veges).dataArray;
		for (int i = 90; i < dataArray.Length; i++)
		{
			VegeProto val = dataArray[i];
			if (val != null && vegetationIds.Contains(((Proto)val).ID) && (!excludeUsed || !excludedIds.Contains(((Proto)val).ID)) && (Object)(object)val.iconSprite != (Object)null && (int)val.Type != 8)
			{
				representativeId = ((Proto)val).ID;
				return val.iconSprite;
			}
		}
		return null;
	}

	private static void PlaceButton(UIButton button, RectTransform group, List<UIButton> destination)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		((Component)button).transform.SetParent((Transform)(object)group);
		((Component)button).GetComponent<RectTransform>().anchoredPosition = new Vector2((float)(destination.Count % 12 * 50), (float)(-(destination.Count / 12) * 50 - 36));
		destination.Add(button);
	}
}
[HarmonyPatch]
internal static class VegetationModePatches
{
	private static readonly MethodInfo SandboxToolsGetter = AccessTools.PropertyGetter(typeof(GameMain), "sandboxToolsEnabled");

	private static readonly MethodInfo VegetationAvailabilityMethod = AccessTools.Method(typeof(VegetationModePatches), "IsVegetationToolAvailable", (Type[])null, (Type[])null);

	private static readonly MethodInfo VectorOneGetter = AccessTools.PropertyGetter(typeof(Vector3), "one");

	private static readonly MethodInfo VegetationScaleVectorMethod = AccessTools.Method(typeof(VegetationModePatches), "GetVegetationScaleVector", (Type[])null, (Type[])null);

	private const float DefaultVegetationScaleStep = 0.1f;

	private const float ShiftVegetationScaleStep = 0.5f;

	private const float ControlVegetationScaleStep = 0.01f;

	private const float MinimumVegetationScale = 0.1f;

	private const float MaximumVegetationScale = 30f;

	private const float VegetationScaleRepeatDelay = 0.3f;

	private const float VegetationScaleRepeatInterval = 0.08f;

	private static bool runtimeDisabled;

	private static bool runtimeErrorLogged;

	private static int selectedVegetationCategory;

	private static int scaledVegetationProtoId;

	private static float vegetationScale = 1f;

	private static KeyCode heldVegetationScaleKey = (KeyCode)0;

	private static float nextVegetationScaleRepeatTime;

	internal static void ValidateTargets()
	{
		runtimeDisabled = false;
		runtimeErrorLogged = false;
		scaledVegetationProtoId = 0;
		vegetationScale = 1f;
		ResetVegetationScaleInput();
		RequireMethod(typeof(UIFunctionPanel), "_OnUpdate");
		RequireMethod(typeof(UIGame), "_OnUpdate");
		RequireMethod(typeof(PlayerAction_Plant), "DetermineActive");
		RequireMethod(typeof(UISandboxMenu), "_OnOpen");
		RequireMethod(typeof(UISandboxMenu), "_OnUpdate");
		RequireMethod(typeof(UISandboxMenu), "SetCurrentCategory");
		RequireMethod(typeof(UISandboxMenu), "SetVegeLayout");
		RequireMethod(typeof(UISandboxMenu), "OnCategoryButtonClick");
		RequireMethod(typeof(UISandboxMenu), "OnChildButtonClick");
		RequireMethod(typeof(PlayerAction_Plant), "SetHandVein");
		RequireMethod(typeof(PlayerAction_Plant), "SetHandVege");
		RequireMethod(typeof(PlayerAction_Plant), "SetRemovalMode");
		RequireMethod(typeof(PlayerAction_Plant), "DeterminePlantPreview");
		RequireMethod(typeof(PlayerAction_Plant), "DetermineRemovePreviews");
		RequireMethod(typeof(PlayerAction_Plant), "PlantVeinFinally");
		RequireMethod(typeof(PlayerAction_Plant), "PlantVegeFinally");
		RequireMethod(typeof(PlayerControlGizmo), "SetPlantPreviewGizmo");
		RequireField(typeof(UISandboxMenu), "vegeButtonDic");
		RequireField(typeof(UISandboxMenu), "vegeButtonPrefab");
		RequireField(typeof(UISandboxMenu), "lastTheme");
		RequireField(typeof(UISandboxMenu), "actionPlant");
		RequireField(typeof(UISandboxMenu), "veinFilterToggle");
		RequireField(typeof(UISandboxMenu), "vegeFilterToggle");
		RequireField(typeof(PlayerControlGizmo), "plantPreviewGizmo");
		if (SandboxToolsGetter == null || VegetationAvailabilityMethod == null || VectorOneGetter == null || VegetationScaleVectorMethod == null)
		{
			throw new MissingMethodException("The sandbox permission getter or its replacement was not found.");
		}
		RequireSandboxCheckCount(typeof(UIFunctionPanel), "_OnUpdate", 3);
		RequireSandboxCheckCount(typeof(UIGame), "_OnUpdate", 1);
		RequireSandboxCheckCount(typeof(PlayerAction_Plant), "DetermineActive", 1);
	}

	private static void RequireMethod(Type type, string methodName)
	{
		if (AccessTools.Method(type, methodName, (Type[])null, (Type[])null) == null)
		{
			throw new MissingMethodException(type.FullName, methodName);
		}
	}

	private static void RequireField(Type type, string fieldName)
	{
		if (AccessTools.Field(type, fieldName) == null)
		{
			throw new MissingFieldException(type.FullName, fieldName);
		}
	}

	private static void RequireSandboxCheckCount(Type type, string methodName, int expectedCount)
	{
		MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		int num = 0;
		foreach (CodeInstruction originalInstruction in PatchProcessor.GetOriginalInstructions((MethodBase)methodInfo, (ILGenerator)null))
		{
			if ((originalInstruction.opcode == OpCodes.Call || originalInstruction.opcode == OpCodes.Callvirt) && object.Equals(originalInstruction.operand, SandboxToolsGetter))
			{
				num++;
			}
		}
		if (num != expectedCount)
		{
			throw new InvalidOperationException($"{type.FullName}.{methodName} contained {num} sandbox checks; " + $"expected {expectedCount}.");
		}
	}

	private static bool IsVegetationToolAvailable()
	{
		if (GameMain.sandboxToolsEnabled)
		{
			return true;
		}
		if (runtimeDisabled)
		{
			return false;
		}
		GameData data = GameMain.data;
		if (data != null && data.gameDesc != null)
		{
			return !data.gameDesc.isSandboxMode;
		}
		return false;
	}

	private static bool IsVegetationOnlyMode()
	{
		if (IsVegetationToolAvailable())
		{
			return !GameMain.sandboxToolsEnabled;
		}
		return false;
	}

	private static bool ShouldRestrictSandboxTools()
	{
		GameData data = GameMain.data;
		if (!GameMain.sandboxToolsEnabled && data != null && data.gameDesc != null)
		{
			return !data.gameDesc.isSandboxMode;
		}
		return false;
	}

	private static bool IsAllowedCategory(int category)
	{
		if (!ShouldRestrictSandboxTools())
		{
			return true;
		}
		if (category != 0 && category != 10)
		{
			if (!runtimeDisabled)
			{
				return category == 3;
			}
			return false;
		}
		return true;
	}

	private static Vector3 GetVegetationScaleVector()
	{
		//IL_000d: 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_0007: Unknown result type (might be due to invalid IL or missing references)
		if (!ShouldRestrictSandboxTools())
		{
			return Vector3.one;
		}
		return Vector3.one * vegetationScale;
	}

	private static void ConfigureVegetationRemoval(PlayerAction_Plant actionPlant)
	{
		if (actionPlant != null && ShouldRestrictSandboxTools())
		{
			actionPlant.veinRemovalFilter = false;
			actionPlant.vegeRemovalFilter = true;
		}
	}

	private static void UpdateVegetationScaleInput(PlayerAction_Plant actionPlant)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Invalid comparison between Unknown and I4
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		if (!ShouldRestrictSandboxTools() || actionPlant == null || actionPlant.handVegeProtoId <= 0 || actionPlant.handPlantPreview == null || VFInput.onGUI || VFInput.inputing || !Application.isFocused)
		{
			ResetVegetationScaleInput();
			return;
		}
		bool key = Input.GetKey((KeyCode)113);
		bool key2 = Input.GetKey((KeyCode)101);
		if (key == key2)
		{
			ResetVegetationScaleInput();
			return;
		}
		KeyCode val = (KeyCode)(key ? 113 : 101);
		bool increase = (int)val == 113;
		float unscaledTime = Time.unscaledTime;
		if (Input.GetKeyDown(val) && heldVegetationScaleKey != val)
		{
			heldVegetationScaleKey = val;
			nextVegetationScaleRepeatTime = unscaledTime + 0.3f;
			ApplyVegetationScaleStep(increase);
		}
		else if (heldVegetationScaleKey == val && !(unscaledTime < nextVegetationScaleRepeatTime))
		{
			nextVegetationScaleRepeatTime = unscaledTime + 0.08f;
			ApplyVegetationScaleStep(increase);
		}
	}

	private static void ApplyVegetationScaleStep(bool increase)
	{
		bool controlHeld = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
		bool shiftHeld = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
		float vegetationScaleStep = GetVegetationScaleStep(controlHeld, shiftHeld);
		vegetationScale = AdjustVegetationScale(vegetationScale, increase, vegetationScaleStep);
	}

	private static float GetVegetationScaleStep(bool controlHeld, bool shiftHeld)
	{
		if (controlHeld)
		{
			return 0.01f;
		}
		if (!shiftHeld)
		{
			return 0.1f;
		}
		return 0.5f;
	}

	private static float AdjustVegetationScale(float currentScale, bool increase, float step)
	{
		return Mathf.Clamp(Mathf.Round((currentScale + (increase ? step : (0f - step))) * 100f) / 100f, 0.1f, 30f);
	}

	private static void ResetVegetationScaleInput()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		heldVegetationScaleKey = (KeyCode)0;
		nextVegetationScaleRepeatTime = 0f;
	}

	private static IEnumerable<CodeInstruction> ReplaceSandboxChecks(IEnumerable<CodeInstruction> instructions, int expectedCount, string targetName)
	{
		int replacedCount = 0;
		foreach (CodeInstruction instruction in instructions)
		{
			if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && object.Equals(instruction.operand, SandboxToolsGetter))
			{
				instruction.opcode = OpCodes.Call;
				instruction.operand = VegetationAvailabilityMethod;
				replacedCount++;
			}
			yield return instruction;
		}
		if (replacedCount != expectedCount)
		{
			throw new InvalidOperationException($"{targetName} contained {replacedCount} sandbox checks; expected {expectedCount}. " + "The game method has changed, so the patch was not applied.");
		}
	}

	[HarmonyTranspiler]
	[HarmonyPatch(typeof(UIFunctionPanel), "_OnUpdate")]
	private static IEnumerable<CodeInstruction> UIFunctionPanelOnUpdateTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return ReplaceSandboxChecks(instructions, 3, "UIFunctionPanel._OnUpdate");
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(UIFunctionPanel), "_OnUpdate")]
	private static void UIFunctionPanelOnUpdatePostfix(UIFunctionPanel __instance)
	{
		if (IsVegetationOnlyMode())
		{
			GameHistoryData history = GameMain.history;
			Player mainPlayer = GameMain.mainPlayer;
			bool flag = history != null && mainPlayer != null && !history.TechUnlocked(1001) && !mainPlayer.sailing && !__instance.showSandBoxMenu;
			if (__instance.needResearchTipGroup.activeSelf != flag)
			{
				__instance.needResearchTipGroup.SetActive(flag);
			}
		}
	}

	[HarmonyTranspiler]
	[HarmonyPatch(typeof(UIGame), "_OnUpdate")]
	private static IEnumerable<CodeInstruction> UIGameOnUpdateTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return ReplaceSandboxChecks(instructions, 1, "UIGame._OnUpdate");
	}

	[HarmonyTranspiler]
	[HarmonyPatch(typeof(PlayerAction_Plant), "DetermineActive")]
	private static IEnumerable<CodeInstruction> DetermineActiveTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return ReplaceSandboxChecks(instructions, 1, "PlayerAction_Plant.DetermineActive");
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "DetermineActive")]
	private static void DetermineActivePostfix(PlayerAction_Plant __instance, ref bool __result)
	{
		if (ShouldRestrictSandboxTools() && __instance.handVeinProtoId > 0)
		{
			__instance.SetHandVein(0);
			__result = false;
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "SetHandVege")]
	private static void SetHandVegePostfix(PlayerAction_Plant __instance, int vegeProtoId)
	{
		if (!ShouldRestrictSandboxTools())
		{
			ResetVegetationScaleInput();
		}
		else if (vegeProtoId <= 0 || __instance.handVegeProtoId <= 0)
		{
			scaledVegetationProtoId = 0;
			vegetationScale = 1f;
			ResetVegetationScaleInput();
		}
		else if (scaledVegetationProtoId != __instance.handVegeProtoId)
		{
			scaledVegetationProtoId = __instance.handVegeProtoId;
			vegetationScale = 1f;
			ResetVegetationScaleInput();
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "DeterminePlantPreview")]
	private static void DeterminePlantPreviewPostfix(PlayerAction_Plant __instance)
	{
		UpdateVegetationScaleInput(__instance);
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "DetermineRemovePreviews")]
	private static void DetermineRemovePreviewsPrefix(PlayerAction_Plant __instance)
	{
		ConfigureVegetationRemoval(__instance);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(PlayerControlGizmo), "SetPlantPreviewGizmo")]
	private static void SetPlantPreviewGizmoPostfix(ModelPreview preview, ModelGizmo ___plantPreviewGizmo)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		if (ShouldRestrictSandboxTools() && preview != null && preview.vegeProtoId > 0 && (Object)(object)___plantPreviewGizmo != (Object)null)
		{
			((Component)___plantPreviewGizmo).transform.localScale = GetVegetationScaleVector();
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(UISandboxMenu), "_OnOpen")]
	private static void SandboxMenuOnOpenPostfix(UISandboxMenu __instance)
	{
		selectedVegetationCategory = 0;
		ApplyMenuMode(__instance);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(UISandboxMenu), "_OnUpdate")]
	private static void SandboxMenuOnUpdatePostfix(UISandboxMenu __instance, PlayerAction_Plant ___actionPlant, UIToggle ___veinFilterToggle, UIToggle ___vegeFilterToggle)
	{
		if (IsVegetationOnlyMode() && __instance.currentCategory == 3 && VegetationCategoryCatalog.IsCustomCategory(selectedVegetationCategory))
		{
			VegetationCategoryUi.HideUnselectedVegetationGroup(__instance);
			VegetationCategoryUi.UpdateScaleDisplay(selectedVegetationCategory, ___actionPlant != null && ___actionPlant.handVegeProtoId > 0, vegetationScale);
		}
		if (IsVegetationOnlyMode() && __instance.currentCategory == 10)
		{
			ConfigureVegetationRemoval(___actionPlant);
			if ((Object)(object)___veinFilterToggle != (Object)null)
			{
				___veinFilterToggle.isOn = false;
				if ((Object)(object)___veinFilterToggle.toggle != (Object)null)
				{
					((Selectable)___veinFilterToggle.toggle).interactable = false;
				}
			}
			if ((Object)(object)___vegeFilterToggle != (Object)null)
			{
				___vegeFilterToggle.isOn = true;
				if ((Object)(object)___vegeFilterToggle.toggle != (Object)null)
				{
					((Selectable)___vegeFilterToggle.toggle).interactable = false;
				}
			}
		}
		else if (!IsVegetationOnlyMode())
		{
			if ((Object)(object)___veinFilterToggle?.toggle != (Object)null)
			{
				((Selectable)___veinFilterToggle.toggle).interactable = true;
			}
			if ((Object)(object)___vegeFilterToggle?.toggle != (Object)null)
			{
				((Selectable)___vegeFilterToggle.toggle).interactable = true;
			}
		}
	}

	private static void ApplyMenuMode(UISandboxMenu menu)
	{
		if (GameMain.sandboxToolsEnabled)
		{
			VegetationCategoryUi.RestoreNativeChrome(menu);
			return;
		}
		if (!IsVegetationOnlyMode())
		{
			VegetationCategoryUi.HideCategoryButtons(menu);
			return;
		}
		VegetationCategoryCatalog.Rebuild();
		if (!VegetationCategoryUi.TryApplyRegularChrome(menu, selectedVegetationCategory, out var error))
		{
			DisableAtRuntime(menu, error);
		}
	}

	private static void DisableAtRuntime(UISandboxMenu menu, string reason)
	{
		runtimeDisabled = true;
		selectedVegetationCategory = 0;
		menu.SetCurrentCategory(0);
		VegetationCategoryUi.HideCategoryButtons(menu);
		if (!runtimeErrorLogged)
		{
			runtimeErrorLogged = true;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogError((object)("The native vegetation category UI was incompatible. Normal-mode vegetation placement has been disabled. " + reason));
			}
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(UISandboxMenu), "SetCurrentCategory")]
	private static bool SetCurrentCategoryPrefix(int category)
	{
		return IsAllowedCategory(category);
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(UISandboxMenu), "OnCategoryButtonClick")]
	private static bool OnCategoryButtonClickPrefix(UISandboxMenu __instance, int index)
	{
		if (!ShouldRestrictSandboxTools())
		{
			return true;
		}
		if (index == 10)
		{
			selectedVegetationCategory = 0;
			return true;
		}
		if (runtimeDisabled || !VegetationCategoryCatalog.IsCustomCategory(index))
		{
			return false;
		}
		bool flag = __instance.currentCategory == 3 && selectedVegetationCategory == index;
		selectedVegetationCategory = ((!flag) ? index : 0);
		__instance.SetCurrentCategory((!flag) ? 3 : 0);
		if (!IsVegetationOnlyMode())
		{
			return false;
		}
		if (!VegetationCategoryUi.TryApplyRegularChrome(__instance, selectedVegetationCategory, out var error))
		{
			DisableAtRuntime(__instance, error);
		}
		return false;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(UISandboxMenu), "SetVegeLayout")]
	private static bool SetVegeLayoutPrefix(UISandboxMenu __instance, Dictionary<int, UIButton> ___vegeButtonDic, UIButton ___vegeButtonPrefab, ref int ___lastTheme)
	{
		if (!IsVegetationOnlyMode())
		{
			return true;
		}
		___lastTheme = 0;
		if (!VegetationCategoryUi.TrySetVegetationLayout(__instance, ___vegeButtonDic, ___vegeButtonPrefab, selectedVegetationCategory, out var error))
		{
			DisableAtRuntime(__instance, error);
		}
		return false;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(UISandboxMenu), "OnChildButtonClick")]
	private static bool OnChildButtonClickPrefix(UISandboxMenu __instance)
	{
		if (ShouldRestrictSandboxTools())
		{
			if (!runtimeDisabled)
			{
				return __instance.currentCategory == 3;
			}
			return false;
		}
		return true;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "SetHandVein")]
	private static bool SetHandVeinPrefix(int veinProtoId)
	{
		if (ShouldRestrictSandboxTools())
		{
			return veinProtoId == 0;
		}
		return true;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "SetRemovalMode")]
	private static void SetRemovalModePostfix(PlayerAction_Plant __instance)
	{
		ConfigureVegetationRemoval(__instance);
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(PlayerAction_Plant), "PlantVeinFinally")]
	private static bool PlantVeinFinallyPrefix()
	{
		return !ShouldRestrictSandboxTools();
	}

	[HarmonyTranspiler]
	[HarmonyPatch(typeof(PlayerAction_Plant), "PlantVegeFinally")]
	private static IEnumerable<CodeInstruction> PlantVegeFinallyTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		int replacedCount = 0;
		foreach (CodeInstruction instruction in instructions)
		{
			if (CodeInstructionExtensions.Calls(instruction, VectorOneGetter))
			{
				instruction.opcode = OpCodes.Call;
				instruction.operand = VegetationScaleVectorMethod;
				replacedCount++;
			}
			yield return instruction;
		}
		if (replacedCount != 2)
		{
			throw new InvalidOperationException("PlayerAction_Plant.PlantVegeFinally contained " + $"{replacedCount} vegetation scale initializers; expected 2. " + "The game method has changed, so scalable vegetation was not enabled.");
		}
	}
}