Decompiled source of GK2ScarecrowPlots v0.1.9

BepInEx/plugins/GK2ScarecrowPlots/GK2ScarecrowPlots.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GK2ScarecrowPlots.Configuration;
using GK2ScarecrowPlots.Detection;
using GK2ScarecrowPlots.Helpers;
using GK2ScarecrowPlots.Logging;
using GK2ScarecrowPlots.Services;
using HarmonyLib;
using LazyBearTechnology;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GK2ScarecrowPlots")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+babf48a59217ba868aa5c8c83ab196c7a9d63898")]
[assembly: AssemblyProduct("GK2ScarecrowPlots")]
[assembly: AssemblyTitle("GK2ScarecrowPlots")]
[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 GK2ScarecrowPlots
{
	[BepInPlugin("de.w00dst0ckOo.gk2.scarecrowplots", "Graveyard Keeper 2 - Scarecrow Plots", "0.1.9")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "de.w00dst0ckOo.gk2.scarecrowplots";

		public const string PluginName = "Graveyard Keeper 2 - Scarecrow Plots";

		public const string PluginVersion = "0.1.9";

		private Harmony harmony;

		private Coroutine gardenStartupCoroutine;

		private static Plugin instance;

		private void Awake()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			ModLog.Initialize(((BaseUnityPlugin)this).Logger);
			LegacyConfig legacyConfig = ConfigMigration.ReadLegacy(((BaseUnityPlugin)this).Config.ConfigFilePath);
			if (legacyConfig.Found)
			{
				ConfigMigration.RemoveLegacySections(((BaseUnityPlugin)this).Config.ConfigFilePath);
				((BaseUnityPlugin)this).Config.Reload();
			}
			ModConfig.Initialize(((BaseUnityPlugin)this).Config, legacyConfig);
			ModLog.Info("Graveyard Keeper 2 - Scarecrow Plots 0.1.9 loading...");
			instance = this;
			harmony = new Harmony("de.w00dst0ckOo.gk2.scarecrowplots");
			harmony.PatchAll();
			MainGame.OnGameStarted = (Action)Delegate.Combine(MainGame.OnGameStarted, new Action(OnGameStarted));
			ModConfig.Enabled.SettingChanged += OnEnabledChanged;
			ModLog.Info("Graveyard Keeper 2 - Scarecrow Plots loaded.");
		}

		private void OnGameStarted()
		{
			RequestGardenProcessing("MainGame.OnGameStarted");
		}

		private void OnEnabledChanged(object sender, EventArgs args)
		{
			GardenZoneProcessor.InvalidateCompletion();
			RequestGardenProcessing("EnabledChanged");
		}

		internal static void RequestGardenProcessing(string source)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				if (instance.gardenStartupCoroutine != null)
				{
					((MonoBehaviour)instance).StopCoroutine(instance.gardenStartupCoroutine);
				}
				instance.gardenStartupCoroutine = ((MonoBehaviour)instance).StartCoroutine(GardenStartupService.ProcessGarden(source));
			}
		}

		private void OnDestroy()
		{
			MainGame.OnGameStarted = (Action)Delegate.Remove(MainGame.OnGameStarted, new Action(OnGameStarted));
			ModConfig.Enabled.SettingChanged -= OnEnabledChanged;
			if (gardenStartupCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(gardenStartupCoroutine);
			}
			instance = null;
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
}
namespace GK2ScarecrowPlots.Services
{
	internal static class GardenStartupService
	{
		internal static IEnumerator ProcessGarden(string source)
		{
			WaitForSecondsRealtime delay = new WaitForSecondsRealtime(0.1f);
			WorldData world = GameWorldAccess.Current;
			yield return null;
			for (int attempt = 1; attempt <= 50; attempt++)
			{
				WorldData current = GameWorldAccess.Current;
				if (world == null)
				{
					world = current;
				}
				else if (world != current)
				{
					yield break;
				}
				if (GardenZoneRegistry.TryGet(out var zone))
				{
					GardenZoneProcessor.ProcessingResult processingResult = GardenZoneProcessor.Process(zone, source, attempt == 50);
					if (processingResult != GardenZoneProcessor.ProcessingResult.Retry)
					{
						if (ModLog.IsDebugEnabled)
						{
							ModLog.Debug((processingResult == GardenZoneProcessor.ProcessingResult.Complete) ? $"Scarecrow startup processing completed. | Source={source} | Attempt={attempt}" : ("Scarecrow startup processing deferred. | Source=" + source + " | Reason=BlockedTarget | Waiting for the next garden initialization event."));
						}
						yield break;
					}
				}
				yield return delay;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"Scarecrow startup processing incomplete after {5f:0.0} seconds. | Source={source} | Waiting for the next garden initialization event.");
			}
		}
	}
}
namespace GK2ScarecrowPlots.Patches
{
	[HarmonyPatch(typeof(Wgo), "CompleteVisualPartsLoad")]
	internal static class GardenVisualPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Wgo __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.MainWgoPart == (Object)null || !ScarecrowAnchorDetector.IsGardenRoot(((Component)__instance.MainWgoPart).transform))
			{
				return;
			}
			GardenZoneRegistry.RememberVisual(__instance);
			Transform scarecrow;
			bool num = ScarecrowAnchorDetector.TryGetScarecrowRoot(((Component)__instance.MainWgoPart).transform, out scarecrow);
			if (num)
			{
				ConfigEntry<bool> hideScarecrow = ModConfig.HideScarecrow;
				if (hideScarecrow != null && hideScarecrow.Value)
				{
					ScarecrowVisualHelper.Hide(scarecrow);
				}
			}
			if (num)
			{
				Transform transform = ((Component)__instance.MainWgoPart).transform;
				Transform scarecrow2 = scarecrow;
				WgoData data = __instance.Data;
				if (GardenZoneProcessor.IsCompleted(transform, scarecrow2, (data != null) ? data.WorldId : null))
				{
					return;
				}
			}
			Plugin.RequestGardenProcessing("GardenVisualLoaded");
		}
	}
	[HarmonyPatch(typeof(WorldZone), "AddWgosOnGameSceneStart")]
	internal static class WorldZonePatch
	{
		[HarmonyPostfix]
		private static void Postfix(WorldZone __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && __instance.Data != null && !(((ObjectLinkedToDefinition<WorldZoneDef>)(object)__instance.Data).id != "garden"))
			{
				GardenZoneRegistry.Remember(__instance);
				Plugin.RequestGardenProcessing("AddWgosOnGameSceneStart");
			}
		}
	}
}
namespace GK2ScarecrowPlots.Logging
{
	internal static class ModLog
	{
		private static ManualLogSource logger;

