Decompiled source of YggShootGrowth v0.1.1

YggShootGrowth.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("YggShootGrowth")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+cffe211b896869750bc785eb080af69525e11f38")]
[assembly: AssemblyProduct("YggShootGrowth")]
[assembly: AssemblyTitle("YggShootGrowth")]
[assembly: AssemblyVersion("0.1.1.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 YggShootGrowth
{
	internal class GrowingYggShoot : MonoBehaviour
	{
		internal static readonly int RegrownAtKey = StringExtensionMethods.GetStableHashCode("YggShootGrowth_regrownAt");

		private const string VisualName = "beech";

		private const float AnimationTime = 0.3f;

		private const double FreshSeconds = 3.0;

		private void Start()
		{
			ZNetView component = ((Component)this).GetComponent<ZNetView>();
			ZDO val = (Object.op_Implicit((Object)(object)component) ? component.GetZDO() : null);
			if (val == null || !Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			long num = val.GetLong(RegrownAtKey, 0L);
			if (num != 0L && !((ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds > 3.0))
			{
				Transform val2 = ((Component)this).transform.Find("beech");
				if (Object.op_Implicit((Object)(object)val2))
				{
					((MonoBehaviour)this).StartCoroutine(GrowAnimation(((Component)val2).gameObject));
				}
			}
		}

		private IEnumerator GrowAnimation(GameObject visual)
		{
			GameObject animated = Object.Instantiate<GameObject>(visual, visual.transform.position, visual.transform.rotation, ((Component)this).transform);
			animated.isStatic = false;
			LODGroup component = ((Component)this).GetComponent<LODGroup>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.fadeMode = (LODFadeMode)0;
			}
			visual.SetActive(false);
			Vector3 fullScale = visual.transform.localScale;
			for (float t = 0f; t < 0.3f; t += Time.deltaTime)
			{
				animated.transform.localScale = fullScale * Mathf.Clamp01(t / 0.3f);
				yield return null;
			}
			Object.Destroy((Object)(object)animated);
			visual.SetActive(true);
		}
	}
	[HarmonyPatch(typeof(Plant), "HaveGrowSpace")]
	internal static class PlantHaveGrowSpacePatch
	{
		private static readonly Collider[] s_colliders = (Collider[])(object)new Collider[30];

		private static int s_spaceMask;

		private static bool Prefix(Plant __instance, ref bool __result)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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)
			if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<GrowingYggShoot>()))
			{
				return true;
			}
			if (s_spaceMask == 0)
			{
				s_spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			}
			Transform transform = ((Component)__instance).transform;
			RaycastHit support2;
			Collider support = ((YggShootGrowthPlugin.Instance.GrowOnRocksAndRoots.Value && ShootSurface.TryFindSupportBelow(transform.position, out support2)) ? ((RaycastHit)(ref support2)).collider : null);
			int num = Physics.OverlapSphereNonAlloc(transform.position, __instance.m_growRadius, s_colliders, s_spaceMask);
			for (int i = 0; i < num; i++)
			{
				Collider val = s_colliders[i];
				if (!((Component)val).transform.IsChildOf(transform) && !ShootSurface.IsPartOfSupport(val, support))
				{
					Plant component = ((Component)val).GetComponent<Plant>();
					if (!Object.op_Implicit((Object)(object)component) || ((Object)(object)component != (Object)(object)__instance && (int)component.GetStatus() == 0))
					{
						__result = false;
						return false;
					}
				}
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
	internal static class ZDOManHandleDestroyedZDOPatch
	{
		private static void Prefix(ZDOMan __instance, ZDOID uid)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = __instance.GetZDO(uid);
			if (zDO != null)
			{
				YggShootGrowthPlugin.Regrowth?.OnZDODestroyed(zDO);
			}
		}
	}
	[HarmonyPatch(typeof(HoverText), "GetHoverText")]
	internal static class HoverTextGetHoverTextPatch
	{
		private static void Postfix(HoverText __instance, ref string __result)
		{
			Plant val = default(Plant);
			if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<GrowingYggShoot>()) && ((Component)__instance).TryGetComponent<Plant>(ref val))
			{
				__result = val.GetHoverText();
			}
		}
	}
	internal class RegrowthTracker
	{
		private enum TrackerMode
		{
			Inactive,
			Host,
			Client
		}

		private enum RegrowthKind
		{
			Stump,
			SmallShoot
		}

		private struct PendingRegrowth
		{
			public Vector3 Position;

			public long DestroyedTicks;

			public RegrowthKind Kind;
		}

		private const float ProcessInterval = 5f;

		private const float OccupiedDistance = 1f;

		private const int SpawnAttempts = 8;

		private static readonly int SmallShootHash = StringExtensionMethods.GetStableHashCode("YggaShoot_small1");

		private static readonly int StumpHash = StringExtensionMethods.GetStableHashCode("ShootStump");

		private readonly YggShootGrowthPlugin _plugin;

		private readonly ManualLogSource _logger;

		private readonly List<PendingRegrowth> _pending = new List<PendingRegrowth>();

		private readonly List<ZDO> _zdoBuffer = new List<ZDO>();

		private readonly Collider[] _colliders = (Collider[])(object)new Collider[30];

		private int _spaceMask;

		private TrackerMode _mode;

		private long _worldUid;

		private string _worldName;

		private float _nextProcessTime;

		private bool _clientQueueDirty;

		public RegrowthTracker(YggShootGrowthPlugin plugin, ManualLogSource logger)
		{
			_plugin = plugin;
			_logger = logger;
			ZNet.WorldSaveStarted = (Action)Delegate.Combine(ZNet.WorldSaveStarted, new Action(OnWorldSaveStarted));
		}

		private static TrackerMode CurrentMode()
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.GetWorldName() == null)
			{
				return TrackerMode.Inactive;
			}
			if (ZNet.instance.IsServer())
			{
				return TrackerMode.Host;
			}
			if (!ModCompatibility.IsModuleOnServer("irti.yggshootgrowth"))
			{
				return TrackerMode.Client;
			}
			return TrackerMode.Inactive;
		}

		public void Update()
		{
			TrackerMode trackerMode = CurrentMode();
			long num = ((trackerMode == TrackerMode.Inactive) ? 0 : ZNet.instance.GetWorldUID());
			if (trackerMode != _mode || num != _worldUid)
			{
				_pending.Clear();
				_clientQueueDirty = false;
				_mode = trackerMode;
				_worldUid = num;
				_worldName = ((trackerMode == TrackerMode.Inactive) ? null : ZNet.instance.GetWorldName());
				if (trackerMode != TrackerMode.Inactive)
				{
					_logger.LogInfo((object)((trackerMode == TrackerMode.Host) ? "Tracking regrowth for all destroyed shoots and stumps (host)." : "Server does not have this mod; tracking regrowth for shoots and stumps this game controls."));
					Load();
				}
			}
			if (trackerMode != TrackerMode.Inactive && !(Time.time < _nextProcessTime))
			{
				_nextProcessTime = Time.time + 5f;
				ProcessPending();
				if (_clientQueueDirty)
				{
					_clientQueueDirty = false;
					Save();
				}
			}
		}

		public void OnZDODestroyed(ZDO zdo)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (_mode == TrackerMode.Inactive || (_mode == TrackerMode.Client && zdo.GetOwner() != ZDOMan.GetSessionID()))
			{
				return;
			}
			int prefab = zdo.GetPrefab();
			RegrowthKind kind;
			if (prefab == StumpHash && _plugin.StumpRegrowth.Value)
			{
				kind = RegrowthKind.Stump;
			}
			else
			{
				if (prefab != SmallShootHash || !_plugin.SmallShootRegrowth.Value)
				{
					return;
				}
				kind = RegrowthKind.SmallShoot;
			}
			Vector3 position = zdo.GetPosition();
			foreach (PendingRegrowth item in _pending)
			{
				if (Utils.DistanceXZ(item.Position, position) < 1f)
				{
					return;
				}
			}
			_pending.Add(new PendingRegrowth
			{
				Position = position,
				DestroyedTicks = ZNet.instance.GetTime().Ticks,
				Kind = kind
			});
			MarkChanged();
		}

		private void MarkChanged()
		{
			if (_mode == TrackerMode.Client)
			{
				_clientQueueDirty = true;
			}
		}

		private bool IsDue(PendingRegrowth pending, long now)
		{
			bool value;
			float value2;
			if (pending.Kind == RegrowthKind.Stump)
			{
				value = _plugin.StumpRegrowth.Value;
				value2 = _plugin.StumpRegrowthDelaySeconds.Value;
			}
			else
			{
				value = _plugin.SmallShootRegrowth.Value;
				value2 = _plugin.SmallShootRegrowthDelaySeconds.Value;
			}
			if (value)
			{
				return now - pending.DestroyedTicks >= TimeSpan.FromSeconds(value2).Ticks;
			}
			return false;
		}

		private void ProcessPending()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			long ticks = ZNet.instance.GetTime().Ticks;
			for (int num = _pending.Count - 1; num >= 0; num--)
			{
				PendingRegrowth pending = _pending[num];
				if (IsDue(pending, ticks) && ZNetScene.instance.IsAreaReady(pending.Position))
				{
					if (IsOccupiedByShootFamily(pending.Position))
					{
						_pending.RemoveAt(num);
						MarkChanged();
					}
					else
					{
						FindSpawnPosition(pending.Position, out var position);
						GameObject prefab = ZNetScene.instance.GetPrefab(SmallShootHash);
						if (!Object.op_Implicit((Object)(object)prefab))
						{
							break;
						}
						ZNetView component = Object.Instantiate<GameObject>(prefab, position, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)).GetComponent<ZNetView>();
						if (Object.op_Implicit((Object)(object)component) && component.GetZDO() != null)
						{
							component.GetZDO().Set(GrowingYggShoot.RegrownAtKey, ticks);
						}
						_pending.RemoveAt(num);
						MarkChanged();
					}
				}
			}
		}

		private void FindSpawnPosition(Vector3 origin, out Vector3 position)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0037: 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)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			float value = _plugin.RegrowthSpreadRadius.Value;
			if (value > 0f)
			{
				for (int i = 0; i < 8; i++)
				{
					float num = ((i < 4) ? (value * 0.5f) : value);
					Vector2 val = Random.insideUnitCircle * num;
					position = new Vector3(origin.x + val.x, origin.y, origin.z + val.y);
					if (IsValidSpawnPosition(ref position))
					{
						return;
					}
				}
			}
			position = origin;
			PlaceOnSurfaceBelow(ref position);
		}

		private static void PlaceOnSurfaceBelow(ref Vector3 position)
		{
			//IL_0001: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			float y = default(float);
			if (ShootSurface.TryFindSupportBelow(position, out var support))
			{
				position.y = ((RaycastHit)(ref support)).point.y;
			}
			else if (ZoneSystem.instance.GetGroundHeight(position, ref y))
			{
				position.y = y;
			}
		}

		private bool IsValidSpawnPosition(ref Vector3 position)
		{
			//IL_002f: 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_004f: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			if (!ShootSurface.TryFindTopSupport(ref position, _plugin.GrowOnRocksAndRoots.Value, out var support) || position.y < ZoneSystem.instance.m_waterLevel)
			{
				return false;
			}
			Heightmap val = Heightmap.FindHeightmap(position);
			if (!Object.op_Implicit((Object)(object)val) || (val.GetBiome(position, 0.02f, false) & 0x200) == 0)
			{
				return false;
			}
			return HaveSpace(position, support);
		}

		private bool IsOccupiedByShootFamily(Vector3 position)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0053: 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)
			_zdoBuffer.Clear();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(position), new SimulationDistance(1, 0, false), _zdoBuffer, (List<ZDO>)null);
			foreach (ZDO item in _zdoBuffer)
			{
				if (ShootSurface.ShootFamilyHashes.Contains(item.GetPrefab()) && Utils.DistanceXZ(item.GetPosition(), position) < 1f)
				{
					return true;
				}
			}
			return false;
		}

		private bool HaveSpace(Vector3 position, Collider support)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (_spaceMask == 0)
			{
				_spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			}
			int num = Physics.OverlapSphereNonAlloc(position, _plugin.GrowRadius.Value, _colliders, _spaceMask);
			for (int i = 0; i < num; i++)
			{
				if (!ShootSurface.IsPartOfSupport(_colliders[i], support))
				{
					return false;
				}
			}
			return true;
		}

		private string SaveFilePath()
		{
			string arg = string.Join("_", _worldName.Split(Path.GetInvalidFileNameChars()));
			string arg2 = ((_mode == TrackerMode.Client) ? ".client" : "");
			return Path.Combine(Path.Combine(Paths.ConfigPath, "YggShootGrowth"), $"{arg}_{_worldUid}{arg2}.regrowth");
		}

		private void Load()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (!_plugin.RegrowthSurvivesRestart.Value)
			{
				return;
			}
			string text = SaveFilePath();
			if (!File.Exists(text))
			{
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(text);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { ';' });
					if (array2.Length == 5)
					{
						_pending.Add(new PendingRegrowth
						{
							Position = new Vector3(float.Parse(array2[0], CultureInfo.InvariantCulture), float.Parse(array2[1], CultureInfo.InvariantCulture), float.Parse(array2[2], CultureInfo.InvariantCulture)),
							DestroyedTicks = long.Parse(array2[3], CultureInfo.InvariantCulture),
							Kind = (RegrowthKind)int.Parse(array2[4], CultureInfo.InvariantCulture)
						});
					}
				}
				_logger.LogInfo((object)$"Loaded {_pending.Count} pending regrowth(s) from {text}.");
			}
			catch (Exception ex)
			{
				_logger.LogWarning((object)("Could not read pending regrowths from " + text + ": " + ex.Message));
			}
		}

		private void OnWorldSaveStarted()
		{
			if (_mode == TrackerMode.Host)
			{
				Save();
			}
		}

		private void Save()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (_mode == TrackerMode.Inactive || _worldUid == 0L || !_plugin.RegrowthSurvivesRestart.Value)
			{
				return;
			}
			string text = SaveFilePath();
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(text));
				List<string> list = new List<string>(_pending.Count);
				foreach (PendingRegrowth item in _pending)
				{
					string[] array = new string[5];
					float x = item.Position.x;
					array[0] = x.ToString("R", CultureInfo.InvariantCulture);
					x = item.Position.y;
					array[1] = x.ToString("R", CultureInfo.InvariantCulture);
					x = item.Position.z;
					array[2] = x.ToString("R", CultureInfo.InvariantCulture);
					long destroyedTicks = item.DestroyedTicks;
					array[3] = destroyedTicks.ToString(CultureInfo.InvariantCulture);
					int kind = (int)item.Kind;
					array[4] = kind.ToString(CultureInfo.InvariantCulture);
					list.Add(string.Join(";", array));
				}
				File.WriteAllLines(text, list.ToArray());
			}
			catch (Exception ex)
			{
				_logger.LogWarning((object)("Could not save pending regrowths to " + text + ": " + ex.Message));
			}
		}
	}
	internal static class ShootSurface
	{
		private const float SearchMargin = 1f;

		internal static readonly HashSet<int> ShootFamilyHashes = CreateShootFamilyHashes();

		private static readonly RaycastHit[] s_rayHits = (RaycastHit[])(object)new RaycastHit[16];

		private static int s_solidRayMask;

		private static int s_supportMask;

		private static int s_terrainLayer = -1;

		private static HashSet<int> CreateShootFamilyHashes()
		{
			HashSet<int> hashSet = new HashSet<int>
			{
				StringExtensionMethods.GetStableHashCode("YggaShoot_small1"),
				StringExtensionMethods.GetStableHashCode("ShootStump")
			};
			string[] grownShootPrefabs = YggShootGrowthPlugin.GrownShootPrefabs;
			foreach (string text in grownShootPrefabs)
			{
				hashSet.Add(StringExtensionMethods.GetStableHashCode(text));
			}
			return hashSet;
		}

		private static void EnsureMasks()
		{
			if (s_solidRayMask == 0)
			{
				s_solidRayMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
				s_supportMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "terrain" });
				s_terrainLayer = LayerMask.NameToLayer("terrain");
			}
		}

		internal static bool IsTerrain(Collider collider)
		{
			EnsureMasks();
			return ((Component)collider).gameObject.layer == s_terrainLayer;
		}

		internal static bool IsSupport(Collider collider)
		{
			EnsureMasks();
			if (Object.op_Implicit((Object)(object)collider.attachedRigidbody) || (s_supportMask & (1 << ((Component)collider).gameObject.layer)) == 0)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent<TreeBase>()) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent<TreeLog>()))
			{
				return !IsShootFamily(collider);
			}
			return false;
		}

		internal static bool IsShootFamily(Collider collider)
		{
			ZNetView componentInParent = ((Component)collider).GetComponentInParent<ZNetView>();
			ZDO val = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.GetZDO() : null);
			if (val != null)
			{
				return ShootFamilyHashes.Contains(val.GetPrefab());
			}
			return false;
		}

		internal static bool TryFindTopSupport(ref Vector3 position, bool allowRocksAndRoots, out Collider support)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			EnsureMasks();
			support = null;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(new Vector3(position.x, position.y + 1000f, position.z), Vector3.down, ref val, 2000f, s_solidRayMask) || !IsSupport(((RaycastHit)(ref val)).collider))
			{
				return false;
			}
			if (!allowRocksAndRoots && !IsTerrain(((RaycastHit)(ref val)).collider))
			{
				return false;
			}
			position.y = ((RaycastHit)(ref val)).point.y;
			support = ((RaycastHit)(ref val)).collider;
			return true;
		}

		internal static bool TryFindSupportBelow(Vector3 position, out RaycastHit support)
		{
			//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)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			EnsureMasks();
			support = default(RaycastHit);
			int num = Physics.RaycastNonAlloc(position + Vector3.up * 1f, Vector3.down, s_rayHits, 1000f, s_supportMask);
			float num2 = float.MaxValue;
			for (int i = 0; i < num; i++)
			{
				RaycastHit val = s_rayHits[i];
				if (((RaycastHit)(ref val)).distance < num2 && IsSupport(((RaycastHit)(ref val)).collider))
				{
					num2 = ((RaycastHit)(ref val)).distance;
					support = val;
				}
			}
			return num2 != float.MaxValue;
		}

		internal static bool IsPartOfSupport(Collider collider, Collider support)
		{
			if (!Object.op_Implicit((Object)(object)support))
			{
				return false;
			}
			if ((Object)(object)collider == (Object)(object)support)
			{
				return true;
			}
			ZNetView componentInParent = ((Component)support).GetComponentInParent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)componentInParent) || Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<LocationProxy>()))
			{
				return false;
			}
			return ((Component)collider).transform.IsChildOf(((Component)componentInParent).transform);
		}
	}
	[BepInPlugin("irti.yggshootgrowth", "YggShootGrowth", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class YggShootGrowthPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "irti.yggshootgrowth";

		public const string PluginName = "YggShootGrowth";

		public const string PluginVersion = "0.1.1";

		internal const string SmallShootPrefab = "YggaShoot_small1";

		internal static readonly string[] GrownShootPrefabs = new string[3] { "YggaShoot1", "YggaShoot2", "YggaShoot3" };

		internal const string StumpPrefab = "ShootStump";

		private const string StateDummyName = "YggShootGrowth_state";

		private ConfigEntry<float> _growTimeMin;

		private ConfigEntry<float> _growTimeMax;

		private FileSystemWatcher _configWatcher;

		private volatile bool _configFileChanged;

		internal static YggShootGrowthPlugin Instance { get; private set; }

		internal static RegrowthTracker Regrowth { get; private set; }

		internal ConfigEntry<float> GrowRadius { get; private set; }

		internal ConfigEntry<bool> GrowOnRocksAndRoots { get; private set; }

		internal ConfigEntry<bool> StumpRegrowth { get; private set; }

		internal ConfigEntry<float> StumpRegrowthDelaySeconds { get; private set; }

		internal ConfigEntry<bool> SmallShootRegrowth { get; private set; }

		internal ConfigEntry<float> SmallShootRegrowthDelaySeconds { get; private set; }

		internal ConfigEntry<float> RegrowthSpreadRadius { get; private set; }

		internal ConfigEntry<bool> RegrowthSurvivesRestart { get; private set; }

		private void Awake()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			_growTimeMin = ((BaseUnityPlugin)this).Config.Bind<float>("Growth", "GrowTimeMin", 30000f, new ConfigDescription("Minimum world-time seconds before a small shoot grows (one in-game day is 1800 s). Vanilla Beech/Pine saplings use 3000-5000. Changes apply to loaded shoots immediately.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 10000000f), Array.Empty<object>()));
			_growTimeMax = ((BaseUnityPlugin)this).Config.Bind<float>("Growth", "GrowTimeMax", 50000f, new ConfigDescription("Maximum world-time seconds before a small shoot grows. Each shoot picks a fixed value between min and max.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 10000000f), Array.Empty<object>()));
			GrowRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Growth", "GrowRadius", 2f, new ConfigDescription("Radius that must be free of other objects for the shoot to grow (vanilla crowding check). Vanilla saplings use 2-3. Also used when a regrown small shoot is about to appear.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			GrowOnRocksAndRoots = ((BaseUnityPlugin)this).Config.Bind<bool>("Growth", "GrowOnRocksAndRoots", false, "Shoots standing on rocks or roots can grow, and regrown shoots may appear on them. When off, such shoots report 'needs room to grow' as in vanilla, and regrowth only picks spots on terrain (the fallback to the original spot can still land on the rock or root it stood on).");
			StumpRegrowth = ((BaseUnityPlugin)this).Config.Bind<bool>("Regrowth", "StumpRegrowth", true, "When a Yggdrasil shoot stump is destroyed, a new small shoot appears in its place after a delay.");
			StumpRegrowthDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Regrowth", "StumpRegrowthDelaySeconds", 1800f, new ConfigDescription("World-time seconds after a stump is destroyed before the new small shoot appears (one in-game day is 1800 s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000000f), Array.Empty<object>()));
			SmallShootRegrowth = ((BaseUnityPlugin)this).Config.Bind<bool>("Regrowth", "SmallShootRegrowth", true, "When a small Yggdrasil shoot is destroyed, a new small shoot appears in its place after a delay.");
			SmallShootRegrowthDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Regrowth", "SmallShootRegrowthDelaySeconds", 900f, new ConfigDescription("World-time seconds after a small shoot is destroyed before the new small shoot appears (one in-game day is 1800 s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000000f), Array.Empty<object>()));
			RegrowthSpreadRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Regrowth", "RegrowthSpreadRadius", 4f, new ConfigDescription("The new small shoot appears at a random spot up to this many meters from where the old one stood. 0 uses the exact same spot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			RegrowthSurvivesRestart = ((BaseUnityPlugin)this).Config.Bind<bool>("Regrowth", "RegrowthSurvivesRestart", true, "Save pending regrowths with the world (in BepInEx/config/YggShootGrowth) so they survive a restart. When off, pending regrowths are forgotten when the world is closed.");
			_growTimeMin.SettingChanged += delegate
			{
				ApplyGrowthSettingsToAll();
			};
			_growTimeMax.SettingChanged += delegate
			{
				ApplyGrowthSettingsToAll();
			};
			GrowRadius.SettingChanged += delegate
			{
				ApplyGrowthSettingsToAll();
			};
			WatchConfigFile();
			Regrowth = new RegrowthTracker(this, ((BaseUnityPlugin)this).Logger);
			PrefabManager.OnVanillaPrefabsAvailable += AddPlantToSmallShoot;
			new Harmony("irti.yggshootgrowth").PatchAll(typeof(YggShootGrowthPlugin).Assembly);
		}

		private void Update()
		{
			if (_configFileChanged)
			{
				_configFileChanged = false;
				ReloadConfig();
			}
			Regrowth.Update();
		}

		private void OnDestroy()
		{
			_configWatcher?.Dispose();
		}

		private void WatchConfigFile()
		{
			_configWatcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
				IncludeSubdirectories = false
			};
			_configWatcher.Changed += delegate
			{
				_configFileChanged = true;
			};
			_configWatcher.Created += delegate
			{
				_configFileChanged = true;
			};
			_configWatcher.Renamed += delegate
			{
				_configFileChanged = true;
			};
			_configWatcher.EnableRaisingEvents = true;
		}

		private void ReloadConfig()
		{
			if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				return;
			}
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Reloaded config file.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not reload config file: " + ex.Message));
			}
		}

		private void ApplyGrowthSettings(Plant plant)
		{
			plant.m_growTime = Mathf.Min(_growTimeMin.Value, _growTimeMax.Value);
			plant.m_growTimeMax = Mathf.Max(_growTimeMin.Value, _growTimeMax.Value);
			plant.m_growRadius = GrowRadius.Value;
		}

		private void ApplyGrowthSettingsToAll()
		{
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("YggaShoot_small1") : null);
			Plant plant = default(Plant);
			if (Object.op_Implicit((Object)(object)val) && val.TryGetComponent<Plant>(ref plant))
			{
				ApplyGrowthSettings(plant);
			}
			int num = 0;
			GrowingYggShoot[] array = Object.FindObjectsByType<GrowingYggShoot>((FindObjectsSortMode)0);
			Plant plant2 = default(Plant);
			for (int i = 0; i < array.Length; i++)
			{
				if (((Component)array[i]).TryGetComponent<Plant>(ref plant2))
				{
					ApplyGrowthSettings(plant2);
					num++;
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)($"Applied grow time {Mathf.Min(_growTimeMin.Value, _growTimeMax.Value)}-" + $"{Mathf.Max(_growTimeMin.Value, _growTimeMax.Value)} s and radius {GrowRadius.Value} to {num} loaded shoot(s)."));
		}

		private void AddPlantToSmallShoot()
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab("YggaShoot_small1");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Prefab 'YggaShoot_small1' not found; shoots will not grow.");
				return;
			}
			List<GameObject> list = new List<GameObject>();
			string[] grownShootPrefabs = GrownShootPrefabs;
			foreach (string text in grownShootPrefabs)
			{
				GameObject prefab2 = PrefabManager.Instance.GetPrefab(text);
				if (Object.op_Implicit((Object)(object)prefab2))
				{
					list.Add(prefab2);
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Prefab '" + text + "' not found; it will not be used as a grown shoot."));
				}
			}
			if (list.Count == 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"No grown shoot prefabs found; shoots will not grow.");
				return;
			}
			Plant val = default(Plant);
			if (!prefab.TryGetComponent<Plant>(ref val))
			{
				val = prefab.AddComponent<Plant>();
			}
			if (!Object.op_Implicit((Object)(object)prefab.GetComponent<GrowingYggShoot>()))
			{
				prefab.AddComponent<GrowingYggShoot>();
			}
			val.m_name = "$prop_yggashoot";
			val.m_grownPrefabs = list.ToArray();
			ApplyGrowthSettings(val);
			val.m_biome = (Biome)512;
			val.m_minScale = 1f;
			val.m_maxScale = 1f;
			val.m_destroyIfCantGrow = false;
			Transform val2 = prefab.transform.Find("YggShootGrowth_state");
			if (!Object.op_Implicit((Object)(object)val2))
			{
				val2 = new GameObject("YggShootGrowth_state").transform;
				val2.SetParent(prefab.transform, false);
			}
			AccessTools.Field(typeof(Plant), "m_healthy").SetValue(val, ((Component)val2).gameObject);
			AccessTools.Field(typeof(Plant), "m_unhealthy").SetValue(val, ((Component)val2).gameObject);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("YggaShoot_small1 will grow into " + string.Join(", ", list.ConvertAll((GameObject p) => ((Object)p).name)) + " " + $"after {val.m_growTime}-{val.m_growTimeMax} s."));
		}
	}
	internal static class PluginVersionInfo
	{
		public const string Version = "0.1.1";
	}
}