Decompiled source of PlantGrass v1.4.0

PlantGrass.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AskaShared;
using AskaShared.Game;
using AwesomeTechnologies.VegetationSystem;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using SSSGame;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("PlantGrass")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.0")]
[assembly: AssemblyInformationalVersion("1.4.0+bfef70ed95f3ab2eb3f9d24c531617dc8fe22d25")]
[assembly: AssemblyProduct("Plant Grass")]
[assembly: AssemblyTitle("PlantGrass")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AskaPlantGrass
{
	[HarmonyPatch(typeof(PlayerCharacter))]
	public static class CharacterSpawnPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Spawned")]
		public static void Spawned(Character __instance)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			LocalPlayerTool.AttachOnSpawn(__instance, Plugin.Log, "AskaPlantGrass_Tool", new Vector3(0f, 0f, 2f), typeof(HeightmapTool), typeof(PlantGrassTool));
		}
	}
	internal static class MenuGate
	{
		internal static bool IsUiCapturingInput()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			try
			{
				return Cursor.visible || (int)Cursor.lockState != 1;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(44, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlantGrass: reading the cursor state threw: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
				return false;
			}
		}
	}
	public class PlantGrassTool : MonoBehaviour
	{
		private const float FootprintMargin = 0.3f;

		private const float FarmMargin = 0.3f;

		private HeightmapTool _heightmapTool;

		private string _lastPaintError;

		private bool _invalidBiomeLogged;

		private void Start()
		{
			_heightmapTool = ((Component)this).GetComponent<HeightmapTool>();
			if ((Object)(object)_heightmapTool == (Object)null)
			{
				Plugin.Log.LogError((object)"PlantGrassTool: HeightmapTool component missing!");
			}
		}

		private void OnDestroy()
		{
			RetentionWindow.ForceClose();
		}

		private void Update()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Expected O, but got Unknown
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_022f: 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_015d: 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)
			RetentionWindow.Tick();
			if ((Object)(object)_heightmapTool == (Object)null || !Plugin.ConfigEnabled.Value || !Input.GetKeyDown(Plugin.ConfigKey.Value) || MenuGate.IsUiCapturingInput())
			{
				return;
			}
			bool flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
			bool flag2 = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307);
			if (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305))
			{
				CycleBiome((!flag) ? 1 : (-1));
				return;
			}
			if (flag2)
			{
				AdjustRadius(flag ? (-0.5f) : 0.5f);
				return;
			}
			bool flag3 = default(bool);
			try
			{
				Vector3 position = ((Component)this).transform.position;
				RetentionWindow.Open();
				if (flag)
				{
					TerraformingToolResult val = Paint(position, (TerrainType)0, clearVegetation: true);
					TerraformingToolResult val2 = Paint(position, (TerrainType)1, clearVegetation: true);
					if ((int)val == 0 || (int)val2 == 0)
					{
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(14, 1, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Lawn laid at ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Vector3>(position);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
						}
						log.LogInfo(val3);
					}
					else
					{
						ManualLogSource log2 = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(36, 3, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Lawn not laid at ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Vector3>(position);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" (natural=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<TerraformingToolResult>(val);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", dirt=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<TerraformingToolResult>(val2);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(").");
						}
						log2.LogInfo(val3);
					}
				}
				else
				{
					TerraformingToolResult val4 = Paint(position, (TerrainType)1, clearVegetation: false);
					if ((int)val4 == 0)
					{
						ManualLogSource log3 = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(19, 1, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Grass restored at ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Vector3>(position);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
						}
						log3.LogInfo(val3);
					}
					else
					{
						ManualLogSource log4 = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(26, 2, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Grass not restored at ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Vector3>(position);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" (");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<TerraformingToolResult>(val4);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(").");
						}
						log4.LogInfo(val3);
					}
				}
				RestoreFootprints(position, Plugin.ConfigRadius.Value);
			}
			catch (Exception ex)
			{
				string text = ex.ToString();
				if (!(text != _lastPaintError))
				{
					return;
				}
				_lastPaintError = text;
				ManualLogSource log5 = Plugin.Log;
				if (log5 != null)
				{
					BepInExWarningLogInterpolatedStringHandler val5 = new BepInExWarningLogInterpolatedStringHandler(65, 1, ref flag3);
					if (flag3)
					{
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("PlantGrass: paint failed (repeats of this error are suppressed): ");
						((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<Exception>(ex);
					}
					log5.LogWarning(val5);
				}
			}
		}

		private TerraformingToolResult Paint(Vector3 position, TerrainType sourceType, bool clearVegetation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			List<Rect> holes = CollectFootprintRects(position, Plugin.ConfigRadius.Value, wantFarms: true);
			_heightmapTool.radius = Plugin.ConfigRadius.Value;
			_heightmapTool.clearVegetation = clearVegetation;
			_heightmapTool.setVegetationMask = true;
			_heightmapTool.checkItemInstances = false;
			_heightmapTool.setTerrainType = true;
			_heightmapTool.terrainType = (TerrainType)0;
			_heightmapTool.requiresTerrainType = true;
			_heightmapTool.requiredTerrainType = sourceType;
			_heightmapTool.biasTerraformingWeights = true;
			_heightmapTool.setBiomeType = Plugin.ConfigPaintBiome.Value;
			_heightmapTool.biomeType = ResolveBiomeType();
			_heightmapTool.propagateOnNetwork = true;
			_heightmapTool.updateNavigation = false;
			return PaintExcludingRects(position, Plugin.ConfigRadius.Value, holes);
		}

		private TerraformingToolResult PaintExcludingRects(Vector3 center, float radius, List<Rect> holes)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			float num = center.x - radius;
			float num2 = center.x + radius;
			float num3 = center.z - radius;
			float num4 = center.z + radius;
			if (holes.Count == 0)
			{
				return _heightmapTool.RunOnArea((TerraformingToolOperation)3, num2 - num, num4 - num3, 0f, center, 0f);
			}
			List<float> list = new List<float> { num, num2 };
			List<float> list2 = new List<float> { num3, num4 };
			foreach (Rect hole in holes)
			{
				Rect current = hole;
				AddCut(list, ((Rect)(ref current)).xMin, num, num2);
				AddCut(list, ((Rect)(ref current)).xMax, num, num2);
				AddCut(list2, ((Rect)(ref current)).yMin, num3, num4);
				AddCut(list2, ((Rect)(ref current)).yMax, num3, num4);
			}
			list.Sort();
			list2.Sort();
			TerraformingToolResult result = (TerraformingToolResult)2;
			bool flag = false;
			Vector3 val = default(Vector3);
			for (int i = 0; i < list.Count - 1; i++)
			{
				float num5 = list[i];
				float num6 = list[i + 1];
				float num7 = num6 - num5;
				if (num7 <= 0.01f)
				{
					continue;
				}
				for (int j = 0; j < list2.Count - 1; j++)
				{
					float num8 = list2[j];
					float num9 = list2[j + 1];
					float num10 = num9 - num8;
					if (num10 <= 0.01f)
					{
						continue;
					}
					float num11 = (num5 + num6) * 0.5f;
					float num12 = (num8 + num9) * 0.5f;
					if (!InAnyRect(holes, num11, num12))
					{
						((Vector3)(ref val))..ctor(num11, center.y, num12);
						TerraformingToolResult val2 = _heightmapTool.RunOnArea((TerraformingToolOperation)3, num7, num10, 0f, val, 0f);
						if ((int)val2 == 0)
						{
							flag = true;
						}
						else if (!flag)
						{
							result = val2;
						}
					}
				}
			}
			if (!flag)
			{
				return result;
			}
			return (TerraformingToolResult)0;
		}

		private static void AddCut(List<float> cuts, float value, float lo, float hi)
		{
			if (value > lo + 0.01f && value < hi - 0.01f)
			{
				cuts.Add(value);
			}
		}

		private static bool InAnyRect(List<Rect> rects, float x, float z)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			foreach (Rect rect in rects)
			{
				Rect current = rect;
				if (x > ((Rect)(ref current)).xMin && x < ((Rect)(ref current)).xMax && z > ((Rect)(ref current)).yMin && z < ((Rect)(ref current)).yMax)
				{
					return true;
				}
			}
			return false;
		}

		private void RestoreFootprints(Vector3 center, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			List<Rect> list = CollectFootprintRects(center, radius, wantFarms: false);
			if (list.Count == 0)
			{
				return;
			}
			_heightmapTool.clearVegetation = true;
			_heightmapTool.setVegetationMask = true;
			_heightmapTool.checkItemInstances = false;
			_heightmapTool.setTerrainType = true;
			_heightmapTool.terrainType = (TerrainType)1;
			_heightmapTool.requiresTerrainType = false;
			_heightmapTool.setBiomeType = false;
			_heightmapTool.biasTerraformingWeights = true;
			_heightmapTool.propagateOnNetwork = true;
			_heightmapTool.updateNavigation = false;
			Vector3 val = default(Vector3);
			foreach (Rect item in list)
			{
				Rect current = item;
				((Vector3)(ref val))..ctor(((Rect)(ref current)).center.x, center.y, ((Rect)(ref current)).center.y);
				_heightmapTool.RunOnArea((TerraformingToolOperation)3, ((Rect)(ref current)).width, ((Rect)(ref current)).height, 0f, val, 0f);
			}
		}

		private static List<Rect> CollectFootprintRects(Vector3 center, float radius, bool wantFarms)
		{
			//IL_0014: 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)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			List<Rect> list = new List<Rect>();
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(radius, 10f, radius);
			foreach (Collider item in (Il2CppArrayBase<Collider>)(object)Physics.OverlapBox(center, val, Quaternion.identity, -1, (QueryTriggerInteraction)2))
			{
				if (!((Component)item).CompareTag(Structure.c_FootprintTag))
				{
					continue;
				}
				Structure componentInParent = ((Component)item).GetComponentInParent<Structure>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					continue;
				}
				bool flag = (Object)(object)((Component)componentInParent).GetComponentInChildren<FarmCropGrid>() != (Object)null;
				if (flag == wantFarms)
				{
					float num = (flag ? 0.3f : 0.3f);
					Bounds bounds = item.bounds;
					float num2 = Mathf.Max(((Bounds)(ref bounds)).min.x - num, center.x - radius);
					float num3 = Mathf.Min(((Bounds)(ref bounds)).max.x + num, center.x + radius);
					float num4 = Mathf.Max(((Bounds)(ref bounds)).min.z - num, center.z - radius);
					float num5 = Mathf.Min(((Bounds)(ref bounds)).max.z + num, center.z + radius);
					if (!(num3 - num2 <= 0.01f) && !(num5 - num4 <= 0.01f))
					{
						list.Add(new Rect(num2, num4, num3 - num2, num5 - num4));
					}
				}
			}
			return list;
		}

		private BiomeType ResolveBiomeType()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected I4, but got Unknown
			BiomeType value = Plugin.ConfigBiome.Value;
			if (Enum.IsDefined(typeof(BiomeType), value))
			{
				return value;
			}
			if (!_invalidBiomeLogged)
			{
				_invalidBiomeLogged = true;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(74, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlantGrass: configured Biome '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>((int)value);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' is not a defined BiomeType; using Default.");
					}
					log.LogWarning(val);
				}
			}
			return (BiomeType)0;
		}

		private void AdjustRadius(float delta)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			float num = Mathf.Clamp(Plugin.ConfigRadius.Value + delta, 0.5f, 30f);
			Plugin.ConfigRadius.Value = num;
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(22, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Paint radius set to ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num, "F1");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("m.");
			}
			log.LogInfo(val);
			ShowToast($"Paint radius: {num:F1}m");
		}

		private void CycleBiome(int direction)
		{
			//IL_0020: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			BiomeType[] array = (BiomeType[])Enum.GetValues(typeof(BiomeType));
			if (array.Length != 0)
			{
				int num = Array.IndexOf(array, Plugin.ConfigBiome.Value);
				if (num < 0)
				{
					num = 0;
				}
				num = (num + direction) % array.Length;
				if (num < 0)
				{
					num += array.Length;
				}
				BiomeType val = array[num];
				Plugin.ConfigBiome.Value = val;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(14, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Biome set to ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<BiomeType>(val);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
				}
				log.LogInfo(val2);
				ShowToast($"Biome: {val}");
			}
		}

		private static void ShowToast(string message)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			try
			{
				string text = message;
				NotificationMenu.Display((NotificationType)0, ref text, false);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(47, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlantGrass: showing the notification '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' threw: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}
	}
	[BepInPlugin("mugsy33.plantgrass", "Plant Grass", "1.4.0")]
	public class Plugin : BasePlugin
	{
		public const string PluginGuid = "mugsy33.plantgrass";

		public const string PluginName = "Plant Grass";

		public const string PluginVersion = "1.4.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ConfigEnabled;

		internal static ConfigEntry<KeyCode> ConfigKey;

		internal static ConfigEntry<bool> ConfigPaintBiome;

		internal static ConfigEntry<BiomeType> ConfigBiome;

		internal static ConfigEntry<float> ConfigRadius;

		internal const float DefaultRadius = 1f;

		internal const float MinRadius = 0.5f;

		internal const float MaxRadius = 30f;

		internal const float RadiusStep = 0.5f;

		internal static readonly bool DebugLogging;

		public override void Load()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			ConfigMigration.Run(((BasePlugin)this).Config, Log);
			ConfigEnabled = ((BasePlugin)this).Config.Bind<bool>("PlantGrass", "Enabled", true, "Master on/off switch for the tool.");
			ConfigKey = ((BasePlugin)this).Config.Bind<KeyCode>("PlantGrass", "Key", (KeyCode)93, "Key that paints grass at your feet. Press alone to restore grass; hold Shift to lay a mowed lawn (grass with the 3D blades removed); hold Alt to change the paint radius (Alt+Shift to shrink); hold Ctrl to cycle the biome (Ctrl+Shift for the previous one).");
			ConfigPaintBiome = ((BasePlugin)this).Config.Bind<bool>("PlantGrass", "PaintGrassBiome", true, "Also mark the painted spot with the biome chosen below so grass reliably appears even in rocky areas (the same trick the game's sapling planting uses). Turn off to only repaint the surface - naturally rocky ground may then stay rocky.");
			ConfigBiome = ((BasePlugin)this).Config.Bind<BiomeType>("PlantGrass", "Biome", (BiomeType)0, "Which biome to stamp on the painted ground (applies only when PaintGrassBiome is on). It sets the ground's biome, which drives its grass/texture look and can influence what vegetation grows there later. Default is standard grassland. Every value the game defines is listed below.");
			ConfigRadius = ((BasePlugin)this).Config.Bind<float>("PlantGrass", "Radius", 1f, new ConfigDescription("Paint radius in meters - the size of each painted patch and the radius of the building-exclusion check. Adjust in-game with Alt + the paint key (Alt to increase, Alt+Shift to decrease); changes are saved here.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
			ClassInjector.RegisterTypeInIl2Cpp<PlantGrassTool>();
			Harmony.CreateAndPatchAll(typeof(CharacterSpawnPatch), (string)null);
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Plant Grass");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.4.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded.");
			}
			log.LogInfo(val);
		}
	}
	internal static class RetentionWindow
	{
		private const float ClosePadSeconds = 3f;

		private static bool _windowOpen;

		private static float _lastPaintTime;

		private static bool _openFailureLogged;

		private static readonly List<BiomeItemDescriptor> _flipped = new List<BiomeItemDescriptor>();

		internal static void Open()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			try
			{
				_lastPaintTime = Time.time;
				if (_windowOpen)
				{
					return;
				}
				BiomeProceduralDataHandler handler = BiomeItemInstance.Handler;
				Dictionary<int, BiomeItemDescriptor> val = ((handler != null) ? handler._descriptorsTable : null);
				if (val == null)
				{
					return;
				}
				_flipped.Clear();
				Enumerator<int, BiomeItemDescriptor> enumerator = val.GetEnumerator();
				while (enumerator.MoveNext())
				{
					BiomeItemDescriptor value = enumerator.Current.Value;
					if (value != null && value._removableByTerraforming)
					{
						value._removableByTerraforming = false;
						_flipped.Add(value);
					}
				}
				_windowOpen = true;
			}
			catch (Exception ex)
			{
				if (_openFailureLogged)
				{
					return;
				}
				_openFailureLogged = true;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(63, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("PlantGrass: retention Open failed; paint proceeds unprotected: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
					}
					log.LogError(val2);
				}
			}
		}

		internal static void Tick()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			try
			{
				if (_windowOpen && !(Time.time - _lastPaintTime < 3f))
				{
					Close();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(35, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlantGrass: retention Tick failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}

		internal static void ForceClose()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			try
			{
				if (_windowOpen)
				{
					Close();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(41, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlantGrass: retention ForceClose failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}

		internal static void Close()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			try
			{
				if (!_windowOpen)
				{
					return;
				}
				int num = 0;
				foreach (BiomeItemDescriptor item in _flipped)
				{
					if (item != null)
					{
						item._removableByTerraforming = true;
						num++;
					}
				}
				_flipped.Clear();
				_windowOpen = false;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(36, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlantGrass: retention Close failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "PlantGrass";

		public const string PLUGIN_NAME = "Plant Grass";

		public const string PLUGIN_VERSION = "1.4.0";
	}
}
namespace AskaShared.Game
{
	public static class LocalPlayerTool
	{
		private static bool _failureLogged;

		public static Character LocalCharacter { get; private set; }

		public static GameObject AttachOnSpawn(Character character, ManualLogSource log, string objectName, Vector3 localPosition, params Type[] components)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				if ((Object)(object)character == (Object)null)
				{
					return null;
				}
				if (!character.IsPlayer() || ((NetworkBehaviour)character).GetLocalAuthorityMask() != 1)
				{
					return null;
				}
				LocalCharacter = character;
				if (string.IsNullOrEmpty(objectName))
				{
					throw new ArgumentException("objectName is required and must be unique to this mod.", "objectName");
				}
				Transform transform = ((Component)character).gameObject.transform;
				if ((Object)(object)transform.Find(objectName) != (Object)null)
				{
					return null;
				}
				GameObject val = new GameObject(objectName);
				val.transform.SetParent(transform, false);
				val.transform.localPosition = localPosition;
				if (components != null)
				{
					foreach (Type type in components)
					{
						if (type != null)
						{
							val.AddComponent(Il2CppType.From(type));
						}
					}
				}
				ManualLogSource val2 = log;
				if (val2 != null)
				{
					BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(29, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(objectName);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" attached to local player '");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)((Component)character).gameObject).name);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("'.");
					}
					val2.LogInfo(val3);
				}
				return val;
			}
			catch (Exception ex)
			{
				if (!_failureLogged)
				{
					_failureLogged = true;
					ManualLogSource val2 = log;
					if (val2 != null)
					{
						BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(121, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(objectName);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(": attaching to the local player threw - this mod will do nothing this session, reported once rather than once per spawn: ");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
						}
						val2.LogError(val4);
					}
				}
				return null;
			}
		}
	}
}