		internal static bool IsDebugEnabled => ModConfig.DebugLogging?.Value ?? false;

		internal static void Initialize(ManualLogSource source)
		{
			logger = source;
		}

		internal static void Info(string message)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)message);
			}
		}

		internal static void Warning(string message)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogWarning((object)message);
			}
		}

		internal static void Debug(string message)
		{
			if (IsDebugEnabled)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)("[DEBUG] " + message));
				}
			}
		}
	}
}
namespace GK2ScarecrowPlots.Helpers
{
	internal static class GameWorldAccess
	{
		internal static WorldData Current
		{
			get
			{
				MainGame instance = MainGame.Instance;
				if (!((Object)(object)instance != (Object)null))
				{
					return null;
				}
				return instance.GameSave?.worldData;
			}
		}
	}
	internal static class GardenPlotHelper
	{
		internal sealed class PlotCreationBatch : IDisposable
		{
			private HashSet<string> ids;

			private bool changed;

			internal void Remember(WgoData data)
			{
				if (ids == null)
				{
					ids = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
					string value = ModConfig.CreatedPlotIds.Value;
					if (!string.IsNullOrWhiteSpace(value))
					{
						string[] array = value.Split(new char[1] { ',' });
						for (int i = 0; i < array.Length; i++)
						{
							string text = array[i].Trim();
							if (!string.IsNullOrWhiteSpace(text))
							{
								ids.Add(text);
							}
						}
					}
				}
				string text2 = ((object)data.UniqueId).ToString();
				changed |= ids.Add(text2);
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Remembered garden plot: " + text2);
				}
			}

			public void Dispose()
			{
				if (changed)
				{
					ModConfig.CreatedPlotIds.Value = string.Join(",", ids);
					ModConfig.SaveIfAutoSaveDisabled();
					changed = false;
				}
			}
		}

