Decompiled source of Sproti v0.5.2

Sproti.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Sproti")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Sproti")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7b1c5e2a-9d34-4f86-a0e7-3c58d1f4b926")]
[assembly: AssemblyFileVersion("0.5.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.2.0")]
namespace Sproti;

internal static class CheatCommands
{
	private class FindTree : ConsoleCommand
	{
		public override string Name => "sproti_findtree";

		public override string Help => "Ping your nearest Sproti tree on the map and list positions (with devcommands: all Sproti trees)";

		public override bool IsCheat => false;

		public override void Run(string[] args)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				TreeLimit.Find(Player.m_localPlayer, ((Terminal)Console.instance).IsCheatsEnabled(), "Sproti_Tree");
			}
		}
	}

	private class FindNursery : ConsoleCommand
	{
		public override string Name => "sproti_findnursery";

		public override string Help => "Ping your Sproti's tree nursery on the map and list positions (with devcommands: all nurseries)";

		public override bool IsCheat => false;

		public override void Run(string[] args)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				TreeLimit.Find(Player.m_localPlayer, ((Terminal)Console.instance).IsCheatsEnabled(), "Sproti_NurseryMarker");
			}
		}
	}

	private class ReloadConfig : ConsoleCommand
	{
		public override string Name => "sproti_reload_config";

		public override string Help => "Reload Sproti's config file after editing it";

		public override bool IsCheat => false;

		public override void Run(string[] args)
		{
			((BaseUnityPlugin)Sproti.Instance).Config.Reload();
			Console.instance.Print("Sproti config reloaded");
		}
	}

	private class RecipeAdd : ConsoleCommand
	{
		public override string Name => "sproti_recipe_add";

		public override string Help => "Learn the Sproti tree (the nursery comes from the move-in scene)";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				RecipeUnlock.Learn(Player.m_localPlayer);
			}
		}
	}

	private class RecipeRemove : ConsoleCommand
	{
		public override string Name => "sproti_recipe_remove";

		public override string Help => "Forget the Sproti tree and nursery, replay the move-in scene";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				RecipeUnlock.Forget(Player.m_localPlayer);
			}
		}
	}

	private class Free : ConsoleCommand
	{
		public override string Name => "sproti_free";

		public override string Help => "Freed Sproti appears in front of you";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			//IL_0027: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_007d: 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)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)GameCamera.instance))
			{
				Vector3 val = ((Component)GameCamera.instance).transform.forward;
				val.y = 0f;
				val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : ((Component)localPlayer).transform.forward);
				FreedSproti.Spawn(((Component)localPlayer).transform.position + val * 3f, ((Component)localPlayer).transform.position, ((Component)localPlayer).transform.position, terrainOnly: false);
			}
		}
	}

	private class MoveIn : ConsoleCommand
	{
		public override string Name => "sproti_movein";

		public override string Help => "Move-in scene in front of you";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			//IL_0027: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_008b: 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)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)GameCamera.instance))
			{
				Vector3 val = ((Component)GameCamera.instance).transform.forward;
				val.y = 0f;
				val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : ((Component)localPlayer).transform.forward);
				Vector3 val2 = ((Component)localPlayer).transform.position + val * 3f;
				FreedSproti.Spawn(val2, ((Component)localPlayer).transform.position, val2 + val * 3f, terrainOnly: false, moveIn: true);
			}
		}
	}

	public static void Register()
	{
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RecipeAdd());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RecipeRemove());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new Free());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new MoveIn());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new FindTree());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new FindNursery());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ReloadConfig());
	}
}
internal static class Cultivating
{
	[HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")]
	private static class RegisterOp
	{
		private static void Prefix(ObjectDB __instance)
		{
			TerrainOp[] array = (TerrainOp[])(object)new TerrainOp[2] { s_op, s_smallOp };
			foreach (TerrainOp val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && !__instance.m_terrainOps.Contains(val))
				{
					__instance.m_terrainOps.Add(val);
				}
			}
		}
	}

	public const string CultivatorItem = "Cultivator";

	private const string VanillaOp = "cultivate_v2";

	private const string OpPrefab = "Sproti_Cultivate";

	private const float PaintRadius = 1.5f;

	private const string SmallOpPrefab = "Sproti_CultivateSmall";

	private const float SmallPaintRadius = 0.5f;

	private const int SpotStep = 3;

	private const float BuildingDistance = 1.5f;

	private const float HouseRadius = 2.5f;

	private const float StandHeight = 0.5f;

	private const float StandRadius = 0.4f;

	private static TerrainOp s_op;

	private static TerrainOp s_smallOp;

	private static Piece s_vanillaPiece;