AskaShared.dll

Decompiled a week ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Mugsy33")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Ship-in-Release infrastructure shared by ASKA BepInEx mods (config GUID migration).")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AskaShared")]
[assembly: AssemblyTitle("AskaShared")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AskaShared
{
	public static class ConfigMigration
	{
		private const string NewPrefix = "mugsy33.";

		private const string OldPrefix = "smithio.aska.";

		public static void Run(ConfigFile config, ManualLogSource log)
		{
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Expected O, but got Unknown
			bool flag = false;
			string text = null;
			bool flag2 = default(bool);
			try
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(config.ConfigFilePath);
				if (!fileNameWithoutExtension.StartsWith("mugsy33.", StringComparison.Ordinal))
				{
					return;
				}
				string text2 = "smithio.aska." + fileNameWithoutExtension.Substring("mugsy33.".Length);
				text = Path.Combine(Paths.ConfigPath, fileNameWithoutExtension + ".cfg");
				string text3 = Path.Combine(Paths.ConfigPath, text2 + ".cfg");
				string text4 = Path.Combine(Paths.ConfigPath, text2 + ".cfg.migrated");
				if (File.Exists(text))
				{
					if (File.Exists(text4))
					{
						File.Delete(text4);
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Deleted migrated legacy configuration: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text4);
						}
						log.LogInfo(val);
					}
					else if (File.Exists(text3))
					{
						File.Move(text3, text4, overwrite: true);
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Legacy configuration renamed to ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text4);
						}
						log.LogInfo(val);
					}
				}
				else if (File.Exists(text3))
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(31, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Legacy configuration detected: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text3);
					}
					log.LogInfo(val);
					string text5 = text + ".tmp";
					File.Copy(text3, text5, overwrite: true);
					File.Move(text5, text, overwrite: true);
					flag = true;
					val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Migrated legacy configuration to ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					}
					log.LogInfo(val);
					config.Reload();
					File.Move(text3, text4, overwrite: true);
					val = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Legacy configuration renamed to ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text4);
					}
					log.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(62, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Configuration migration failed; using existing configuration. ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log.LogWarning(val2);
				if (flag && text != null)
				{
					try
					{
						File.Delete(text);
						return;
					}
					catch
					{
						return;
					}
				}
			}
		}
	}
}