		internal static WgoData SpawnGardenPlot(GameScene scene, Vector3 position, PlotCreationBatch batch)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			if ((Object)(object)scene == (Object)null)
			{
				return null;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"Creating garden plot at {position}.");
			}
			WgoData val = new WgoData("garden_empty", position, scene.Id);
			if ((Object)(object)scene.AddWgoData(val, false) == (Object)null)
			{
				ModLog.Warning($"Failed to create garden plot at {position}.");
				return null;
			}
			batch.Remember(val);
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Created garden plot | " + $"UniqueId={val.UniqueId} | " + $"Position={position}");
			}
			return val;
		}

		internal static void RemoveCreatedPlots()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			string value = ModConfig.CreatedPlotIds.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				return;
			}
			string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			List<string> list = new List<string>(array.Length);
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string text = array2[i].Trim();
				if (!Guid.TryParse(text, out var result))
				{
					ModLog.Warning("Invalid stored garden plot ID: " + text);
					list.Add(text);
					continue;
				}
				SGuid val = new SGuid(result);
				WgoData wgoData = MainGame.WorldData.GetWgoData(val);
				if (wgoData == null)
				{
					if (ModLog.IsDebugEnabled)
					{
						ModLog.Debug("Stored garden plot no longer exists: " + text);
					}
					continue;
				}
				if (((ObjectLinkedToDefinition<WGODef>)(object)wgoData).Definition == null || ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).Definition.wgoGroup != "garden_bed")
				{
					ModLog.Warning("Stored object " + text + " is not a garden bed. It will not be removed.");
					list.Add(text);
					continue;
				}
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Removing garden plot | " + $"UniqueId={wgoData.UniqueId} | " + "ID=" + ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id + " | " + $"Position={wgoData.Position}");
				}
				MainGame.WorldData.RemoveWgoDataFromGameScene(wgoData, true);
			}
			ModConfig.CreatedPlotIds.Value = string.Join(",", list);
			ModConfig.SaveIfAutoSaveDisabled();
		}
	}
	internal static class GardenZoneProcessor
	{
		internal enum ProcessingResult
		{
			Retry,
			Complete,
			Blocked
		}

		private enum TargetResult
		{
			Complete,
			Blocked,
			Failed
		}

		private const float BlockedPositionTolerance = 0.35f;

		private static object completedWorld;

		private static string completedScene;

		private static string completedTier;

		private static string completedPlotIds;

		private static Vector3 completedAnchorPosition;

		private static object blockedWorld;

		private static string blockedScene;

		private static readonly HashSet<Vector3> blockedTargets = new HashSet<Vector3>();

		internal static void InvalidateCompletion()
		{
			completedWorld = null;
		}

		internal static bool IsCompleted(Transform root, Transform scarecrow, string sceneId)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value)
			{
				completedWorld = null;
				return false;
			}
			if (GameWorldAccess.Current != null && completedWorld == GameWorldAccess.Current && (Object)(object)root != (Object)null && (Object)(object)scarecrow != (Object)null && completedScene == sceneId && completedTier == ((Object)root).name && ((Vector3)(ref completedAnchorPosition)).Equals(scarecrow.position))
			{
				return completedPlotIds == ModConfig.CreatedPlotIds.Value;
			}
			return false;
		}

		internal static ProcessingResult Process(WorldZone zone, string source, bool allowGridFallback = false)
		{
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)zone == (Object)null)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Garden processing skipped | Source=" + source + " | Zone=null");
				}
				return ProcessingResult.Retry;
			}
			if (GameWorldAccess.Current == null)
			{
				return ProcessingResult.Retry;
			}
			WorldZoneData data = zone.Data;
			if (data == null || ((ObjectLinkedToDefinition<WorldZoneDef>)(object)data).id != "garden")
			{
				return ProcessingResult.Retry;
			}
			GardenZoneRegistry.Remember(zone);
			if (!ModConfig.Enabled.Value)
			{
				completedWorld = null;
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow Plots disabled. Removing mod-created plots.");
				}
				if (string.IsNullOrWhiteSpace(ModConfig.CreatedPlotIds.Value) && ModLog.IsDebugEnabled)
				{
					ModLog.Debug("No stored plot IDs found. Existing plots may need to be removed manually in-game.");
				}
				GardenPlotHelper.RemoveCreatedPlots();
				ConfigEntry<bool> hideScarecrow = ModConfig.HideScarecrow;
				if (hideScarecrow == null || !hideScarecrow.Value)
				{
					return ProcessingResult.Complete;
				}
			}
			if (!GardenZoneRegistry.TryGetVisualRoot(zone, out var root))
			{
				if (allowGridFallback && ModLog.IsDebugEnabled)
				{
					ModLog.Debug($"Garden processing incomplete | Reason=VisualRootUnavailable | ZoneId={((ObjectLinkedToDefinition<WorldZoneDef>)(object)data).id} | SceneId={data.gameSceneId} | RegisteredWGOs={zone.Wgos.Count}");
				}
				return ProcessingResult.Retry;
			}
			Transform scarecrow;
			bool flag = ScarecrowAnchorDetector.TryGetScarecrowRoot(root, out scarecrow);
			if (flag)
			{
				ConfigEntry<bool> hideScarecrow2 = ModConfig.HideScarecrow;
				if (hideScarecrow2 != null && hideScarecrow2.Value)
				{
					ScarecrowVisualHelper.Hide(scarecrow);
				}
			}
			if (!ModConfig.Enabled.Value)
			{
				if (!flag)
				{
					return ProcessingResult.Retry;
				}
				return ProcessingResult.Complete;
			}
			if (IsCompleted(root, scarecrow, data.gameSceneId))
			{
				return ProcessingResult.Complete;
			}
			PlayerController playerController = MainGame.PlayerController;
			GameScene val = ((playerController != null) ? playerController.CurrentGameScene : null);
			if ((Object)(object)val == (Object)null || val.Id != data.gameSceneId)
			{
				return ProcessingResult.Retry;
			}
			if (!flag && (!allowGridFallback || !val.IsStartCompleted))
			{
				return ProcessingResult.Retry;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Processing garden | Source=" + source + " | ZoneId=" + ((ObjectLinkedToDefinition<WorldZoneDef>)(object)data).id);
			}
			CollectGarden(data, out var wgos, out var beds, out var hasGardenBuilder);
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"Garden scan | WGOs={wgos.Count} | GardenBeds={beds.Count}");
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"builder_garden present={hasGardenBuilder}");
			}
			if (!hasGardenBuilder)
			{
				return ProcessingResult.Retry;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Starting scarecrow detection | " + $"Beds={beds.Count}");
			}
			ScarecrowAnchorDetector.Result result;
			bool flag2 = ScarecrowAnchorDetector.TryDetect(beds, scarecrow, out result);
			if (flag && !flag2)
			{
				return ProcessingResult.Retry;
			}
			Vector3 targetA;
			Vector3 targetB;
			bool missingAOccupied;
			bool missingBOccupied;
			if (flag2)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow detection method=Anchor");
				}
				targetA = result.MissingA;
				targetB = result.MissingB;
				missingAOccupied = result.MissingAOccupied;
				missingBOccupied = result.MissingBOccupied;
			}
			else
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow anchor detection unavailable. Falling back to grid detection.");
				}
				if (!ScarecrowFieldDetector.TryDetect(beds, out var result2))
				{
					if (ModLog.IsDebugEnabled)
					{
						ModLog.Debug("Scarecrow detection failed.");
					}
					return ProcessingResult.Retry;
				}
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow detection method=GridFallback");
				}
				targetA = result2.MissingA;
				targetB = result2.MissingB;
				missingAOccupied = result2.MissingAOccupied;
				missingBOccupied = result2.MissingBOccupied;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Scarecrow detection succeeded | " + $"TargetA={targetA} | " + $"OccupiedA={missingAOccupied} | " + $"TargetB={targetB} | " + $"OccupiedB={missingBOccupied}");
			}
			if (blockedWorld != GameWorldAccess.Current || blockedScene != val.Id)
			{
				blockedTargets.Clear();
				blockedWorld = GameWorldAccess.Current;
				blockedScene = val.Id;
			}
			blockedTargets.RemoveWhere((Vector3 position) => !((Vector3)(ref position)).Equals(targetA) && !((Vector3)(ref position)).Equals(targetB));
			bool flag3;
			bool flag4;
			using (GardenPlotHelper.PlotCreationBatch batch = new GardenPlotHelper.PlotCreationBatch())
			{
				TargetResult num = TrySpawnGardenPlot(val, wgos, targetA, missingAOccupied, batch);
				TargetResult targetResult = TrySpawnGardenPlot(val, wgos, targetB, missingBOccupied, batch);
				flag3 = num == TargetResult.Complete && targetResult == TargetResult.Complete;
				flag4 = num == TargetResult.Blocked || targetResult == TargetResult.Blocked;
			}
			if (flag3 && flag2)
			{
				completedWorld = GameWorldAccess.Current;
				completedScene = data.gameSceneId;
				completedTier = ((Object)root).name;
				completedAnchorPosition = scarecrow.position;
				completedPlotIds = ModConfig.CreatedPlotIds.Value;
			}
			if (!flag3)
			{
				InvalidateCompletion();
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Garden processing incomplete | Reason=" + (flag4 ? "BlockedTarget" : "PlotCreationFailed"));
				}
			}
			if (!flag3)
			{
				if (!flag4)
				{
					return ProcessingResult.Retry;
				}
				return ProcessingResult.Blocked;
			}
			return ProcessingResult.Complete;
		}

		private static TargetResult TrySpawnGardenPlot(GameScene scene, List<WgoData> wgos, Vector3 position, bool gardenBedOccupied, GardenPlotHelper.PlotCreationBatch batch)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (gardenBedOccupied)
			{
				blockedTargets.Remove(position);
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug($"Skipping garden plot at {position}: " + "garden bed already exists.");
				}
				return TargetResult.Complete;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"Checking target for blocking WGOs | Position={position}");
			}
			WgoData val = FindBlockingWgo(wgos, position);
			if (val != null)
			{
				blockedTargets.Add(position);
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Target blocked temporarily | " + $"Position={position} | " + "BlockingWgo=" + (((BalanceBaseObject)(((ObjectLinkedToDefinition<WGODef>)(object)val).Definition?)).id ?? ((ObjectLinkedToDefinition<WGODef>)(object)val).id) + " | " + $"BlockingPosition={val.Position}");
				}
				return TargetResult.Blocked;
			}
			bool flag = blockedTargets.Remove(position);
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug(string.Format("{0} | Position={1}", flag ? "Previously blocked target now clear" : "Target clear", position));
			}
			WgoData val2 = GardenPlotHelper.SpawnGardenPlot(scene, position, batch);
			if (val2 != null)
			{
				wgos.Add(val2);
			}
			if (val2 == null)
			{
				return TargetResult.Failed;
			}
			return TargetResult.Complete;
		}

		private static WgoData FindBlockingWgo(List<WgoData> wgos, Vector3 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(position.x, position.z);
			foreach (WgoData wgo in wgos)
			{
				if (wgo != null && !(((ObjectLinkedToDefinition<WGODef>)(object)wgo).Definition?.wgoGroup == "garden_bed") && Vector2.Distance(new Vector2(wgo.Position.x, wgo.Position.z), val) <= 0.35f)
				{
					return wgo;
				}
			}
			return null;
		}

		private static void CollectGarden(WorldZoneData zone, out List<WgoData> wgos, out List<WgoData> beds, out bool hasGardenBuilder)
		{
			wgos = new List<WgoData>(zone.wgoDataList.Count + 2);
			beds = new List<WgoData>(zone.wgoDataList.Count);
			hasGardenBuilder = false;
			foreach (SGuid wgoData2 in zone.wgoDataList)
			{
				WgoData wgoData = MainGame.WorldData.GetWgoData(wgoData2);
				if (wgoData == null)
				{
					continue;
				}
				wgos.Add(wgoData);
				WGODef definition = ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).Definition;
				if (definition != null)
				{
					if (definition.wgoGroup == "garden_bed")
					{
						beds.Add(wgoData);
					}
					if (((BalanceBaseObject)definition).id == "builder_garden")
					{
						hasGardenBuilder = true;
					}
				}
			}
		}
	}
	internal static class GardenZoneRegistry
	{
		private static WorldZone garden;

		private static object world;

		private static Wgo visualOwner;

		private static WgoData visualData;

		private static object visualWorld;

		internal static void RememberVisual(Wgo owner)
		{
			if ((Object)(object)owner == (Object)null || owner.Data == null || (Object)(object)owner.MainWgoPart == (Object)null || !ScarecrowAnchorDetector.IsGardenRoot(((Component)owner.MainWgoPart).transform))
			{
				return;
			}
			visualWorld = GameWorldAccess.Current;
			if (visualWorld != null)
			{
				visualOwner = owner;
				visualData = owner.Data;
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Garden visual registered | Name=" + ((Object)owner.MainWgoPart).name + " | WorldId=" + visualData.WorldId + " | ZoneId=" + ((ObjectLinkedToDefinition<WorldZoneDef>)(object)visualData.WorldZoneData)?.id);
				}
			}
		}

		internal static void Remember(WorldZone zone)
		{
			if (!((Object)(object)zone == (Object)null) && zone.Data != null && !(((ObjectLinkedToDefinition<WorldZoneDef>)(object)zone.Data).id != "garden"))
			{
				WorldData current = GameWorldAccess.Current;
				if (current == null)
				{
					garden = null;
					world = null;
				}
				else
				{
					garden = zone;
					world = current;
				}
			}
		}

		internal static bool TryGet(out WorldZone zone)
		{
			WorldData current = GameWorldAccess.Current;
			zone = null;
			if (current == null)
			{
				garden = null;
				world = null;
				return false;
			}
			if (world == current && (Object)(object)garden != (Object)null && garden.Data != null && ((ObjectLinkedToDefinition<WorldZoneDef>)(object)garden.Data).id == "garden")
			{
				zone = garden;
				return true;
			}
			garden = null;
			PlayerController playerController = MainGame.PlayerController;
			GameScene val = ((playerController != null) ? playerController.CurrentGameScene : null);
			WorldZone val2 = (((Object)(object)val != (Object)null) ? val.GetWorldZoneById("garden") : null);
			if ((Object)(object)val2 == (Object)null || val2.Data == null || ((ObjectLinkedToDefinition<WorldZoneDef>)(object)val2.Data).id != "garden")
			{
				return false;
			}
			Remember(val2);
			zone = val2;
			return true;
		}

		internal static bool TryGetVisualRoot(WorldZone zone, out Transform root)
		{
			root = null;
			if ((Object)(object)zone == (Object)null || zone.Data == null || ((ObjectLinkedToDefinition<WorldZoneDef>)(object)zone.Data).id != "garden")
			{
				return false;
			}
			if (visualWorld != GameWorldAccess.Current || (Object)(object)visualOwner == (Object)null || visualOwner.Data != visualData)
			{
				visualOwner = null;
				visualData = null;
				visualWorld = null;
			}
			if ((Object)(object)visualOwner != (Object)null && visualData.WorldId == zone.Data.gameSceneId && (Object)(object)visualOwner.MainWgoPart != (Object)null && ScarecrowAnchorDetector.IsGardenRoot(((Component)visualOwner.MainWgoPart).transform))
			{
				root = ((Component)visualOwner.MainWgoPart).transform;
				return true;
			}
			foreach (Wgo wgo in zone.Wgos)
			{
				if (!((Object)(object)wgo == (Object)null) && !((Object)(object)wgo.MainWgoPart == (Object)null))
				{
					Transform transform = ((Component)wgo.MainWgoPart).transform;
					if (ScarecrowAnchorDetector.IsGardenRoot(transform))
					{
						root = transform;
						return true;
					}
				}
			}
			Transform val = ((Component)zone).transform;
			while ((Object)(object)val != (Object)null)
			{
				if (ScarecrowAnchorDetector.IsGardenRoot(val))
				{
					root = val;
					return true;
				}
				val = val.parent;
			}
			PlayerController playerController = MainGame.PlayerController;
			GameScene val2 = ((playerController != null) ? playerController.CurrentGameScene : null);
			if ((Object)(object)val2 == (Object)null || val2.Id != zone.Data.gameSceneId || string.IsNullOrEmpty(zone.Data.contentPartName))
			{
				return false;
			}
			GameSceneConfig gameSceneConfig = val2.GameSceneConfig;
			GameObject val3 = default(GameObject);
			if ((Object)(object)gameSceneConfig == (Object)null || !gameSceneConfig.TryGetLoadedContent(zone.Data.contentPartName, ref val3) || (Object)(object)val3 == (Object)null)
			{
				return false;
			}
			Transform[] componentsInChildren = val3.GetComponentsInChildren<Transform>(true);
			foreach (Transform val4 in componentsInChildren)
			{
				if (ScarecrowAnchorDetector.IsGardenRoot(val4))
				{
					root = val4;
					return true;
				}
			}
			return false;
		}
	}
	internal static class ScarecrowVisualHelper
	{
		private static readonly HashSet<Transform> hiddenScarecrows = new HashSet<Transform>();

		private static object hiddenWorld;

		internal static void Hide(Transform scarecrow)
		{
			if (!((Object)(object)scarecrow == (Object)null))
			{
				WorldData current = GameWorldAccess.Current;
				if (hiddenWorld != current)
				{
					hiddenScarecrows.Clear();
					hiddenWorld = current;
				}
				if (current != null && !hiddenScarecrows.Contains(scarecrow))
				{
					DisableRenderers(scarecrow);
					DisableColliders(scarecrow);
					hiddenScarecrows.Add(scarecrow);
				}
			}
		}

		private static void DisableRenderers(Transform scarecrow)
		{
			Renderer[] componentsInChildren = ((Component)scarecrow).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled)
				{
					val.enabled = false;
					if (ModLog.IsDebugEnabled)
					{
						ModLog.Debug("Scarecrow renderer disabled | Name=" + ((Object)((Component)val).gameObject).name);
					}
				}
			}
		}

		private static void DisableColliders(Transform scarecrow)
		{
			Collider[] componentsInChildren = ((Component)scarecrow).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled)
				{
					val.enabled = false;
					if (ModLog.IsDebugEnabled)
					{
						ModLog.Debug("Scarecrow collider disabled | Name=" + ((Object)((Component)val).gameObject).name + " | Type=" + ((object)val).GetType().Name);
					}
				}
			}
		}
	}
}
namespace GK2ScarecrowPlots.Detection
{
	internal static class ScarecrowAnchorDetector
	{
		internal sealed class Result
		{
			internal Vector3 MissingA;