	private static int SpaceMask => LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });

	private static int StandMask => LayerMask.GetMask(new string[4] { "Default", "static_solid", "Default_small", "piece" });

	public static void CreatePrefab()
	{
		s_op = CreateOp("Sproti_Cultivate", 1.5f);
		s_smallOp = (Object.op_Implicit((Object)(object)s_op) ? CreateOp("Sproti_CultivateSmall", 0.5f) : null);
		if (Object.op_Implicit((Object)(object)s_op))
		{
			s_vanillaPiece = Cache.GetPrefab<GameObject>("cultivate_v2").GetComponent<Piece>();
		}
	}

	private static TerrainOp CreateOp(string name, float paintRadius)
	{
		GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, "cultivate_v2");
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<TerrainOp>()))
		{
			Sproti.Log.LogWarning((object)"terrain op cultivate_v2 not found, Sproti cannot cultivate");
			return null;
		}
		foreach (Transform item in ((IEnumerable)val.transform).Cast<Transform>().ToList())
		{
			Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
		}
		Object.DestroyImmediate((Object)(object)val.GetComponent<Piece>());
		TerrainOp component = val.GetComponent<TerrainOp>();
		Settings settings = component.m_settings;
		settings.m_smooth = false;
		settings.m_level = false;
		settings.m_raise = false;
		settings.m_paintRadius = paintRadius;
		settings.m_halfOffset = false;
		return component;
	}

	public static ItemData FindCultivator(Inventory inventory)
	{
		return ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => Object.op_Implicit((Object)(object)item.m_dropPrefab) && ((Object)item.m_dropPrefab).name == "Cultivator"));
	}

	public static IEnumerator FindSpots(SprotiTree tree, Func<Vector3, bool> blocked, List<Vector3> spots)
	{
		if (!Object.op_Implicit((Object)(object)s_op) || !Object.op_Implicit((Object)(object)s_smallOp))
		{
			yield break;
		}
		Vector3 center = ((Component)tree).transform.position;
		int cx = Mathf.RoundToInt(center.x);
		int cz = Mathf.RoundToInt(center.z);
		float radius = tree.Radius;
		float reach = radius + 1.5f;
		int steps = Mathf.CeilToInt(reach / 3f);
		Vector3 val = default(Vector3);
		float y = default(float);
		for (int x = -steps; x <= steps; x++)
		{
			for (int z = -steps; z <= steps; z++)
			{
				if (SearchBudget.Exhausted)
				{
					yield return null;
					if (!Object.op_Implicit((Object)(object)tree))
					{
						yield break;
					}
				}
				((Vector3)(ref val))..ctor((float)(cx + x * 3), 0f, (float)(cz + z * 3));
				if (Utils.DistanceXZ(val, center) <= reach && ZoneSystem.instance.GetGroundHeight(val, ref y))
				{
					val.y = y;
					if (Paintable(val, tree, out var _).Count > 0 && FindStand(val, out var stand) && !blocked(stand))
					{
						spots.Add(stand);
					}
				}
			}
		}
	}

	public static bool CultivateAt(SprotiTree tree, Vector3 stand)
	{
		//IL_001a: 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_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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_004d: 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_00b3: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: 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_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)s_op) || !Object.op_Implicit((Object)(object)s_smallOp))
		{
			return false;
		}
		Vector3 val = SpotOf(stand, ((Component)tree).transform.position);
		bool whole;
		List<Vector3> list = Paintable(val, tree, out whole);
		if (list.Count == 0)
		{
			return false;
		}
		if (whole)
		{
			Object.Instantiate<GameObject>(((Component)s_op).gameObject, val, Quaternion.identity);
		}
		else
		{
			foreach (Vector3 item in list)
			{
				Object.Instantiate<GameObject>(((Component)s_smallOp).gameObject, item, Quaternion.identity);
			}
		}
		if (Object.op_Implicit((Object)(object)s_vanillaPiece))
		{
			s_vanillaPiece.m_placeEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
		}
		return true;
	}

	public static void CultivateUnderHouse(SprotiTree tree)
	{
		//IL_001f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)s_smallOp))
		{
			return;
		}
		long creator = ((Component)tree).GetComponent<Piece>().GetCreator();
		Vector3 position = ((Component)tree).transform.position;
		Vector3 val = default(Vector3);
		for (int i = Mathf.FloorToInt(position.x - 2.5f); i <= Mathf.CeilToInt(position.x + 2.5f); i++)
		{
			for (int j = Mathf.FloorToInt(position.z - 2.5f); j <= Mathf.CeilToInt(position.z + 2.5f); j++)
			{
				((Vector3)(ref val))..ctor((float)i, 0f, (float)j);
				if (!(Utils.DistanceXZ(val, position) > 2.5f) && !DoorPath.Covers(((Component)tree).transform, val))
				{
					val.y = ZoneSystem.instance.GetGroundHeight(val);
					if (!Protected(val, creator))
					{
						Object.Instantiate<GameObject>(((Component)s_smallOp).gameObject, val, Quaternion.identity);
					}
				}
			}
		}
	}

	private static Vector3 SpotOf(Vector3 stand, Vector3 center)
	{
		//IL_0000: 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_001b: 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_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.RoundToInt(center.x);
		int num2 = Mathf.RoundToInt(center.z);
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor((float)(num + Mathf.RoundToInt((stand.x - (float)num) / 3f) * 3), 0f, (float)(num2 + Mathf.RoundToInt((stand.z - (float)num2) / 3f) * 3));
		val.y = ZoneSystem.instance.GetGroundHeight(val);
		return val;
	}

	private static bool FindStand(Vector3 spot, out Vector3 stand)
	{
		//IL_0007: 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_000e: 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)
		//IL_004a: 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_004d: 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_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: 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)
		//IL_0078: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		foreach (Vector3 item in from v in Vertices(spot)
			orderby Utils.DistanceXZ(v, spot)
			select v)
		{
			Vector3 val = (stand = item);
			stand.y = ZoneSystem.instance.GetGroundHeight(val);
			if (!Physics.CheckSphere(stand + Vector3.up * 0.5f, 0.4f, StandMask, (QueryTriggerInteraction)1) && !Planting.InsideSolid(stand))
			{
				return true;
			}
		}
		stand = spot;
		return false;
	}

	private static IEnumerable<Vector3> Vertices(Vector3 spot)
	{
		//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)
		for (int x = -1; x <= 1; x++)
		{
			for (int z = -1; z <= 1; z++)
			{
				yield return spot + new Vector3((float)x, 0f, (float)z);
			}
		}
	}

	private static bool NeedsWork(Vector3 spot, Vector3 center, float radius)
	{
		//IL_0000: 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_0015: 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_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		foreach (Vector3 item in Vertices(spot))
		{
			Heightmap val = Heightmap.FindHeightmap(item);
			if (Object.op_Implicit((Object)(object)val) && Utils.DistanceXZ(item, center) <= radius && !val.IsCultivated(item))
			{
				return true;
			}
		}
		return false;
	}

	private static List<Vector3> Paintable(Vector3 spot, SprotiTree tree, out bool whole)
	{
		//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_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: 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)
		//IL_0056: 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_005d: 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_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: 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)
		List<Vector3> list = new List<Vector3>();
		whole = false;
		Vector3 position = ((Component)tree).transform.position;
		if (!NeedsWork(spot, position, tree.Radius))
		{
			return list;
		}
		whole = true;
		long creator = ((Component)tree).GetComponent<Piece>().GetCreator();
		bool flag = NearBuilding(spot, 3f, tree);
		foreach (Vector3 item in Vertices(spot))
		{
			Vector3 val = item;
			val.y = ZoneSystem.instance.GetGroundHeight(item);
			if (Protected(val, creator) || SprotiHouse.OnPath(((Component)tree).transform.InverseTransformPoint(val), 0f) || DoorPath.Covers(((Component)tree).transform, val) || (flag && NearBuilding(val, 1.5f, tree)) || Planting.InsideSolid(val))
			{
				whole = false;
				continue;
			}
			Heightmap val2 = Heightmap.FindHeightmap(item);
			if (!Object.op_Implicit((Object)(object)val2) || Utils.DistanceXZ(item, position) > tree.Radius)
			{
				whole = false;
			}
			else if (!val2.IsCultivated(item))
			{
				list.Add(val);
			}
		}
		return list;
	}

	private static bool Protected(Vector3 ground, long creator)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		if (!(ground.y < ZoneSystem.instance.m_waterLevel) && !Location.IsInsideNoBuildLocation(ground))
		{
			return !Planting.CreatorHasWardAccess(creator, ground);
		}
		return true;
	}

	private static bool NearBuilding(Vector3 point, float distance, SprotiTree tree)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		Collider[] array = Physics.OverlapSphere(point, distance, SpaceMask, (QueryTriggerInteraction)1);
		for (int i = 0; i < array.Length; i++)
		{
			if (IsPlayerBuilding(array[i], tree))
			{
				return true;
			}
		}
		return false;
	}

	private static bool IsPlayerBuilding(Collider collider, SprotiTree tree)
	{
		Piece componentInParent = ((Component)collider).GetComponentInParent<Piece>();
		if (!Object.op_Implicit((Object)(object)componentInParent) || (Object)(object)((Component)componentInParent).gameObject == (Object)(object)((Component)tree).gameObject || Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<Plant>()) || Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<TreeChest>()))
		{
			return false;
		}
		bool flag;
		switch (componentInParent.m_name)
		{
		case "$piece_woodfence":
		case "$piece_stonefence":
		case "$piece_woodfencegate":
		case "$piece_stakewall":
		case "$piece_dvergr_stake_wall":
		case "$piece_BlackwoodStakewall":
			flag = true;
			break;
		default:
			flag = false;
			break;
		}
		if (flag)
		{
			return false;
		}
		return componentInParent.IsPlacedByPlayer();
	}
}
internal static class DoorPath
{
	[HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")]
	private static class RegisterOp
	{
		private static void Prefix(ObjectDB __instance)
		{
			TerrainOp[] array = (TerrainOp[])(((object)s_ops) ?? ((object)new TerrainOp[0]));
			foreach (TerrainOp item in array)
			{
				if (!__instance.m_terrainOps.Contains(item))
				{
					__instance.m_terrainOps.Add(item);
				}
			}
		}
	}

	private const string VanillaOp = "paved_road_v2";

	private const float PaintRadius = 0.5f;

	private const float CentreAhead = 0.8f;

	private const float HalfWidth = 1f;

	private const float HalfLength = 1f;

	private static readonly (float limit, float strength)[] Rings = new(float, float)[3]
	{
		(0.7f, 1f),
		(1f, 0.6f),
		(1.3f, 0.55f)
	};

	private static TerrainOp[] s_ops;

	private static Vector3 Centre => SprotiHouse.DoorOffset + Vector3.forward * 0.8f;

	public static void CreatePrefab()
	{
		s_ops = (TerrainOp[])(object)new TerrainOp[Rings.Length];
		for (int i = 0; i < Rings.Length; i++)
		{
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("Sproti_Pave" + i, "paved_road_v2");
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<TerrainOp>()))
			{
				Sproti.Log.LogWarning((object)"terrain op paved_road_v2 not found, no path in front of Sproti's door");
				s_ops = null;
				break;
			}
			foreach (Transform item in ((IEnumerable)val.transform).Cast<Transform>().ToList())
			{
				Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
			}
			Object.DestroyImmediate((Object)(object)val.GetComponent<Piece>());
			TerrainOp component = val.GetComponent<TerrainOp>();
			Settings settings = component.m_settings;
			settings.m_smooth = false;
			settings.m_level = false;
			settings.m_raise = false;
			settings.m_halfOffset = false;
			settings.m_paintRadius = 0.5f;
			settings.m_paintStrength = Rings[i].strength;
			s_ops[i] = component;
		}
	}

	private static float EllipseDistance(Transform tree, Vector3 world)
	{
		//IL_0001: 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_000b: 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_0013: 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_0025: 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_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: 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_0043: 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_0054: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = tree.TransformPoint(Centre);
		Vector3 val2 = tree.InverseTransformDirection(new Vector3(world.x - val.x, 0f, world.z - val.z));
		Vector2 val3 = new Vector2(val2.x / 1f, val2.z / 1f);
		return ((Vector2)(ref val3)).magnitude;
	}

	public static bool Covers(Transform tree, Vector3 vertex)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		return EllipseDistance(tree, vertex) <= Rings[Rings.Length - 1].limit;
	}

	public static void Pave(Transform tree)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: 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_00ed: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		if (s_ops == null)
		{
			return;
		}
		Vector3 val = tree.TransformPoint(Centre);
		float num = Mathf.Max(1f, 1f) * Rings[Rings.Length - 1].limit;
		Vector3 val2 = default(Vector3);
		for (int i = Mathf.FloorToInt(val.x - num); i <= Mathf.CeilToInt(val.x + num); i++)
		{
			for (int j = Mathf.FloorToInt(val.z - num); j <= Mathf.CeilToInt(val.z + num); j++)
			{
				((Vector3)(ref val2))..ctor((float)i, 0f, (float)j);
				float distance = EllipseDistance(tree, val2);
				int num2 = Array.FindIndex(Rings, ((float limit, float strength) r) => distance <= r.limit);
				if (num2 >= 0)
				{
					val2.y = ZoneSystem.instance.GetGroundHeight(val2);
					Object.Instantiate<GameObject>(((Component)s_ops[num2]).gameObject, val2, Quaternion.identity);
				}
			}
		}
	}
}
internal class FreedSproti : MonoBehaviour, Hoverable, Interactable
{
	private enum Scene
	{
		Freed,
		MoveIn
	}

	private class SceneData
	{
		public string[] Lines;

		public SprotiFace.Expression[] Faces;

		public int TeachLine;

		public int OriginFrom = -1;

		public int OriginTo = -1;

		public bool PopOut;
	}

	[HarmonyPatch(typeof(Destructible), "Destroy")]
	private static class NestDestroyed
	{
		private static void Prefix(Destructible __instance, HitData hit)
		{
			//IL_0030: 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)
			//IL_0036: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null)
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (val != null && !(Utils.GetPrefabName(((Component)__instance).gameObject) != "Spawner_GreydwarfNest"))
			{
				Vector3 position = ((Component)__instance).transform.position;
				if (RecipeUnlock.AnyoneUnaware(position, 50f) && Random.value < 0.25f)
				{
					Sproti.Log.LogInfo((object)$"sproti freed from nest at {position}");
					Spawn(TryFreeSpot(position, ((Component)val).transform.position, out var spot) ? spot : position, ((Component)val).transform.position, position, terrainOnly: true);
				}
			}
		}
	}

	public const string PrefabName = "Sproti_Freed";

	private const string NestPrefab = "Spawner_GreydwarfNest";

	private const string StartKey = "sproti_freed_start";

	private const string LineKey = "sproti_freed_line";

	private const string LineStartKey = "sproti_freed_line_start";

	private const string OriginKey = "sproti_freed_origin";

	private const string SceneKey = "sproti_scene";

	private const string BuilderKey = "sproti_scene_builder";

	private const string AbortedKey = "sproti_scene_aborted";

