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();
}
}
}
}