			internal Vector3 MissingB;

			internal bool MissingAOccupied;

			internal bool MissingBOccupied;

			internal Vector3 ScarecrowPosition;
		}

		private const float OccupancyTolerance = 0.1f;

		private static Transform cachedScarecrow;

		private static object cachedWorld;

		private static Transform cachedGardenRoot;

		internal static bool TryDetect(List<WgoData> beds, Transform scarecrow, out Result result)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			result = null;
			if (beds == null || beds.Count == 0)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow anchor detection failed: no garden beds.");
				}
				return false;
			}
			if ((Object)(object)scarecrow == (Object)null)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow anchor detection failed: scarecrow root not found.");
				}
				return false;
			}
			Vector3 position = scarecrow.position;
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Scarecrow anchor found | " + $"Position={position}");
			}
			if (!TryFindNearestColumn(beds, position.x, out var columnX))
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow anchor detection failed: garden column not found.");
				}
				return false;
			}
			if (!TryFindRows(beds, columnX, position.z, out var upperZ, out var lowerZ))
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Scarecrow anchor detection failed: surrounding garden rows not found.");
				}
				return false;
			}
			float num = FindNearestBedY(beds, position);
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(columnX, num, upperZ);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(columnX, num, lowerZ);
			bool flag = HasGardenBed(beds, val, 0.1f);
			bool flag2 = HasGardenBed(beds, val2, 0.1f);
			result = new Result
			{
				MissingA = val,
				MissingB = val2,
				MissingAOccupied = flag,
				MissingBOccupied = flag2,
				ScarecrowPosition = position
			};
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Scarecrow anchor result | " + $"ColumnX={columnX:F2} | " + $"UpperZ={upperZ:F2} | " + $"LowerZ={lowerZ:F2} | " + $"TargetA={val} | " + $"OccupiedA={flag} | " + $"TargetB={val2} | " + $"OccupiedB={flag2}");
			}
			return true;
		}

		internal static bool TryGetScarecrowRoot(Transform gardenRoot, out Transform scarecrow)
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			WorldData current = GameWorldAccess.Current;
			scarecrow = null;
			if (current == null || !IsGardenRoot(gardenRoot))
			{
				cachedWorld = null;
				cachedGardenRoot = null;
				cachedScarecrow = null;
				return false;
			}
			if (cachedWorld == current && (Object)(object)cachedGardenRoot == (Object)(object)gardenRoot && TryGetScarecrowAnchor(cachedScarecrow, gardenRoot, out var anchor))
			{
				scarecrow = anchor;
				return true;
			}
			bool flag = cachedWorld != current || (Object)(object)cachedGardenRoot != (Object)(object)gardenRoot;
			cachedWorld = current;
			cachedGardenRoot = gardenRoot;
			cachedScarecrow = null;
			Transform val = null;
			int num = 0;
			Transform[] componentsInChildren = ((Component)gardenRoot).GetComponentsInChildren<Transform>(true);
			foreach (Transform obj in componentsInChildren)
			{
				if (((Object)obj).name.StartsWith("scarecrow_on_stick", StringComparison.Ordinal))
				{
					num++;
				}
				if (TryGetScarecrowAnchor(obj, gardenRoot, out var anchor2) && ((Object)(object)val == (Object)null || (!((Component)val).gameObject.activeInHierarchy && ((Component)anchor2).gameObject.activeInHierarchy)))
				{
					val = anchor2;
				}
			}
			if (ModLog.IsDebugEnabled && (flag || (Object)(object)val != (Object)null))
			{
				ModLog.Debug($"Garden root found | Path={GetTransformPath(gardenRoot)} | ScarecrowCandidates={num} | AnchorFound={(Object)(object)val != (Object)null}");
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			cachedScarecrow = val;
			scarecrow = val;
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"Scarecrow anchor selected | Path={GetTransformPath(val)} | Position={val.position}");
			}
			return true;
		}

		private static string GetTransformPath(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "<null>";
			}
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		private static bool TryGetScarecrowAnchor(Transform transform, Transform gardenRoot, out Transform anchor)
		{
			anchor = null;
			if ((Object)(object)transform == (Object)null || !((Object)transform).name.StartsWith("scarecrow_on_stick", StringComparison.Ordinal))
			{
				return false;
			}
			Transform val = transform;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)gardenRoot)
			{
				Transform parent = val.parent;
				if ((Object)(object)parent != (Object)null && ((Object)parent).name == "Base" && (Object)(object)parent.parent == (Object)(object)gardenRoot)
				{
					if (!((Object)val).name.StartsWith("scarecrow_on_stick", StringComparison.Ordinal) || ((Object)val).name.StartsWith("scarecrow_on_stick_sh", StringComparison.Ordinal))
					{
						return false;
					}
					anchor = val;
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		internal static bool IsGardenRoot(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			string name = ((Object)transform).name;
			int num = name.Length - "(Clone)".Length;
			if (num <= "garden_t".Length || !name.StartsWith("garden_t", StringComparison.Ordinal) || !name.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				return false;
			}
			for (int i = "garden_t".Length; i < num; i++)
			{
				if (name[i] < '0' || name[i] > '9')
				{
					return false;
				}
			}
			return true;
		}

		private static bool TryFindNearestColumn(List<WgoData> beds, float scarecrowX, out float columnX)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			columnX = 0f;
			float num = float.MaxValue;
			bool flag = false;
			foreach (WgoData bed in beds)
			{
				if (bed != null)
				{
					float num2 = Mathf.Abs(bed.Position.x - scarecrowX);
					if (!(num2 >= num))
					{
						num = num2;
						columnX = bed.Position.x;
						flag = true;
					}
				}
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Scarecrow nearest column | " + $"ScarecrowX={scarecrowX:F2} | " + $"ColumnX={columnX:F2} | " + $"Distance={num:F2}");
			}
			if (flag && TryGetColumnSpacing(UniqueCoordinates(beds, columns: true), out var spacing))
			{
				return num <= spacing * 0.5f;
			}
			return false;
		}

		private static bool TryFindRows(List<WgoData> beds, float columnX, float scarecrowZ, out float upperZ, out float lowerZ)
		{
			upperZ = 0f;
			lowerZ = 0f;
			List<float> list = UniqueCoordinates(beds, columns: true);
			List<float> list2 = UniqueCoordinates(beds, columns: false);
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Garden grid | UniqueRows=[" + string.Join(", ", list2.ConvertAll((float z) => z.ToString("F2"))) + "]");
			}
			if (!TryGetColumnSpacing(list, out var columnSpacing))
			{
				return false;
			}
			List<WgoData> nearby = beds.FindAll((WgoData bed) => bed != null && Mathf.Abs(bed.Position.x - columnX) <= columnSpacing * 2f + 0.1f);
			list2 = UniqueCoordinates(nearby, columns: false);
			list2.RemoveAll((float z) => CountRowColumns(nearby, z) < 2);
			bool flag = false;
			bool flag2 = false;
			foreach (float item in list2)
			{
				if (item > scarecrowZ && (!flag || item < upperZ))
				{
					upperZ = item;
					flag = true;
				}
				else if (item < scarecrowZ && (!flag2 || item > lowerZ))
				{
					lowerZ = item;
					flag2 = true;
				}
			}
			float num = float.MaxValue;
			for (int num2 = 1; num2 < list2.Count; num2++)
			{
				float num3 = list2[num2] - list2[num2 - 1];
				int num4 = 0;
				foreach (float item2 in list)
				{
					if (!(Mathf.Abs(item2 - columnX) > columnSpacing * 2f + 0.1f) && HasBedAtXZ(nearby, item2, list2[num2 - 1]) && HasBedAtXZ(nearby, item2, list2[num2]))
					{
						num4++;
					}
				}
				if (num4 >= 3 && num3 < num)
				{
					num = num3;
				}
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug(string.Format("Garden grid spacing | ColumnSpacing={0:F2} | RowSpacing={1}", columnSpacing, (num == float.MaxValue) ? "unreliable" : num.ToString("F2")));
			}
			bool flag3 = flag;
			bool flag4 = flag2;
			if (flag != flag2 && list2.Count >= 3 && num != float.MaxValue)
			{
				if (flag && upperZ - scarecrowZ < num - 0.1f)
				{
					lowerZ = upperZ - num;
					flag2 = true;
				}
				else if (flag2 && scarecrowZ - lowerZ < num - 0.1f)
				{
					upperZ = lowerZ + num;
					flag = true;
				}
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug(string.Format("Scarecrow surrounding rows | ColumnX={0:F2} | ScarecrowZ={1:F2} | UpperZ={2:F2} | UpperSource={3} | LowerZ={4:F2} | LowerSource={5}", columnX, scarecrowZ, upperZ, flag3 ? "Direct" : (flag ? "Inferred" : "Missing"), lowerZ, flag4 ? "Direct" : (flag2 ? "Inferred" : "Missing")));
			}
			return flag && flag2;
		}

		private static List<float> UniqueCoordinates(List<WgoData> beds, bool columns)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			List<float> list = new List<float>();
			foreach (WgoData bed in beds)
			{
				if (bed != null)
				{
					list.Add(columns ? bed.Position.x : bed.Position.z);
				}
			}
			list.Sort();
			List<float> list2 = new List<float>();
			foreach (float item in list)
			{
				if (list2.Count == 0 || item - list2[list2.Count - 1] > 0.1f)
				{
					list2.Add(item);
				}
			}
			return list2;
		}

		private static bool TryGetColumnSpacing(List<float> columns, out float spacing)
		{
			spacing = float.MaxValue;
			for (int i = 1; i < columns.Count; i++)
			{
				spacing = Mathf.Min(spacing, columns[i] - columns[i - 1]);
			}
			int num = 0;
			for (int j = 1; j < columns.Count; j++)
			{
				if (Mathf.Abs(columns[j] - columns[j - 1] - spacing) <= 0.1f)
				{
					num++;
				}
			}
			return num >= 2;
		}

		private static int CountRowColumns(List<WgoData> beds, float z)
		{
			return UniqueCoordinates(beds.FindAll((WgoData bed) => Mathf.Abs(bed.Position.z - z) <= 0.1f), columns: true).Count;
		}

		private static bool HasBedAtXZ(List<WgoData> beds, float x, float z)
		{
			return beds.Exists((WgoData bed) => Mathf.Abs(bed.Position.x - x) <= 0.1f && Mathf.Abs(bed.Position.z - z) <= 0.1f);
		}

		private static float FindNearestBedY(List<WgoData> beds, Vector3 scarecrowPosition)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			float y = scarecrowPosition.y;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(scarecrowPosition.x, scarecrowPosition.z);
			foreach (WgoData bed in beds)
			{
				if (bed != null)
				{
					float num2 = Vector2.Distance(new Vector2(bed.Position.x, bed.Position.z), val);
					if (!(num2 >= num))
					{
						num = num2;
						y = bed.Position.y;
					}
				}
			}
			return y;
		}

		private static bool HasGardenBed(List<WgoData> beds, Vector3 position, float tolerance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(position.x, position.z);
			foreach (WgoData bed in beds)
			{
				if (bed != null && Vector2.Distance(new Vector2(bed.Position.x, bed.Position.z), val) <= tolerance)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ScarecrowFieldDetector
	{
		internal sealed class Result
		{
			public Vector3 MissingA;

			public Vector3 MissingB;

			public bool MissingAOccupied;

			public bool MissingBOccupied;
		}

		private sealed class Candidate
		{
			public Vector2 Origin;

			public Vector2 ColumnDirection;

			public Vector2 RowDirection;

			public int Matches;
		}

		private const float ColumnSpacing = 0.96f;

		private const float RowSpacingOuter = 1.2f;

		private const float RowSpacingMiddle = 1.5f;

		private const float Tolerance = 0.1f;

		private const int MinimumMatches = 8;

		private static readonly float[] RowOffsets = new float[4] { 0f, 1.2f, 2.7f, 3.9f };

		internal static bool TryDetect(List<WgoData> beds, out Result result)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: 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_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			result = null;
			if (beds == null)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Detector stopped: beds list is null.");
				}
				return false;
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug($"Detector started | Beds={beds.Count} | " + $"MinimumMatches={8}");
			}
			if (beds.Count < 8)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Detector stopped: not enough garden beds | " + $"Beds={beds.Count} | " + $"Minimum={8}");
				}
				return false;
			}
			Candidate best = null;
			Vector2 val3 = default(Vector2);
			foreach (WgoData bed in beds)
			{
				Vector2 val = ToXZ(bed.Position);
				foreach (WgoData bed2 in beds)
				{
					if (bed != bed2)
					{
						Vector2 val2 = ToXZ(bed2.Position) - val;
						if (!(Mathf.Abs(((Vector2)(ref val2)).magnitude - 0.96f) > 0.1f))
						{
							Vector2 normalized = ((Vector2)(ref val2)).normalized;
							((Vector2)(ref val3))..ctor(0f - normalized.y, normalized.x);
							TestCandidates(beds, val, normalized, val3, ref best);
							TestCandidates(beds, val, normalized, -val3, ref best);
						}
					}
				}
			}
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Detector best candidate | " + $"Matches={best?.Matches ?? 0} | " + $"Origin={best?.Origin} | " + $"ColumnDirection={best?.ColumnDirection} | " + $"RowDirection={best?.RowDirection}");
			}
			if (best == null || best.Matches < 8)
			{
				if (ModLog.IsDebugEnabled)
				{
					ModLog.Debug("Detector stopped: no valid scarecrow field candidate.");
				}
				return false;
			}
			Vector2 val4 = best.Origin + best.RowDirection * 1.2f + best.RowDirection * 1.5f;
			Vector2 val5 = val4 + best.RowDirection * 1.2f;
			Vector2 position = val4 + best.ColumnDirection * 1.92f;
			Vector2 position2 = val5 + best.ColumnDirection * 1.92f;
			float y = FindFieldY(beds, best.Origin);
			result = new Result
			{
				MissingA = ToXYZ(position, y),
				MissingB = ToXYZ(position2, y),
				MissingAOccupied = HasBedAt(beds, position),
				MissingBOccupied = HasBedAt(beds, position2)
			};
			if (ModLog.IsDebugEnabled)
			{
				ModLog.Debug("Detector result | " + $"MissingA={result.MissingA} | " + $"OccupiedA={result.MissingAOccupied} | " + $"MissingB={result.MissingB} | " + $"OccupiedB={result.MissingBOccupied}");
			}
			return true;
		}

		private static void TestCandidates(List<WgoData> beds, Vector2 knownBed, Vector2 columnDirection, Vector2 rowDirection, ref Candidate best)
		{
			//IL_0008: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 5; j++)
				{
					Vector2 origin = knownBed - columnDirection * (0.96f * (float)j) - rowDirection * RowOffsets[i];
					int num = CountMatches(beds, origin, columnDirection, rowDirection);
					if (best == null || num > best.Matches)
					{
						best = new Candidate
						{
							Origin = origin,
							ColumnDirection = columnDirection,
							RowDirection = rowDirection,
							Matches = num
						};
					}
				}
			}
		}

		private static int CountMatches(List<WgoData> beds, Vector2 origin, Vector2 columnDirection, Vector2 rowDirection)
		{
			//IL_0006: 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)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			for (int i = 0; i < 4; i++)
			{
				Vector2 val = origin + rowDirection * RowOffsets[i];
				for (int j = 0; j < 5; j++)
				{
					Vector2 position = val + columnDirection * (0.96f * (float)j);
					if (HasBedAt(beds, position))
					{
						num++;
					}
				}
			}
			return num;
		}

		private static bool HasBedAt(List<WgoData> beds, Vector2 position)
		{
			//IL_0010: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			foreach (WgoData bed in beds)
			{
				if (Vector2.Distance(ToXZ(bed.Position), position) <= 0.1f)
				{
					return true;
				}
			}
			return false;
		}

		private static float FindFieldY(List<WgoData> beds, Vector2 reference)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			float result = 0f;
			foreach (WgoData bed in beds)
			{
				float num2 = Vector2.Distance(ToXZ(bed.Position), reference);
				if (!(num2 >= num))
				{
					num = num2;
					result = bed.Position.y;
				}
			}
			return result;
		}

		private static Vector2 ToXZ(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(position.x, position.z);
		}

		private static Vector3 ToXYZ(Vector2 position, float y)
		{
			//IL_0000: 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)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(position.x, y, position.y);
		}
	}
}
namespace GK2ScarecrowPlots.Configuration
{
	internal sealed class LegacyConfig
	{
		internal bool Found;