	private const string AtTreeKey = "sproti_scene_at_tree";

	private const float OrphanCheckDelay = 2f;

	private const string NextRpc = "Sproti_FreedNext";

	private const float Chance = 0.25f;

	public const float Range = 50f;

	private const float AppearDelay = 2f;

	private const float NestDistance = 6f;

	private const float NestMaxAngle = 30f;

	private const int SpotTries = 12;

	private const float SpotRadius = 0.35f;

	private const float SpotClearance = 0.15f;

	private const int SpotSearchHeight = 30;

	private const string AppearSound = "sfx_lootspawn";

	private const float RemoveDelay = 1f;

	private const float LineTimeout = 10f;

	private const float SilentTime = 1.5f;

	private const float TeachWindow = 5f;

	private const float TextCullDistance = 30f;

	private const float TurnSpeed = 90f;

	private const float OriginTurnSpeed = 360f;

	private const int GroundSearch = 3;

	private static readonly SceneData Freed = new SceneData
	{
		Lines = new string[4] { "$sproti_freed_1", "$sproti_freed_2", "$sproti_freed_3", "$sproti_freed_4" },
		Faces = new SprotiFace.Expression[4]
		{
			SprotiFace.Expression.Idling,
			SprotiFace.Expression.Working,
			SprotiFace.Expression.Judging,
			SprotiFace.Expression.Working
		},
		TeachLine = 4
	};

	private static readonly SceneData MoveIn = new SceneData
	{
		Lines = new string[7] { "$sproti_movein_1", null, "$sproti_movein_2", "$sproti_movein_3", "$sproti_movein_4", "$sproti_movein_5", "$sproti_movein_6" },
		Faces = new SprotiFace.Expression[7]
		{
			SprotiFace.Expression.Idling,
			SprotiFace.Expression.Idling,
			SprotiFace.Expression.Judging,
			SprotiFace.Expression.Working,
			SprotiFace.Expression.Working,
			SprotiFace.Expression.Idling,
			SprotiFace.Expression.Judging
		},
		TeachLine = 5,
		OriginFrom = 1,
		OriginTo = 2,
		PopOut = true
	};

	private static readonly List<FreedSproti> s_moveIns = new List<FreedSproti>();

	private ZNetView m_nview;

	private SceneData m_scene;

	private Vector3 m_origin;

	private Transform m_visual;

	private Collider m_collider;

	private SprotiFade m_fade;

	private SprotiFace m_face;

	private SprotiPuppet m_puppet;

	private bool m_appeared;

	private int m_shownLine = -1;

	private static int SpotMask => LayerMask.GetMask(new string[4] { "Default", "static_solid", "Default_small", "piece" });

	private string[] Lines => m_scene.Lines;

	private static long Now => ZNet.instance.GetTime().Ticks;

	public static void CreatePrefab(GameObject creature)
	{
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Expected O, but got Unknown
		GameObject val = PrefabManager.Instance.CreateEmptyPrefab("Sproti_Freed", true);
		Object.DestroyImmediate((Object)(object)val.GetComponent<Collider>());
		Object.DestroyImmediate((Object)(object)val.GetComponent<MeshRenderer>());
		Object.DestroyImmediate((Object)(object)val.GetComponent<MeshFilter>());
		((Object)Object.Instantiate<Transform>(creature.transform.Find("Visual"), val.transform, false)).name = "Visual";
		val.layer = LayerMask.NameToLayer("piece_nonsolid");
		CapsuleCollider obj = val.AddComponent<CapsuleCollider>();
		obj.radius = 0.35f;
		obj.height = 1.11216f;
		obj.center = new Vector3(0f, 0.55608f, 0f);
		val.AddComponent<FreedSproti>();
		PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false));
	}

	public static void Spawn(Vector3 position, Vector3 lookAt, Vector3 origin, bool terrainOnly, bool moveIn = false)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: 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)
		float y = default(float);
		if (terrainOnly)
		{
			position.y = ZoneSystem.instance.GetGroundHeight(position);
		}
		else if (ZoneSystem.instance.GetSolidHeight(position, ref y, 3))
		{
			position.y = y;
		}
		ZDO val = Create(position, lookAt, origin);
		if (moveIn && Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			val.Set("sproti_scene", 1);
			val.Set("sproti_scene_builder", Player.m_localPlayer.GetPlayerID());
		}
	}

	public static void SpawnMoveIn(SprotiTree tree)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer) || RecipeUnlock.HasSeenMoveIn(localPlayer))
		{
			return;
		}
		foreach (FreedSproti s_moveIn in s_moveIns)
		{
			if (s_moveIn.m_nview.IsValid() && s_moveIn.m_nview.GetZDO().GetLong("sproti_scene_builder", 0L) == localPlayer.GetPlayerID())
			{
				return;
			}
		}
		ZDO obj = Create(tree.HomePosition, ((Component)localPlayer).transform.position, ((Component)tree).transform.position);
		obj.Set("sproti_scene", 1);
		obj.Set("sproti_scene_builder", localPlayer.GetPlayerID());
		obj.Set("sproti_scene_at_tree", true);
	}

	private static ZDO Create(Vector3 position, Vector3 lookAt, Vector3 origin)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: 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_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: 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_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = lookAt - position;
		val.y = 0f;
		Quaternion val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? Quaternion.LookRotation(val) : Quaternion.identity);
		ZDO zDO = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("Sproti_Freed"), position, val2).GetComponent<ZNetView>().GetZDO();
		zDO.Set("sproti_freed_origin", origin);
		return zDO;
	}

	public static bool MoveInAt(SprotiTree tree)
	{
		//IL_001e: 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)
		foreach (FreedSproti s_moveIn in s_moveIns)
		{
			if (Object.op_Implicit((Object)(object)tree) && Utils.DistanceXZ(s_moveIn.m_origin, ((Component)tree).transform.position) < 0.1f)
			{
				return true;
			}
		}
		return false;
	}

	private static float Seconds(long ticks)
	{
		return (float)ticks / 10000000f;
	}

	private static long Ticks(float seconds)
	{
		return (long)(seconds * 10000000f);
	}

	private void Awake()
	{
		m_nview = ((Component)this).GetComponent<ZNetView>();
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid())
		{
			ZDO zDO = m_nview.GetZDO();
			if (m_nview.IsOwner() && zDO.GetLong("sproti_freed_start", 0L) == 0L)
			{
				long num = Now + Ticks(2f);
				zDO.Set("sproti_freed_start", num);
				zDO.Set("sproti_freed_line", 0);
				zDO.Set("sproti_freed_line_start", num);
			}
			m_nview.Register<int>("Sproti_FreedNext", (Action<long, int>)RPC_Next);
			OwnerRemoval.Register(m_nview, Abort);
			m_visual = ((Component)this).transform.Find("Visual");
			m_collider = ((Component)this).GetComponent<Collider>();
			m_fade = new SprotiFade(((Component)this).transform.Find("Visual/Rig"));
			m_fade.Snap(visible: false);
			m_face = new SprotiFace(((Component)this).transform.Find("Visual/Rig"));
			m_puppet = ((Component)((Component)this).transform.Find("Visual/Rig")).GetComponent<SprotiPuppet>();
		}
	}

	private void Start()
	{
		//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)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid())
		{
			return;
		}
		ZDO zDO = m_nview.GetZDO();
		bool flag = zDO.GetInt("sproti_scene", 0) == 1;
		m_scene = (flag ? MoveIn : Freed);
		m_origin = zDO.GetVec3("sproti_freed_origin", ((Component)this).transform.position);
		m_face.Set(m_scene.Faces[0]);
		if (flag)
		{
			s_moveIns.Add(this);
			if (zDO.GetBool("sproti_scene_at_tree", false))
			{
				((MonoBehaviour)this).Invoke("CheckOrphaned", 2f);
			}
		}
	}

	private void OnDestroy()
	{
		s_moveIns.Remove(this);
		m_fade?.Destroy();
		if (Object.op_Implicit((Object)(object)Chat.instance))
		{
			Chat.instance.ClearNpcText(((Component)this).gameObject);
		}
	}

	private void Update()
	{
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid() || m_scene == null)
		{
			return;
		}
		ZDO zDO = m_nview.GetZDO();
		long num = zDO.GetLong("sproti_freed_start", 0L);
		if (num == 0L)
		{
			return;
		}
		float num2 = Seconds(Now - num);
		int num3 = zDO.GetInt("sproti_freed_line", 0);
		float num4 = Seconds(Now - zDO.GetLong("sproti_freed_line_start", 0L));
		bool flag = num3 < Lines.Length;
		if (num2 >= 0f && !m_appeared)
		{
			m_appeared = true;
			if (m_nview.IsOwner() && num2 < 1f)
			{
				NetSound.Play("sfx_lootspawn", ((Component)this).transform.position);
			}
		}
		bool flag2 = num2 >= 0f && flag;
		if (flag2 != m_fade.Alpha > 0f)
		{
			m_fade.Snap(flag2);
		}
		m_collider.enabled = flag2;
		bool toOrigin = num3 >= m_scene.OriginFrom && num3 <= m_scene.OriginTo;
		Turn(toOrigin, m_scene.OriginFrom >= 0 && num3 >= m_scene.OriginFrom && num3 <= m_scene.OriginTo + 1);
		if (num4 >= 0f && num3 != m_shownLine)
		{
			if (flag)
			{
				if (Lines[num3] != null)
				{
					Say(Lines[num3]);
				}
				else if (Object.op_Implicit((Object)(object)Chat.instance))
				{
					Chat.instance.ClearNpcText(((Component)this).gameObject);
				}
				m_face.Set(m_scene.Faces[num3]);
			}
			else
			{
				if (Object.op_Implicit((Object)(object)Chat.instance))
				{
					Chat.instance.ClearNpcText(((Component)this).gameObject);
				}
				if (num4 < 1f && num2 >= 0f && m_scene.PopOut)
				{
					NetSound.Play("sfx_pickable_pick", ((Component)this).transform.position, local: true, 1f, 2f);
				}
				else if (num4 < 1f && num2 >= 0f && m_nview.IsOwner())
				{
					NetSound.Play("sfx_lootspawn", ((Component)this).transform.position);
				}
			}
			bool flag3 = zDO.GetBool("sproti_scene_aborted", false);
			if (num3 >= m_scene.TeachLine && num4 < 5f && !flag3)
			{
				Teach();
			}
			Player localPlayer = Player.m_localPlayer;
			if (!flag && m_scene == MoveIn && num4 < 5f && !flag3 && Object.op_Implicit((Object)(object)localPlayer) && localPlayer.GetPlayerID() == zDO.GetLong("sproti_scene_builder", 0L) && RecipeUnlock.IsNurseryKnown(localPlayer))
			{
				RecipeUnlock.MarkMoveInSeen(localPlayer);
			}
			m_shownLine = num3;
		}
		if (m_nview.IsOwner())
		{
			if (flag && num4 >= ((Lines[num3] != null) ? 10f : 1.5f))
			{
				Advance(num3);
			}
			else if (!flag && num4 >= 1f)
			{
				m_nview.Destroy();
			}
		}
	}

	private void Turn(bool toOrigin, bool fast)
	{
		//IL_003f: 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_004a: 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_0054: 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_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)m_visual))
		{
			m_puppet.LookTarget = (Character)(object)(toOrigin ? null : localPlayer);
			Vector3 val = (toOrigin ? m_origin : ((Component)localPlayer).transform.position) - m_visual.position;
			val.y = 0f;
			if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
			{
				m_visual.rotation = Quaternion.RotateTowards(m_visual.rotation, Quaternion.LookRotation(val), (fast ? 360f : 90f) * Time.deltaTime);
			}
		}
	}

	public static void TreeRemoved(SprotiTree tree)
	{
		//IL_0016: 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)
		foreach (FreedSproti s_moveIn in s_moveIns)
		{
			if (Utils.DistanceXZ(s_moveIn.m_origin, ((Component)tree).transform.position) < 0.1f)
			{
				OwnerRemoval.Request(s_moveIn.m_nview);
			}
		}
	}

	private void CheckOrphaned()
	{
		//IL_0028: 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)
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid() && m_nview.IsOwner() && SprotiTree.IsLoaded(m_origin) && !Object.op_Implicit((Object)(object)SprotiTree.FindAt(m_origin)))
		{
			Abort();
		}
	}

	private void Abort()
	{
		ZDO zDO = m_nview.GetZDO();
		if (zDO.GetInt("sproti_freed_line", 0) < Lines.Length)
		{
			zDO.Set("sproti_scene_aborted", true);
			zDO.Set("sproti_freed_line", Lines.Length);
			zDO.Set("sproti_freed_line_start", Now);
		}
	}

	private void Advance(int line)
	{
		ZDO zDO = m_nview.GetZDO();
		if (zDO.GetInt("sproti_freed_line", 0) == line && line < Lines.Length && !(Seconds(Now - zDO.GetLong("sproti_freed_line_start", 0L)) < 0f))
		{
			zDO.Set("sproti_freed_line", line + 1);
			zDO.Set("sproti_freed_line_start", Now);
		}
	}

	private void RPC_Next(long sender, int line)
	{
		if (m_nview.IsOwner())
		{
			Advance(line);
		}
	}

	public bool Interact(Humanoid user, bool hold, bool alt)
	{
		if (hold || !m_nview.IsValid() || m_shownLine < 0 || m_shownLine >= Lines.Length)
		{
			return false;
		}
		m_nview.InvokeRPC("Sproti_FreedNext", new object[1] { m_shownLine });
		return true;
	}

	public bool UseItem(Humanoid user, ItemData item)
	{
		return false;
	}

	public string GetHoverText()
	{
		if (m_shownLine < 0 || m_shownLine >= Lines.Length)
		{
			return "";
		}
		return Localization.instance.Localize("$sproti_creature\n[<color=yellow><b>$KEY_Use</b></color>] $sproti_freed_next");
	}

	public string GetHoverName()
	{
		return Localization.instance.Localize("$sproti_creature");
	}

	public float GetHoverOffset()
	{
		return 0f;
	}

	private void Say(string text)
	{
		//IL_0017: 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)
		if (Object.op_Implicit((Object)(object)Chat.instance))
		{
			Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 1.51216f, 30f, 10f, "$sproti_creature", text, false);
		}
	}

	private void Teach()
	{
		//IL_0014: 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)
		Player localPlayer = Player.m_localPlayer;
		if (Object.op_Implicit((Object)(object)localPlayer) && !(Vector3.Distance(((Component)localPlayer).transform.position, m_origin) > 50f))
		{
			if (m_scene == Freed && !RecipeUnlock.IsKnown(localPlayer))
			{
				RecipeUnlock.Learn(localPlayer);
			}
			else if (m_scene == MoveIn && !RecipeUnlock.IsNurseryKnown(localPlayer))
			{
				RecipeUnlock.LearnNursery(localPlayer);
			}
		}
	}

	private static bool TryFreeSpot(Vector3 nest, Vector3 attacker, out Vector3 spot)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: 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_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: 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_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: 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_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: 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)
		Vector3 val = nest - attacker;
		val.y = 0f;
		val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
		spot = nest;
		float num2 = default(float);
		for (int i = 0; i < 12; i++)
		{
			spot = nest + Quaternion.Euler(0f, Random.Range(-30f, 30f), 0f) * val * 6f;
			spot.y = ZoneSystem.instance.GetGroundHeight(spot);
			Vector3 val2 = spot + Vector3.up * 0.5f;
			Vector3 val3 = spot + Vector3.up * 0.76215994f;
			bool num = ZoneSystem.instance.GetSolidHeight(spot, ref num2, 30) && num2 > spot.y + 0.15f;
			bool flag = spot.y < ZoneSystem.instance.m_waterLevel;
			if (!num && !flag && !Physics.CheckCapsule(val2, val3, 0.35f, SpotMask))
			{
				return true;
			}
		}
		return false;
	}
}
internal static class Harvesting
{
	[HarmonyPatch(typeof(Pickable), "RPC_Pick")]
	private static class ServerPickEffects
	{
		private static ZDOID EffectSource()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return ZDOID.None;
			}
			return ((Character)localPlayer).GetZDOID();
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: 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_0034: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			return new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[2]
			{
				new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Player), "m_localPlayer"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Character), "GetZDOID", (Type[])null, (Type[])null), (string)null)
			}).ThrowIfInvalid("Pickable.RPC_Pick local player effect source not found").Set(OpCodes.Call, (object)AccessTools.Method(typeof(ServerPickEffects), "EffectSource", (Type[])null, (Type[])null))
				.Advance(1)
				.Set(OpCodes.Nop, (object)null)
				.InstructionEnumeration();
		}
	}

	[HarmonyPatch(typeof(Pickable), "Awake")]
	private static class RegisterPickable
	{
		private static void Postfix(Pickable __instance)
		{
			s_pickables.Add(__instance);
		}
	}

	private static readonly HashSet<Pickable> s_pickables = new HashSet<Pickable>();

	internal static List<GameObject> CultivatorPieces()
	{
		return ObjectDB.instance.GetItemPrefab("Cultivator").GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces.m_pieces;
	}

	private static HashSet<string> CropPickableNames()
	{
		HashSet<string> hashSet = new HashSet<string>();
		foreach (GameObject item in CultivatorPieces())
		{
			Plant component = item.GetComponent<Plant>();
			if (!Object.op_Implicit((Object)(object)component) || !component.m_needCultivatedGround)
			{
				continue;
			}
			GameObject[] grownPrefabs = component.m_grownPrefabs;
			foreach (GameObject val in grownPrefabs)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent<Pickable>()))
				{
					hashSet.Add(((Object)val).name);
				}
			}
		}
		return hashSet;
	}

	public static IEnumerator Candidates(SprotiTree tree, Inventory output, Func<Vector3, bool> blocked, List<Pickable> result)
	{
		HashSet<string> crops = CropPickableNames();
		s_pickables.RemoveWhere((Pickable val) => !Object.op_Implicit((Object)(object)val));
		List<Pickable> list = s_pickables.ToList();
		foreach (Pickable p in list)
		{
			if (SearchBudget.Exhausted)
			{
				yield return null;
				if (!Object.op_Implicit((Object)(object)tree))
				{
					yield break;
				}
			}
			if (Object.op_Implicit((Object)(object)p) && ((Component)p).gameObject.activeInHierarchy && Utils.DistanceXZ(((Component)p).transform.position, ((Component)tree).transform.position) <= tree.Radius && Object.op_Implicit((Object)(object)p.m_nview) && p.m_nview.IsValid() && Object.op_Implicit((Object)(object)p.m_itemPrefab) && IsPlant(p, crops) && p.CanBePicked() && !blocked(((Component)p).transform.position) && Fits(output, MaxYield(p)))
			{
				result.Add(p);
			}
		}
	}

	private static bool IsPlant(Pickable pickable, HashSet<string> crops)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Invalid comparison between Unknown and I4
		if ((int)pickable.m_pickRaiseSkill != 106)
		{
			return crops.Contains(Utils.GetPrefabName(((Component)pickable).gameObject));
		}
		return true;
	}

	public static GameObject ChooseSort(List<Pickable> candidates, Inventory output, Vector3 from)
	{
		//IL_000e: 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)
		Pickable val = (from p in candidates
			orderby (output.FindFreeStackSpace(ItemName(p.m_itemPrefab), (float)Game.m_worldLevel) <= 0) ? 1 : 0, Vector3.Distance(((Component)p).transform.position, @from)
			select p).FirstOrDefault();
		if (!Object.op_Implicit((Object)(object)val))
		{
			return null;
		}
		return val.m_itemPrefab;
	}

	public static Pickable TakeNearest(List<Pickable> candidates, SprotiTree tree, Inventory output, Vector3 from, Func<Vector3, bool> blocked)
	{
		//IL_0040: 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)
		//IL_0046: 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)
		candidates.RemoveAll((Pickable p) => !Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)p.m_nview) || !p.m_nview.IsValid() || !p.CanBePicked() || Utils.DistanceXZ(((Component)p).transform.position, ((Component)tree).transform.position) > tree.Radius || blocked(((Component)p).transform.position));
		int num = -1;
		float num2 = float.MaxValue;
		for (int num3 = 0; num3 < candidates.Count; num3++)
		{
			Vector3 val = ((Component)candidates[num3]).transform.position - from;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude < num2 && YieldFits(candidates[num3], output))
			{
				num = num3;
				num2 = sqrMagnitude;
			}
		}
		if (num < 0)
		{
			return null;
		}
		Pickable result = candidates[num];
		candidates.RemoveAt(num);
		return result;
	}

	public static string SortName(GameObject sort)
	{
		return Localization.instance.Localize(ItemName(sort));
	}

	private static string ItemName(GameObject item)
	{
		return item.GetComponent<ItemDrop>().m_itemData.m_shared.m_name;
	}

	private static Dictionary<GameObject, int> MaxYield(Pickable pickable)
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<GameObject, int> dictionary = new Dictionary<GameObject, int>();
		int value = (pickable.m_dontScale ? pickable.m_amount : Mathf.Max(pickable.m_minAmountScaled, Game.instance.ScaleDrops(pickable.m_itemPrefab, pickable.m_amount)));
		dictionary[pickable.m_itemPrefab] = value;
		DropTable extraDrops = pickable.m_extraDrops;
		if (!extraDrops.IsEmpty())
		{
			float num = Mathf.Max(1f, Game.m_resourceRate);
			int num2 = extraDrops.m_dropMax * Mathf.CeilToInt(num);
			foreach (DropData drop in extraDrops.m_drops)
			{
				int num3 = (drop.m_dontScale ? drop.m_stackMax : Mathf.CeilToInt((float)drop.m_stackMax * num));
				dictionary.TryGetValue(drop.m_item, out var value2);
				dictionary[drop.m_item] = value2 + num3 * num2;
			}
		}
		return dictionary;
	}

	public static bool YieldFits(Pickable pickable, Inventory output)
	{
		return Fits(output, MaxYield(pickable));
	}

	private static bool Fits(Inventory inventory, Dictionary<GameObject, int> maxYield)
	{
		int num = 0;
		foreach (KeyValuePair<GameObject, int> item in maxYield)
		{
			ItemData itemData = item.Key.GetComponent<ItemDrop>().m_itemData;
			int num2 = Mathf.Max(0, item.Value - inventory.FindFreeStackSpace(itemData.m_shared.m_name, (float)Game.m_worldLevel));
			int num3 = Mathf.Max(1, itemData.m_shared.m_maxStackSize);
			num += (num2 + num3 - 1) / num3;
		}
		return num <= inventory.GetEmptySlots();
	}

	public static bool Harvest(Pickable pickable, Container output)
	{
		Inventory inventory = output.GetInventory();
		if (pickable.m_picked || !pickable.CanBePicked() || !Fits(inventory, MaxYield(pickable)))
		{
			return false;
		}
		HashSet<ItemDrop> before = new HashSet<ItemDrop>(ItemDrop.s_instances);
		pickable.m_nview.InvokeRPC("RPC_Pick", new object[1] { 0 });
		foreach (ItemDrop item in ItemDrop.s_instances.Where((ItemDrop d) => Object.op_Implicit((Object)(object)d) && !before.Contains(d)).ToList())
		{
			if (item.m_nview.IsOwner() && inventory.CanAddItem(item.m_itemData, item.m_itemData.m_stack) && inventory.AddItem(item.m_itemData))
			{
				ZNetScene.instance.Destroy(((Component)item).gameObject);
			}
			else
			{
				Sproti.Log.LogDebug((object)$"harvest overflow {item.m_itemData.m_shared.m_name} x{item.m_itemData.m_stack} stays on the ground");
			}
		}
		return true;
	}
}
internal static class NetSound
{
	public const string Pop = "sfx_pickable_pick";