		internal bool Enabled = true;

		internal bool DebugLogging;

		internal string CreatedPlotIds = string.Empty;
	}
	internal static class ConfigMigration
	{
		internal static LegacyConfig ReadLegacy(string path)
		{
			LegacyConfig legacyConfig = new LegacyConfig();
			if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
			{
				return legacyConfig;
			}
			string text = string.Empty;
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (string.IsNullOrWhiteSpace(text2) || text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2);
					continue;
				}
				int num = text2.IndexOf('=');
				if (num >= 0)
				{
					string text3 = text2.Substring(0, num).Trim();
					string text4 = text2.Substring(num + 1).Trim();
					bool result2;
					if (text == "General" && text3 == "Enabled" && bool.TryParse(text4, out var result))
					{
						legacyConfig.Enabled = result;
						legacyConfig.Found = true;
					}
					else if (text == "Debug" && text3 == "EnableDebugLogging" && bool.TryParse(text4, out result2))
					{
						legacyConfig.DebugLogging = result2;
						legacyConfig.Found = true;
					}
					else if (text == "Internal" && text3 == "CreatedPlotIds")
					{
						legacyConfig.CreatedPlotIds = text4;
						legacyConfig.Found = true;
					}
				}
			}
			return legacyConfig;
		}

		internal static void RemoveLegacySections(string path)
		{
			if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
			{
				return;
			}
			string[] array = File.ReadAllLines(path);
			List<string> list = new List<string>();
			string text = string.Empty;
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				string text3 = text2.Trim();
				if (text3.StartsWith("[") && text3.EndsWith("]"))
				{
					text = text3.Substring(1, text3.Length - 2);
				}
				switch (text)
				{
				case "General":
				case "Debug":
				case "Internal":
					continue;
				}
				list.Add(text2);
			}
			File.WriteAllLines(path, list);
		}
	}
	internal static class ModConfig
	{
		private const string SectionGeneral = "01 - General";

		private const string SectionVisual = "02 - Visual";

		private const string SectionDebug = "90 - Debug";

		private const string SectionInternal = "99 - Internal";

		private static ConfigFile configFile;

		internal static ConfigEntry<bool> Enabled { get; private set; }

		internal static ConfigEntry<bool> HideScarecrow { get; private set; }

		internal static ConfigEntry<bool> DebugLogging { get; private set; }

		internal static ConfigEntry<string> CreatedPlotIds { get; private set; }

		internal static void Initialize(ConfigFile config, LegacyConfig legacy)
		{
			configFile = config;
			Enabled = config.Bind<bool>("01 - General", "Enabled", true, "Adds the two garden plots occupied by the scarecrow. Set to false to remove plots previously created by this mod. Any crops planted on those plots will also be removed.");
			HideScarecrow = config.Bind<bool>("02 - Visual", "HideScarecrow", false, "Hides the scarecrow visual and its collision area. The scarecrow will return the next time the garden is loaded after this setting is disabled.");
			DebugLogging = config.Bind<bool>("90 - Debug", "EnableDebugLogging", false, "Enables detailed diagnostic logging for garden detection and plot creation.");
			CreatedPlotIds = config.Bind<string>("99 - Internal", "CreatedPlotIds", string.Empty, "Internal list of garden plots created by this mod. Do not edit manually.");
			if (legacy != null && legacy.Found)
			{
				Enabled.Value = legacy.Enabled;
				DebugLogging.Value = legacy.DebugLogging;
				CreatedPlotIds.Value = legacy.CreatedPlotIds;
				SaveIfAutoSaveDisabled();
			}
		}

		internal static void SaveIfAutoSaveDisabled()
		{
			if (configFile != null && !configFile.SaveOnConfigSet)
			{
				configFile.Save();
			}
		}
	}
}