	public const float PopPitch = 2f;

	private static readonly HashSet<string> s_missing = new HashSet<string>();

	public static void Play(string prefab, Vector3 position, bool local = false, float volume = 1f, float pitch = 1f)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefab) : null);
		if (!Object.op_Implicit((Object)(object)val) && local)
		{
			val = Cache.GetPrefab<GameObject>(prefab);
		}
		if (!Object.op_Implicit((Object)(object)val))
		{
			if (s_missing.Add(prefab))
			{
				Sproti.Log.LogWarning((object)("sound " + prefab + " not found"));
			}
			return;
		}
		ZNetView.m_forceDisableInit = local;
		try
		{
			GameObject val2 = Object.Instantiate<GameObject>(val, position, Quaternion.identity);
			CamShaker[] componentsInChildren = val2.GetComponentsInChildren<CamShaker>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			ZSFX component = val2.GetComponent<ZSFX>();
			if (component != null)
			{
				component.SetVolumeModifier(volume);
				component.SetPitchModifier(pitch);
			}
		}
		finally
		{
			ZNetView.m_forceDisableInit = false;
		}
	}
}
internal static class NurseryLimit
{
	internal struct Info
	{
		public bool HasTree;

		public bool HasNursery;

		public bool Active;
	}

	[HarmonyPatch(typeof(Game), "Start")]
	private static class Register
	{
		private static void Postfix()
		{
			ZRoutedRpc.instance.Register<long>("Sproti_NurseryInfo", (Action<long, long>)RPC_Info);
			ZRoutedRpc.instance.Register<long, int>("Sproti_NurseryInfoAnswer", (Action<long, long, int>)RPC_InfoAnswer);
			s_info.Clear();
			s_asked.Clear();
			s_pending.Clear();
			s_placedTime = float.MinValue;
			s_selected = false;
		}
	}

	[HarmonyPatch(typeof(Player), "SetupPlacementGhost")]
	private static class NurserySelected
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Piece selectedPiece = __instance.GetSelectedPiece();
			int num;
			if (((Character)__instance).InPlaceMode() && Object.op_Implicit((Object)(object)selectedPiece))
			{
				num = (Object.op_Implicit((Object)(object)((Component)selectedPiece).GetComponent<NurseryMarker>()) ? 1 : 0);
				if (num != 0 && !s_selected)
				{
					Ask(__instance.GetPlayerID());
				}
			}
			else
			{
				num = 0;
			}
			s_selected = (byte)num != 0;
		}
	}

	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	private static class Placed
	{
		private static void Postfix(Player __instance, Piece piece, bool __result)
		{
			if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && Object.op_Implicit((Object)(object)piece) && Object.op_Implicit((Object)(object)((Component)piece).GetComponent<NurseryMarker>()))
			{
				s_placedTime = Time.time;
				s_info[__instance.GetPlayerID()] = new Info
				{
					HasTree = true,
					HasNursery = true,
					Active = true
				};
			}
		}
	}

	[HarmonyPatch(typeof(WearNTear), "Remove")]
	private static class Removed
	{
		private static void Prefix(WearNTear __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.IsValid())
			{
				NurseryMarker component = ((Component)__instance).GetComponent<NurseryMarker>();
				if (Object.op_Implicit((Object)(object)component) && component.Creator == localPlayer.GetPlayerID())
				{
					s_placedTime = float.MinValue;
					((MonoBehaviour)localPlayer).StartCoroutine(AskLater(component.Creator));
				}
				SprotiTree component2 = ((Component)__instance).GetComponent<SprotiTree>();
				if (Object.op_Implicit((Object)(object)component2) && ((Component)component2).GetComponent<TreeNursery>().HasArea)
				{
					((Character)localPlayer).Message((MessageType)2, "$msg_sproti_nursery_now_inactive", 0, (Sprite)null, false);
				}
			}
		}
	}

	private const string RequestName = "Sproti_NurseryInfo";

	private const string AnswerName = "Sproti_NurseryInfoAnswer";

	private const float PlacedGrace = 5f;

	private const float RemovedDelay = 2f;

	private const float RefreshTime = 10f;

	private const float RefusedInterval = 2f;

	private const float AnswerTimeout = 5f;

	private const int TreeFlag = 1;

	private const int NurseryFlag = 2;

	private const int ActiveFlag = 4;

	private static readonly Dictionary<long, Info> s_info = new Dictionary<long, Info>();

	private static readonly Dictionary<long, float> s_asked = new Dictionary<long, float>();

	private static readonly HashSet<long> s_pending = new HashSet<long>();

	private static float s_placedTime = float.MinValue;

	private static bool s_selected;

	internal static bool Get(long creator, out Info info)
	{
		if (!s_asked.TryGetValue(creator, out var value) || Time.time - value > 10f)
		{
			Ask(creator);
		}
		return s_info.TryGetValue(creator, out info);
	}

	private static void Ask(long creator, bool force = false)
	{
		if (ZRoutedRpc.instance != null && (force || !s_pending.Contains(creator) || !(Time.time - s_asked[creator] < 5f)))
		{
			s_asked[creator] = Time.time;
			s_pending.Add(creator);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "Sproti_NurseryInfo", new object[1] { creator });
		}
	}

	private static IEnumerator AskLater(long creator)
	{
		yield return (object)new WaitForSeconds(2f);
		Ask(creator, force: true);
	}

	internal static string Problem(Player player)
	{
		long playerID = player.GetPlayerID();
		bool flag = false;
		bool flag2 = false;
		foreach (NurseryMarker item in NurseryMarker.Of(playerID))
		{
			flag = true;
			flag2 |= item.IsActive;
		}
		if (!flag)
		{
			if (!s_info.TryGetValue(playerID, out var value))
			{
				Ask(playerID);
				return "$msg_sproti_nursery_checking";
			}
			flag = value.HasNursery;
			flag2 = value.Active;
		}
		if (flag)
		{
			if (!flag2)
			{
				return "$msg_sproti_nursery_inactive_exists";
			}
			return "$msg_sproti_nursery_exists";
		}
		return null;
	}

	internal static void Refused(Player player)
	{
		long playerID = player.GetPlayerID();
		if (!s_asked.TryGetValue(playerID, out var value) || Time.time - value >= 2f)
		{
			Ask(playerID);
		}
	}

	private static void RPC_Info(long sender, long creator)
	{
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		int stableHashCode = StringExtensionMethods.GetStableHashCode("Sproti_Tree");
		int stableHashCode2 = StringExtensionMethods.GetStableHashCode("Sproti_NurseryMarker");
		List<Vector3> trees = new List<Vector3>();
		List<Vector3> list = new List<Vector3>();
		foreach (ZDO value in ZDOMan.instance.m_objectsByID.Values)
		{
			int prefab = value.GetPrefab();
			if ((prefab == stableHashCode || prefab == stableHashCode2) && value.GetLong(ZDOVars.s_creator, 0L) == creator)
			{
				((prefab == stableHashCode) ? trees : list).Add(value.GetPosition());
			}
		}
		bool flag = list.Exists((Vector3 marker) => trees.Exists((Vector3 tree) => Utils.DistanceXZ(marker, tree) <= 32f));
		int num = (int)(((trees.Count > 0) ? 1u : 0u) | (uint)((list.Count > 0) ? 2 : 0)) | (flag ? 4 : 0);
		ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Sproti_NurseryInfoAnswer", new object[2] { creator, num });
	}

	private static void RPC_InfoAnswer(long sender, long creator, int flags)
	{
		s_pending.Remove(creator);
		Info value = new Info
		{
			HasTree = ((flags & 1) != 0),
			HasNursery = ((flags & 2) != 0),
			Active = ((flags & 4) != 0)
		};
		Player localPlayer = Player.m_localPlayer;
		if (Object.op_Implicit((Object)(object)localPlayer) && creator == localPlayer.GetPlayerID() && !value.HasNursery && Time.time - s_placedTime <= 5f && s_info.TryGetValue(creator, out var value2))
		{
			value.HasNursery = value2.HasNursery;
			value.Active = value2.Active;
		}
		s_info[creator] = value;
	}
}
internal class NurseryMarker : MonoBehaviour, Interactable, Hoverable
{
	private static readonly List<NurseryMarker> Instances = new List<NurseryMarker>();

	private ZNetView m_nview;

	private Piece m_piece;

	private CircleProjector[] m_circles;

	private readonly SprotiMap m_map = new SprotiMap("Sproti.map_icon_nursery.png", moves: false);

	private SprotiTree m_home;

	private int m_homeVersion = -1;

	internal bool Alive
	{
		get
		{
			if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid())
			{
				return m_nview.GetZDO().GetFloat(ZDOVars.s_health, 1000f) > 0f;
			}
			return false;
		}
	}

	internal long Creator => m_piece.GetCreator();

	internal bool IsActive => Object.op_Implicit((Object)(object)Home);

	private SprotiTree Home
	{
		get
		{
			if (!Alive)
			{
				return null;
			}
			return CachedHome();
		}
	}

	internal static IEnumerable<NurseryMarker> All => Instances.Where((NurseryMarker marker) => marker.Alive);

	private SprotiTree CachedHome()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		if (m_homeVersion != SprotiTree.HomesVersion || (Object.op_Implicit((Object)(object)m_home) && !m_home.IsValid))
		{
			m_homeVersion = SprotiTree.HomesVersion;
			m_home = NearestInRange<SprotiTree>(SprotiTree.Instances.Where((SprotiTree tree) => tree.IsValid && Builder(tree) == Creator), ((Component)this).transform.position);
		}
		return m_home;
	}

	private static long Builder(SprotiTree tree)
	{
		return ((Component)tree).GetComponent<Piece>().GetCreator();
	}

	private static T NearestInRange<T>(IEnumerable<T> candidates, Vector3 position) where T : Component
	{
		//IL_0007: 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)
		return (from c in candidates
			select (c: c, distance: Utils.DistanceXZ(((Component)c).transform.position, position)) into c
			where c.distance <= 32f
			orderby c.distance
			select c.c).FirstOrDefault();
	}

	internal static NurseryMarker FindFor(SprotiTree home)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)home) && home.IsValid)
		{
			return NearestInRange<NurseryMarker>(Instances.Where((NurseryMarker marker) => marker.Alive && marker.Creator == Builder(home)), ((Component)home).transform.position);
		}
		return null;
	}

	internal static IEnumerable<NurseryMarker> Of(long creator)
	{
		return Instances.Where((NurseryMarker marker) => marker.Alive && marker.Creator == creator);
	}

	private void Awake()
	{
		m_nview = ((Component)this).GetComponent<ZNetView>();
		m_piece = ((Component)this).GetComponent<Piece>();
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid())
		{
			m_circles = ((Component)this).GetComponentsInChildren<CircleProjector>(true);
			Instances.Add(this);
			SprotiTree.HomesVersion++;
		}
	}

	private void OnDestroy()
	{
		if (Instances.Remove(this))
		{
			SprotiTree.HomesVersion++;
		}
		m_map.Remove();
	}

	private void Update()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (m_circles == null)
		{
			return;
		}
		m_map.Update((Alive && Sproti.MapHomes.Value) ? m_piece : null, ((Component)this).transform.position);
		SprotiTree home = Home;
		bool flag = Object.op_Implicit((Object)(object)home) && home.MarkersVisible;
		CircleProjector[] circles = m_circles;
		foreach (CircleProjector val in circles)
		{
			if (((Component)val).gameObject.activeSelf != flag)
			{
				((Component)val).gameObject.SetActive(flag);
			}
		}
	}

	public bool Interact(Humanoid user, bool hold, bool alt)
	{
		SprotiTree home = Home;
		if (hold || !alt || (Object)(object)user != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)home))
		{
			return false;
		}
		home.ShowAreas();
		return true;
	}

	public bool UseItem(Humanoid user, ItemData item)
	{
		return false;
	}

	public string GetHoverText()
	{
		string text = SprotiTree.WithBuilder(m_piece.m_name, m_nview);
		SprotiTree home = Home;
		if (Object.op_Implicit((Object)(object)home))
		{
			text += TreePerks.HoverLines(home.Perks & 2);
			text += "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $sproti_show_radius";
		}
		else
		{
			NurseryLimit.Info info;
			bool flag = SprotiTree.Instances.Any((SprotiTree tree) => tree.IsValid && Builder(tree) == Creator) || (NurseryLimit.Get(Creator, out info) && info.HasTree);
			text = text + "\n<color=red>$sproti_inactive (" + (flag ? "$sproti_too_far" : "$sproti_no_tree") + ")</color>";
		}
		return Localization.instance.Localize(text);
	}

	public string GetHoverName()
	{
		return Localization.instance.Localize(m_piece.m_name);
	}

	public float GetHoverOffset()
	{
		return 0f;
	}
}
internal static class OwnerRemoval
{
	private const string Rpc = "Sproti_Remove";

	private const int MaxHops = 3;

	public static void Register(ZNetView nview, Action remove)
	{
		nview.Register<int>("Sproti_Remove", (Action<long, int>)delegate(long sender, int hops)
		{
			Handle(nview, remove, hops);
		});
	}

	public static void Request(ZNetView nview)
	{
		if (Object.op_Implicit((Object)(object)nview) && nview.IsValid())
		{
			nview.InvokeRPC("Sproti_Remove", new object[1] { 0 });
		}
	}

	private static void Handle(ZNetView nview, Action remove, int hops)
	{
		if (nview.IsValid())
		{
			if (nview.IsOwner())
			{
				remove();
			}
			else if (nview.GetZDO().GetOwner() != 0L && hops < 3)
			{
				nview.InvokeRPC("Sproti_Remove", new object[1] { hops + 1 });
			}
		}
	}
}
internal static class OwnershipRpc
{
	[HarmonyPatch(typeof(Game), "Start")]
	private static class Register
	{
		private static void Postfix()
		{
			ZRoutedRpc.instance.Register<ZDOID>("Sproti_RequestOwn", (Action<long, ZDOID>)RPC_RequestOwn);
		}
	}

	private const string Name = "Sproti_RequestOwn";

	public static void Request(ZNetView nview)
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		if (nview.IsValid() && !nview.IsOwner())
		{
			ZDO zDO = nview.GetZDO();
			if (!zDO.HasOwner())
			{
				nview.ClaimOwnership();
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "Sproti_RequestOwn", new object[1] { zDO.m_uid });
		}
	}

	private static void RPC_RequestOwn(long sender, ZDOID id)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		ZDO zDO = ZDOMan.instance.GetZDO(id);
		if (zDO != null && zDO.IsOwner())
		{
			GameObject val = ZNetScene.instance.FindInstance(id);
			Container val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Container>() : null);
			if (!Object.op_Implicit((Object)(object)val2) || !val2.IsInUse())
			{
				ZDOMan.instance.ForceSendZDO(sender, id);
				zDO.SetOwner(sender);
			}
		}
	}
}
internal static class Planting
{
	public enum Result
	{
		Planted,
		SpotTaken,
		NoMaterial
	}

	private struct Candidate
	{
		public Vector3 Position;

		public Heightmap Heightmap;

		public bool? GroundUsable;
	}

	public sealed class Plan
	{
		public Piece Piece;

		public List<Vector3> Spots;
	}

	private const float GridStep = 0.5f;

	private const float ColliderReach = 0.5f;

	private const float EdgePadding = 0.5f;

	private const int EdgeSamples = 8;

	private const int BudgetCheckEvery = 16;

	private static int s_roofMask;

	private static int s_spaceMask;

	private static Collider[] s_hits = (Collider[])(object)new Collider[64];

	private const float RoofHeight = 100f;

	private const float SolidClearance = 0.2f;

	private static int s_rockMask;

	private static int RoofMask
	{
		get
		{
			if (s_roofMask == 0)
			{
				return s_roofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" });
			}
			return s_roofMask;
		}
	}

	private static int SpaceMask
	{
		get
		{
			if (s_spaceMask == 0)
			{
				return s_spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			}
			return s_spaceMask;
		}
	}

	private static int RockMask
	{
		get
		{
			if (s_rockMask == 0)
			{
				return s_rockMask = LayerMask.GetMask(new string[2] { "Default", "static_solid" });
			}
			return s_rockMask;
		}
	}

	private static int Overlap(Vector3 pos, float radius)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		int result;
		while ((result = Physics.OverlapSphereNonAlloc(pos, radius, s_hits, SpaceMask)) == s_hits.Length)
		{
			s_hits = (Collider[])(object)new Collider[s_hits.Length * 2];
		}
		return result;
	}

	private static List<Piece> PlantablePieces()
	{
		List<Piece> list = new List<Piece>();
		foreach (GameObject item in Harvesting.CultivatorPieces())
		{
			Piece component = item.GetComponent<Piece>();
			Plant component2 = item.GetComponent<Plant>();
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2) && component2.m_needCultivatedGround && component2.m_attachDistance <= 0f && component2.m_growRadiusVines <= 0f && component.m_resources.Length == 1 && Object.op_Implicit((Object)(object)component.m_resources[0].m_resItem))
			{
				list.Add(component);
			}
		}
		list.AddRange(TreeRegrowth.Saplings);
		return list;
	}

	private static Requirement Material(Piece piece)
	{
		return piece.m_resources[0];
	}

	private static string MaterialName(Piece piece)
	{
		return Material(piece).m_resItem.m_itemData.m_shared.m_name;
	}

	internal static bool IsTreeSeed(string itemName)
	{
		return TreeRegrowth.Saplings.Exists((Piece piece) => MaterialName(piece) == itemName);
	}

	public static string MaterialPrefab(Piece piece)
	{
		return ((Object)Material(piece).m_resItem).name;
	}

	internal static bool IsTreeThought(string thought)
	{
		return TreeRegrowth.Saplings.Exists((Piece piece) => thought == SprotiThought.Plant(MaterialPrefab(piece)));
	}

	private static ItemData MaterialSlot(Inventory inventory, Piece piece)
	{
		ItemData val = ((IEnumerable<ItemData>)SlotOrder(inventory)).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => item.m_shared.m_name == MaterialName(piece)));
		if (val == null || val.m_stack < Material(piece).m_amount)
		{
			return null;
		}
		return val;
	}

	public static bool HasMaterial(Container input, Piece piece)
	{
		return MaterialSlot(input.GetInventory(), piece) != null;
	}

	public static string ThoughtItem(Piece piece)
	{
		if (TreeRegrowth.Saplings.Contains(piece))
		{
			return MaterialPrefab(piece);
		}
		Pickable val = (from prefab in ((Component)piece).GetComponent<Plant>().m_grownPrefabs
			where Object.op_Implicit((Object)(object)prefab)
			select prefab.GetComponent<Pickable>()).FirstOrDefault((Func<Pickable, bool>)((Pickable pickable) => Object.op_Implicit((Object)(object)pickable) && Object.op_Implicit((Object)(object)pickable.m_itemPrefab)));
		if (!Object.op_Implicit((Object)(object)val))
		{
			return MaterialPrefab(piece);
		}
		return ((Object)val.m_itemPrefab).name;
	}

	public static bool WontGrowAt(SprotiTree tree, string itemName)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		Piece val = ((IEnumerable<Piece>)PlantablePieces()).FirstOrDefault((Func<Piece, bool>)((Piece p) => MaterialName(p) == itemName));
		if (TreeRegrowth.Saplings.Contains(val))
		{
			return false;
		}
		Heightmap val2 = Heightmap.FindHeightmap(((Component)tree).transform.position);
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
		{
			return !ClimateFits(((Component)val).GetComponent<Plant>(), val2, ((Component)tree).transform.position);
		}
		return false;
	}

	public static IEnumerator PlanRound(SprotiTree tree, Inventory input, Func<Vector3, bool> blocked, Plan plan)
	{
		List<Piece> pieces = PlantablePieces();
		float maxGrowRadius = ((pieces.Count > 0) ? pieces.Max((Piece p) => ((Component)p).GetComponent<Plant>().m_growRadius) : 0f);
		Heightmap treeHeightmap = Heightmap.FindHeightmap(((Component)tree).transform.position);
		List<ItemData> items = SlotOrder(input);
		List<Candidate> cropCandidates = null;
		List<Candidate> treeCandidates = null;
		TreeNursery nursery = ((Component)tree).GetComponent<TreeNursery>();
		long creator = ((Component)tree).GetComponent<Piece>().GetCreator();
		HashSet<Piece> tried = new HashSet<Piece>();
		Dictionary<Vector2s, bool> zonesReady = new Dictionary<Vector2s, bool>();
		foreach (ItemData item in items)
		{
			Piece piece = ((IEnumerable<Piece>)pieces).FirstOrDefault((Func<Piece, bool>)((Piece p) => MaterialName(p) == item.m_shared.m_name));
			if (!Object.op_Implicit((Object)(object)piece) || !tried.Add(piece))
			{
				continue;
			}
			Plant component = ((Component)piece).GetComponent<Plant>();
			bool flag = TreeRegrowth.Saplings.Contains(piece);
			if (flag ? (!nursery.HasArea) : (!Object.op_Implicit((Object)(object)treeHeightmap) || !ClimateFits(component, treeHeightmap, ((Component)tree).transform.position)))
			{
				continue;
			}
			int num = RunAmount(items, item) / Mathf.Max(1, Material(piece).m_amount);
			if (num <= 0)
			{
				continue;
			}
			List<Candidate> list;
			if (!flag)
			{
				list = cropCandidates;
				if (list == null)
				{
					List<Candidate> list2;
					cropCandidates = (list2 = Grid(tree));
					list = list2;
				}
			}
			else
			{
				list = treeCandidates;
				if (list == null)
				{
					List<Candidate> list2;
					treeCandidates = (list2 = NurseryGrid(tree, nursery));
					list = list2;
				}
			}
			List<Candidate> candidates = list;
			Vector3 areaCenter = (flag ? nursery.Center : ((Component)tree).transform.position);
			float areaRadius = (flag ? 15f : tree.Radius);
			List<Vector3> spots = new List<Vector3>();
			IEnumerator find = FindSpots(tree, piece, maxGrowRadius, num, blocked, creator, candidates, areaCenter, areaRadius, zonesReady, spots);
			while (find.MoveNext())
			{
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)tree))
			{
				yield break;
			}
			if (spots.Count > 0)
			{
				plan.Piece = piece;
				plan.Spots = spots;
				yield break;
			}
		}
	}

	private static List<ItemData> SlotOrder(Inventory inventory)
	{
		return (from item in inventory.GetAllItems()
			where item.m_worldLevel == Game.m_worldLevel
			orderby item.m_gridPos.y, item.m_gridPos.x
			select item).ToList();
	}

	public static bool IsFront(Container input, Piece piece)
	{
		ItemData val = MaterialSlot(input.GetInventory(), piece);
		if (val != null)
		{
			return SlotOrder(input.GetInventory()).FirstOrDefault() == val;
		}
		return false;
	}

	private static int RunAmount(List<ItemData> items, ItemData first)
	{
		int num = 0;
		for (int i = items.IndexOf(first); i < items.Count && items[i].m_shared.m_name == first.m_shared.m_name; i++)
		{
			num += items[i].m_stack;
		}
		return num;
	}

	private static List<Candidate> Grid(SprotiTree tree)
	{
		//IL_000d: 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_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		Vector3 center = ((Component)tree).transform.position;
		float radius = tree.Radius;
		int num = Mathf.FloorToInt(radius / 0.5f);
		List<Candidate> list = new List<Candidate>();
		Vector3 val = default(Vector3);
		for (int i = -num; i <= num; i++)
		{
			for (int j = -num; j <= num; j++)
			{
				((Vector3)(ref val))..ctor((float)i * 0.5f, 0f, (float)j * 0.5f);
				if (((Vector3)(ref val)).sqrMagnitude <= radius * radius)
				{
					list.Add(new Candidate
					{
						Position = center + val
					});
				}
			}
		}
		return list.OrderBy(delegate(Candidate c)
		{
			//IL_0001: 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_000c: 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)
			Vector3 val2 = c.Position - center;
			return ((Vector3)(ref val2)).sqrMagnitude;
		}).ToList();
	}

	private static List<Candidate> NurseryGrid(SprotiTree tree, TreeNursery nursery)
	{
		//IL_001f: 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_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: 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_0055: 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_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		List<Candidate> list = new List<Candidate>();
		int num = Mathf.FloorToInt(30f);
		Vector3 center = nursery.Center;
		for (int i = -num; i <= num; i++)
		{
			for (int j = -num; j <= num; j++)
			{
				Vector3 val = center + new Vector3((float)i * 0.5f, 0f, (float)j * 0.5f);
				if (TreeNursery.Inside(val, center))
				{
					list.Add(new Candidate
					{
						Position = val
					});
				}
			}
		}
		return list.OrderBy(delegate(Candidate c)
		{
			//IL_0001: 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_0016: 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)
			Vector3 val2 = c.Position - ((Component)tree).transform.position;
			return ((Vector3)(ref val2)).sqrMagnitude;
		}).ToList();
	}

	private static IEnumerator FindSpots(SprotiTree tree, Piece piece, float maxGrowRadius, int amount, Func<Vector3, bool> blocked, long creator, List<Candidate> candidates, Vector3 areaCenter, float areaRadius, Dictionary<Vector2s, bool> zonesReady, List<Vector3> spots)
	{
		//IL_003b: 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)
		Plant plant = ((Component)piece).GetComponent<Plant>();
		bool sapling = TreeRegrowth.Saplings.Contains(piece);
		float spacing = (sapling ? TreeSpacing.Distance(plant, plant) : (plant.m_growRadius + 0.5f));
		List<(Vector3 Position, float Spacing)> neighbours = Neighbours(plant, areaCenter, areaRadius + TreeSpacing.SearchRadius(plant, maxGrowRadius));
		int checks = 0;
		float y = default(float);
		for (int i = 0; i < candidates.Count; i++)
		{
			int num = checks + 1;
			checks = num;
			if (num % 16 == 0 && SearchBudget.Exhausted)
			{
				yield return null;
				if (!Object.op_Implicit((Object)(object)tree))
				{
					break;
				}
			}
			Candidate value = candidates[i];
			Vector3 pos = value.Position;
			Vector3 local = ((Component)tree).transform.InverseTransformPoint(pos);
			if (SprotiHouse.OnPath(local, plant.m_growRadius) || SprotiHouse.NearChest(local, plant.m_growRadius) || spots.Any((Vector3 s) => Utils.DistanceXZ(s, pos) < spacing) || neighbours.Exists(((Vector3 Position, float Spacing) n) => Utils.DistanceXZ(n.Position, pos) < n.Spacing))
			{
				continue;
			}
			if (!value.GroundUsable.HasValue)
			{
				Heightmap val = Heightmap.FindHeightmap(pos);
				value.GroundUsable = false;
				if (Object.op_Implicit((Object)(object)val) && (!plant.m_needCultivatedGround || val.IsCultivated(pos)) && !blocked(pos) && IsLoaded(pos, zonesReady) && ZoneSystem.instance.GetGroundHeight(pos, ref y))
				{
					pos.y = y;
					value.Position = pos;
					value.Heightmap = val;
					value.GroundUsable = CanPlantOnGround(val, pos, creator, plant.m_needCultivatedGround);
				}
				candidates[i] = value;
			}
			if (value.GroundUsable != true || !Object.op_Implicit((Object)(object)value.Heightmap) || !CanGrowAt(piece, plant, value.Heightmap, pos, maxGrowRadius))
			{
				continue;
			}
			spots.Add(pos);
			if (spots.Count >= amount)
			{
				break;
			}
			if (sapling)
			{
				Candidate[] array = candidates.GetRange(i + 1, candidates.Count - i - 1).ToArray();
				float[] array2 = new float[array.Length];
				for (int num2 = 0; num2 < array.Length; num2++)
				{
					array2[num2] = Utils.DistanceXZ(array[num2].Position, pos);
				}
				Array.Sort(array2, array);
				candidates = new List<Candidate>(array);
				i = -1;
			}
		}
	}

	private static bool IsLoaded(Vector3 pos, Dictionary<Vector2s, bool> zonesReady)
	{
		//IL_0005: 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_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_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (ZNetScene.instance.OutsideActiveArea(pos))
		{
			return false;
		}
		Vector2s zone = ZoneSystem.GetZone(pos);
		if (!zonesReady.TryGetValue(zone, out var value))
		{
			value = (zonesReady[zone] = ZNetScene.instance.IsAreaReady(pos));
		}
		return value;
	}

	private static List<(Vector3 Position, float Spacing)> Neighbours(Plant plant, Vector3 center, float radius)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		HashSet<Plant> hashSet = new HashSet<Plant>();
		int num = Overlap(center, radius);
		for (int i = 0; i < num; i++)
		{
			Plant component = ((Component)s_hits[i]).GetComponent<Plant>();
			if (Object.op_Implicit((Object)(object)component))
			{
				hashSet.Add(component);
			}
		}
		return hashSet.Select((Plant other) => (position: ((Component)other).transform.position, TreeSpacing.Distance(plant, other))).ToList();
	}

	public static Result PlantAt(SprotiTree tree, Container input, Piece piece, Vector3 spot)
	{
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: 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_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		Inventory inventory = input.GetInventory();
		Requirement val = Material(piece);
		ItemData val2 = MaterialSlot(inventory, piece);
		if (val2 == null)
		{
			return Result.NoMaterial;
		}
		float maxGrowRadius = PlantablePieces().Max((Piece p) => ((Component)p).GetComponent<Plant>().m_growRadius);
		Piece component = ((Component)tree).GetComponent<Piece>();
		TreeNursery component2 = ((Component)tree).GetComponent<TreeNursery>();
		if (!(TreeRegrowth.Saplings.Contains(piece) ? component2.Contains(spot) : (Utils.DistanceXZ(spot, ((Component)tree).transform.position) <= tree.Radius)) || !CanPlantAt(piece, ((Component)piece).GetComponent<Plant>(), spot, maxGrowRadius, component.GetCreator()))
		{
			return Result.SpotTaken;
		}
		inventory.RemoveItem(val2, val.m_amount);
		Quaternion val3 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
		GameObject val4 = Object.Instantiate<GameObject>(((Component)piece).gameObject, spot, val3);
		CopyCreator(component, val4.GetComponent<Piece>());
		WearNTear component3 = val4.GetComponent<WearNTear>();
		if (Object.op_Implicit((Object)(object)component3))
		{
			component3.OnPlaced();
		}
		IPlaced[] components = val4.GetComponents<IPlaced>();
		for (int num = 0; num < components.Length; num++)
		{
			components[num].OnPlaced();
		}
		piece.m_placeEffect.Create(spot, val3, val4.transform, 1f, -1, default(ZDOID));
		return Result.Planted;
	}

	private static void CopyCreator(Piece tree, Piece plant)
	{
		if (Object.op_Implicit((Object)(object)tree) && Object.op_Implicit((Object)(object)plant) && tree.GetCreator() != 0L)
		{
			plant.m_creator = tree.GetCreator();
			plant.m_creatorPlatformUserIDIndex = tree.GetCreatorPlatformUserIdIndex();
			ZDO zDO = plant.m_nview.GetZDO();
			zDO.Set(ZDOVars.s_creator, plant.m_creator);
			zDO.Set(ZDOVars.s_creatorIndex, plant.m_creatorPlatformUserIDIndex, false);
		}
	}

	private static bool ClimateFits(Plant plant, Heightmap heightmap, Vector3 pos)
	{
		//IL_0001: 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_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Invalid comparison between Unknown and I4
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Invalid comparison between Unknown and I4
		//IL_0027: 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)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Invalid comparison between Unknown and I4
		Biome biome = heightmap.GetBiome(pos, 0.02f, false);
		if ((biome & plant.m_biome) == 0)
		{
			return false;
		}
		if (!plant.m_tolerateHeat && (int)biome == 32 && !ShieldGenerator.IsInsideShield(pos))
		{
			return false;
		}
		if (!plant.m_tolerateCold && ((int)biome == 64 || (int)biome == 4))
		{
			return ShieldGenerator.IsInsideShield(pos);
		}
		return true;
	}

	public static bool CreatorHasWardAccess(long creator, Vector3 pos)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		bool flag = false;
		foreach (PrivateArea allArea in PrivateArea.m_allAreas)
		{
			if (allArea.IsEnabled() && allArea.IsInside(pos, 0f))
			{
				if (creator != 0L && (allArea.m_piece.GetCreator() == creator || allArea.IsPermitted(creator)))
				{
					return true;
				}
				flag = true;
			}
		}
		return !flag;
	}

	private static bool CultivatedAround(Vector3 pos)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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)
		//IL_003a: 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_0040: 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)
		for (int i = 0; i < 8; i++)
		{
			float num = (float)i * 2f * (float)Math.PI / 8f;
			Vector3 val = pos + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * 0.5f;
			Heightmap val2 = Heightmap.FindHeightmap(val);
			if (!Object.op_Implicit((Object)(object)val2) || !val2.IsCultivated(val))
			{
				return false;
			}
		}
		return true;
	}

	private static bool CanPlantAt(Piece piece, Plant plant, Vector3 pos, float maxGrowRadius, long creator)
	{
		//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_0010: 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)
		Heightmap heightmap = Heightmap.FindHeightmap(pos);
		if (SprotiTree.IsLoaded(pos) && CanPlantOnGround(heightmap, pos, creator, plant.m_needCultivatedGround))
		{
			return CanGrowAt(piece, plant, heightmap, pos, maxGrowRadius);
		}
		return false;
	}

	private static bool CanPlantOnGround(Heightmap heightmap, Vector3 pos, long creator, bool needsCultivated)
	{
		//IL_001c: 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_0025: 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_002d: 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_0044: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)heightmap) && (!needsCultivated || (heightmap.IsCultivated(pos) && CultivatedAround(pos))) && !Location.IsInsideNoBuildLocation(pos) && CreatorHasWardAccess(creator, pos) && !Physics.Raycast(pos, Vector3.up, 100f, RoofMask))
		{
			return !InsideSolid(pos);
		}
		return false;
	}

	internal static bool InsideSolid(Vector3 ground)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		return Physics.Raycast(ground + Vector3.up * 100f, Vector3.down, 99.8f, RockMask);
	}

	internal static bool CanRegrowAt(Piece sapling, Vector3 pos, Transform stump)
	{
		//IL_000d: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		Heightmap val = Heightmap.FindHeightmap(pos);
		if (!Object.op_Implicit((Object)(object)val) || Physics.RaycastAll(pos, Vector3.up, 100f, RoofMask).Any((RaycastHit hit) => !((Component)((RaycastHit)(ref hit)).collider).transform.IsChildOf(stump)))
		{
			return false;
		}
		float maxGrowRadius = TreeRegrowth.Saplings.Max((Piece p) => ((Component)p).GetComponent<Plant>().m_growRadius);
		return CanGrowAt(sa