Decompiled source of RavenScout v1.0.0

plugins/RavenScout.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("RavenScout")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6752175819ff0a5d3eae7a28de14a8a6f53b57c2")]
[assembly: AssemblyProduct("RavenScout")]
[assembly: AssemblyTitle("RavenScout")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RavenScout
{
	internal class Cost
	{
		public string Prefab;

		public int Amount;
	}
	internal static class Costs
	{
		public static List<Cost> Parse(string text)
		{
			List<Cost> list = new List<Cost>();
			string[] array = (text ?? "").Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length == 2 && array2[0].Trim().Length > 0 && int.TryParse(array2[1].Trim(), out var result) && result > 0)
				{
					list.Add(new Cost
					{
						Prefab = array2[0].Trim(),
						Amount = result
					});
				}
			}
			return list;
		}

		public static ItemData ItemData(string prefabName)
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return val.m_itemData;
		}

		public static string DisplayName(string prefabName)
		{
			ItemData val = ItemData(prefabName);
			if (val == null)
			{
				return prefabName;
			}
			return Localization.instance.Localize(val.m_shared.m_name);
		}

		public static List<string> Missing(List<Cost> costs)
		{
			return (from c in costs
				where ItemData(c.Prefab) == null
				select c.Prefab).ToList();
		}

		public static string Describe(List<Cost> costs)
		{
			if (costs.Count != 0)
			{
				return string.Join(", ", costs.Select((Cost c) => $"{c.Amount} {DisplayName(c.Prefab)}"));
			}
			return "free";
		}

		public static bool TryPay(Player player, List<Cost> costs)
		{
			List<string> list = Missing(costs);
			if (list.Count > 0)
			{
				((Character)player).Message((MessageType)2, "Needs items this game doesn't have (" + string.Join(", ", list) + ") - see the config", 0, (Sprite)null, false);
				return false;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			foreach (Cost cost in costs)
			{
				ItemData val = ItemData(cost.Prefab);
				if (inventory.CountItems(val.m_shared.m_name, -1, true) < cost.Amount)
				{
					((Character)player).Message((MessageType)2, $"Not enough {DisplayName(cost.Prefab)} ({cost.Amount} needed)", 0, (Sprite)null, false);
					return false;
				}
			}
			foreach (Cost cost2 in costs)
			{
				inventory.RemoveItem(ItemData(cost2.Prefab).m_shared.m_name, cost2.Amount, -1, true);
			}
			return true;
		}
	}
	internal static class FeatherGuide
	{
		private class Target
		{
			public string Label;

			public Vector3 Position;
		}

		private const float ArrivedDistance = 40f;

		public static void Use(Player player, ItemData item)
		{
			//IL_005c: 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)
			//IL_007e: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.FeatherGuideOn.Value)
			{
				((Character)player).Message((MessageType)2, "Read it in the tooltip", 0, (Sprite)null, false);
				return;
			}
			List<Target> list = Targets(item);
			if (list.Count == 0)
			{
				((Character)player).Message((MessageType)2, "This report has nothing for the feather to point to", 0, (Sprite)null, false);
				return;
			}
			int num = UsesLeft(item);
			if (num <= 0)
			{
				((Character)player).Message((MessageType)2, "The feather has gone still - it can't show the way any more", 0, (Sprite)null, false);
				return;
			}
			Vector3 position = ((Component)player).transform.position;
			Target target = null;
			float num2 = float.MaxValue;
			foreach (Target item2 in list)
			{
				float num3 = Scouting.DistanceXZ(position, item2.Position);
				if (num3 < num2)
				{
					num2 = num3;
					target = item2;
				}
			}
			if (num2 < 40f)
			{
				((Character)player).Message((MessageType)2, "The feather trembles: " + target.Label + " is right here", 0, (Sprite)null, false);
				return;
			}
			item.m_customData["ravenscout_guideuses"] = (num - 1).ToString();
			Vector3 val = target.Position - position;
			val.y = 0f;
			Vector3 forward = ((Component)player).transform.forward;
			forward.y = 0f;
			float num4 = Vector3.SignedAngle(forward, val, Vector3.up);
			string text = ((Mathf.Abs(num4) <= 30f) ? "ahead" : ((Mathf.Abs(num4) >= 150f) ? "behind you" : ((num4 > 0f) ? "to your right" : "to your left")));
			string text2 = num switch
			{
				2 => "1 more time", 
				1 => "it goes still", 
				_ => $"{num - 1} more times", 
			};
			((Character)player).Message((MessageType)2, "The raven's feather points " + text + ", toward the " + target.Label + " (" + Far(num2) + ")  -  " + text2, 0, (Sprite)null, false);
		}

		public static string TooltipLine(ItemData item)
		{
			if (!Plugin.FeatherGuideOn.Value || Targets(item).Count == 0)
			{
				return "";
			}
			int num = UsesLeft(item);
			if (num <= 0)
			{
				return "\n\n<color=grey>The feather has gone still.</color>";
			}
			return string.Format("\n\n<color=grey>Use it: the raven's feather points toward the nearest find ({0} use{1} left).</color>", num, (num == 1) ? "" : "s");
		}

		private static string Far(float metres)
		{
			if (Plugin.ReportPrecision.Value == Plugin.Precision.Exact)
			{
				return $"{Mathf.RoundToInt(metres)} m";
			}
			if (metres < 150f)
			{
				return "close";
			}
			if (metres < 700f)
			{
				return "not far";
			}
			if (!(metres < 2000f))
			{
				return "far away";
			}
			return "a good walk";
		}

		private static int UsesLeft(ItemData item)
		{
			if (!item.m_customData.TryGetValue("ravenscout_guideuses", out var value) || !int.TryParse(value, out var result))
			{
				return 0;
			}
			return result;
		}

		private static List<Target> Targets(ItemData item)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			List<Target> list = new List<Target>();
			if (!item.m_customData.TryGetValue("ravenscout_guide", out var value) || string.IsNullOrEmpty(value))
			{
				return list;
			}
			string[] array = value.Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				if (array2.Length == 3 && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					list.Add(new Target
					{
						Label = array2[0],
						Position = new Vector3(result, 0f, result2)
					});
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class ContainerHoverTextPatch
	{
		private static void Postfix(Container __instance, ref string __result)
		{
			RavenRoost component = ((Component)__instance).GetComponent<RavenRoost>();
			if (Object.op_Implicit((Object)(object)component))
			{
				__result += component.GetExtraHoverText();
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class GameStartPatch
	{
		private static void Postfix()
		{
			ScoutNet.Register();
		}
	}
	[HarmonyPatch(typeof(Container), "UseItem")]
	internal static class ContainerUseItemPatch
	{
		private static bool Prefix(Container __instance, Humanoid user, ItemData item, ref bool __result)
		{
			RavenRoost component = ((Component)__instance).GetComponent<RavenRoost>();
			if (Object.op_Implicit((Object)(object)component))
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null)
				{
					__result = component.Feed(val, item);
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ReportTooltipPatch
	{
		private static void Postfix(ItemData item, ref string __result)
		{
			if (ScoutReportItem.IsReport(item))
			{
				__result += ScoutReportItem.Tooltip(item);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	internal static class ReportUsePatch
	{
		private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item)
		{
			if (ScoutReportItem.IsReport(item))
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					if (inventory != null && inventory != ((Humanoid)val).GetInventory())
					{
						return true;
					}
					FeatherGuide.Use(val, item);
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Container), "CanBeRemoved")]
	internal static class ContainerCanBeRemovedPatch
	{
		private static void Postfix(Container __instance, ref bool __result)
		{
			if (__result)
			{
				RavenRoost component = ((Component)__instance).GetComponent<RavenRoost>();
				if (Object.op_Implicit((Object)(object)component) && component.IsAway)
				{
					__result = false;
				}
			}
		}
	}
	[BepInPlugin("com.ravenscout.valheim", "Raven Scout", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal enum HungryBehaviour
		{
			FlySlowly,
			Refuse
		}

		internal enum PinGrouping
		{
			Area,
			Patch,
			Each
		}

		internal enum NoMapBehaviour
		{
			Auto,
			MapOnly,
			ReportOnly,
			Both
		}

		internal enum Precision
		{
			Vague,
			Rough,
			Exact
		}

		internal enum ShareMode
		{
			Private,
			Everyone
		}

		public const string ModGuid = "com.ravenscout.valheim";

		public const string ModName = "Raven Scout";

		public const string ModVersion = "1.0.0";

		public const string RoostPrefabName = "piece_ravenroost";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> BaseRange;

		internal static ConfigEntry<float> MinDistance;

		internal static ConfigEntry<float> SecondsPer100m;

		internal static ConfigEntry<float> MinTripSeconds;

		internal static ConfigEntry<int> MaxTripsPerDay;

		internal static ConfigEntry<float> RevealRadius;

		internal static ConfigEntry<float> SpotRadius;

		internal static ConfigEntry<bool> SpotDungeons;

		internal static ConfigEntry<string> DungeonNames;

		internal static ConfigEntry<bool> SpotBosses;

		internal static ConfigEntry<string> BossNames;

		internal static ConfigEntry<bool> SpotTraders;

		internal static ConfigEntry<string> TraderNames;

		internal static ConfigEntry<bool> SpotOther;

		internal static ConfigEntry<string> OtherNames;

		internal static ConfigEntry<bool> SpotOres;

		internal static ConfigEntry<string> OreNames;

		internal static ConfigEntry<bool> SpotFood;

		internal static ConfigEntry<string> FoodNames;

		internal static ConfigEntry<float> FoodPinSpacing;

		internal static ConfigEntry<float> OrePinSpacing;

		internal static ConfigEntry<bool> LiveTracking;

		internal static ConfigEntry<bool> ShowRavenOnMap;

		internal static ConfigEntry<bool> LiveMessages;

		internal static ConfigEntry<PinGrouping> FoodPinGrouping;

		internal static ConfigEntry<PinGrouping> OrePinGrouping;

		internal static ConfigEntry<ShareMode> ShareFindings;

		internal static ConfigEntry<NoMapBehaviour> NoMapMode;

		internal static ConfigEntry<Precision> ReportPrecision;

		internal static ConfigEntry<KeyCode> RenameKey;

		internal static ConfigEntry<bool> ShareReports;

		internal static ConfigEntry<string> CopyCost;

		internal static ConfigEntry<bool> FeatherGuideOn;

		internal static ConfigEntry<int> FeatherGuideUses;

		internal static ConfigEntry<bool> UseFood;

		internal static ConfigEntry<HungryBehaviour> Hungry;

		internal static ConfigEntry<float> HungrySpeed;

		internal static ConfigEntry<int> MaxMeals;

		internal static ConfigEntry<float> MaxFoodSpeed;

		internal static ConfigEntry<float> RawMeatSpeed;

		internal static ConfigEntry<string> RawMeatItems;

		private Harmony _harmony;

		private const string OtherNamesV1 = "GoblinCamp=Fuling Village,DrakeNest=Drake Nest,TarPit=Tar Pit,Mistlands_Giant=Giant Remains,Mistlands_Excavation=Dvergr Excavation,WoodVillage=Abandoned Village,StoneHenge=Stone Circle,NorthVillage=Northern Village";

		private const string OtherNamesDefault = "GoblinCamp=Fuling Village,DrakeNest=Drake Nest,TarPit=Tar Pit,Mistlands_Giant=Giant Remains,Mistlands_Excavation=Dvergr Excavation,WoodVillage=Abandoned Village,StoneHenge=Stone Circle,NorthVillage=Northern Village,Mistlands_GuardTower=Dvergr Tower,Mistlands_Lighthouse=Dvergr Lighthouse,MorgenHole=Morgen Hole,CharredRuins=Charred Ruins,CharredTowerRuins=Charred Tower,VoltureNest=Volture Nest,HotSpring=Hot Spring,NorthMemorialPlace=Memorial Site";

		private void UpgradeDefault(ConfigEntry<string> entry, string oldDefault)
		{
			string value = entry.Value;
			string text = (string)((ConfigEntryBase)entry).DefaultValue;
			if (value != text && value == oldDefault)
			{
				entry.Value = text;
				Log.LogInfo((object)(((ConfigEntryBase)entry).Definition.Key + ": updated to the new default list"));
			}
		}

		internal static ConfigDescription Synced(string description)
		{
			//IL_000a: 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_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} });
		}

		private void Awake()
		{
			//IL_0669: Unknown result type (might be due to invalid IL or missing references)
			//IL_0673: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BaseRange = ((BaseUnityPlugin)this).Config.Bind<float>("Trip", "BaseRange", 1500f, Synced("How far (metres) a raven with an ordinary meal (x1.0) can fly out. The meal's speed multiplies it: x1.6 food = 2400 m."));
			MinDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Trip", "MinDistance", 200f, Synced("Shortest scouting trip, in metres."));
			SecondsPer100m = ((BaseUnityPlugin)this).Config.Bind<float>("Trip", "SecondsPer100m", 15f, Synced("Seconds a raven at x1.0 speed needs per 100 m. The trip is there and back, so 1 km out takes 300 s at x1.0. In-game time: sleeping speeds it up."));
			MinTripSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Trip", "MinTripSeconds", 30f, Synced("Shortest possible trip, in seconds."));
			MaxTripsPerDay = ((BaseUnityPlugin)this).Config.Bind<int>("Trip", "MaxTripsPerDay", 0, Synced("How many trips each roost can start per in-game day. 0 = unlimited (a roost always has only one raven out)."));
			NoMapMode = ((BaseUnityPlugin)this).Config.Bind<NoMapBehaviour>("Report", "NoMapMode", NoMapBehaviour.Auto, Synced("What the raven brings back. Auto: map reveal and pins, or a Scout Report item in no-map worlds (and for players who turned their own map off). MapOnly, ReportOnly, Both: as named. A no-map world never gets map changes: there MapOnly gives a report instead."));
			ReportPrecision = ((BaseUnityPlugin)this).Config.Bind<Precision>("Report", "ReportPrecision", Precision.Vague, Synced("How exact Scout Reports are. Vague: \"about 300 m\", \"far, over 2 km\", north-east. Rough: to the nearest 100 m. Exact: metres and compass degrees."));
			RenameKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "Rename", (KeyCode)110, "While looking at a roost: give it a name (shown on its reports).");
			ShareFindings = ((BaseUnityPlugin)this).Config.Bind<ShareMode>("Report", "ShareFindings", ShareMode.Private, Synced("Who gets a returning raven's map reveal and pins. Private: only the player who sent it. Everyone: every player; those offline get the latest trips of every roost when they join. Live tracking (the moving feather) is always just for the sender."));
			ShareReports = ((BaseUnityPlugin)this).Config.Bind<bool>("Report", "ShareReports", true, Synced("Show a Copy report button at the roost: anyone can take a copy of its last report, to keep or give to a friend."));
			CopyCost = ((BaseUnityPlugin)this).Config.Bind<string>("Report", "CopyCost", "Feathers:1", Synced("What a copy costs, as PrefabName:Amount, comma-separated. Empty = free."));
			FeatherGuideOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Report", "FeatherGuide", true, Synced("Using a Scout Report (hotbar key or right-click) makes the raven's feather point left, right, ahead or behind toward the nearest find on it. Never a marker or compass. Turn off for hardcore servers."));
			FeatherGuideUses = ((BaseUnityPlugin)this).Config.Bind<int>("Report", "FeatherGuideUses", 3, Synced("How many times each report's feather can point the way."));
			RevealRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Spotting", "RevealRadius", 120f, Synced("Half the width of the strip of map the raven reveals along its route, in metres."));
			SpotRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Spotting", "SpotRadius", 150f, Synced("How far from its route (metres) the raven spots places and ore."));
			SpotDungeons = ((BaseUnityPlugin)this).Config.Bind<bool>("Spotting", "SpotDungeons", true, Synced("Pin dungeons: crypts, caves, mines."));
			DungeonNames = ((BaseUnityPlugin)this).Config.Bind<string>("Spotting", "DungeonNames", "Crypt=Burial Chambers,HalfBurried_ForestCrypt=Burial Chambers,SunkenCrypt=Sunken Crypt,TrollCave=Troll Cave,MountainCave=Frost Cave,Mistlands_DvergrTownEntrance=Infested Mine,CharredFortress=Charred Fortress,Hildir_crypt=Smouldering Tomb,Hildir_cave=Howling Cavern,Hildir_plainsfortress=Sealed Tower", Synced("Location prefab name (or start of it) = pin label, comma-separated."));
			SpotBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("Spotting", "SpotBosses", true, Synced("Pin boss altars."));
			BossNames = ((BaseUnityPlugin)this).Config.Bind<string>("Spotting", "BossNames", "Eikthyrnir=Eikthyr,GDKing=The Elder,Bonemass=Bonemass,Dragonqueen=Moder,GoblinKing=Yagluth,Mistlands_DvergrBossEntrance=The Queen,FaderLocation=Fader,DN_Bossroom=Deep North boss", Synced("Location prefab name (or start of it) = pin label, comma-separated."));
			SpotTraders = ((BaseUnityPlugin)this).Config.Bind<bool>("Spotting", "SpotTraders", true, Synced("Pin traders."));
			TraderNames = ((BaseUnityPlugin)this).Config.Bind<string>("Spotting", "TraderNames", "Vendor_BlackForest=Haldor,Hildir_camp=Hildir,BogWitch_Camp=Bog Witch", Synced("Location prefab name (or start of it) = pin label, comma-separated."));
			SpotOther = ((BaseUnityPlugin)this).Config.Bind<bool>("Spotting", "SpotOther", true, Synced("Pin other interesting places."));
			OtherNames = ((BaseUnityPlugin)this).Config.Bind<string>("Spotting", "OtherNames", "GoblinCamp=Fuling Village,DrakeNest=Drake Nest,TarPit=Tar Pit,Mistlands_Giant=Giant Remains,Mistlands_Excavation=Dvergr Excavation,WoodVillage=Abandoned Village,StoneHenge=Stone Circle,NorthVillage=Northern Village,Mistlands_GuardTower=Dvergr Tower,Mistlands_Lighthouse=Dvergr Lighthouse,MorgenHole=Morgen Hole,CharredRuins=Charred Ruins,CharredTowerRuins=Charred Tower,VoltureNest=Volture Nest,HotSpring=Hot Spring,NorthMemorialPlace=Memorial Site", Synced("Location prefab name (or start of it) = pin label, comma-separated."));
			UpgradeDefault(OtherNames, "GoblinCamp=Fuling Village,DrakeNest=Drake Nest,TarPit=Tar Pit,Mistlands_Giant=Giant Remains,Mistlands_Excavation=Dvergr Excavation,WoodVillage=Abandoned Village,StoneHenge=Stone Circle,NorthVillage=Northern Village");
			SpotOres = ((BaseUnityPlugin)this).Config.Bind<bool>("Spotting", "SpotOres", true, Synced("Pin ore deposits. Only land someone has already been near has ore in it, so far wild land shows none."));
			OreNames = ((BaseUnityPlugin)this).Config.Bind<string>("Spotting", "OreNames", "rock4_copper=Copper,rock4_copper_frac=Copper,MineRock_Copper=Copper,MineRock_Tin=Tin,Pickable_Tin=Tin,rock3_silver=Silver,rock3_silver_frac=Silver,silvervein=Silver,silvervein_frac=Silver,MineRock_Obsidian=Obsidian,mudpile=Iron Scrap,mudpile2=Iron Scrap,mudpile_frac=Iron Scrap,mudpile2_frac=Iron Scrap,mudpile_beacon=Iron Scrap,giant_brain=Soft Tissue,giant_brain_frac=Soft Tissue,MineRock_Meteorite=Flametal,FlametalRockstand=Flametal,FlametalRockstand_frac=Flametal,goldvein=Gold,goldvein_frac=Gold", Synced("Ore object prefab name (exact) = pin label, comma-separated. Add :N to the label to need at least N close together."));
			SpotFood = ((BaseUnityPlugin)this).Config.Bind<bool>("Spotting", "SpotFood", false, Synced("Pin wild food: berries, mushrooms, thistle, wild seeds. Off by default: like ore, plants only exist in land someone has already been near, so it's a rough guide, not a full list. Picked plants and plants next to anything player-built (farms) are skipped."));
			FoodNames = ((BaseUnityPlugin)this).Config.Bind<string>("Spotting", "FoodNames", "RaspberryBush=Raspberries:3,BlueberryBush=Blueberries:3,CloudberryBush=Cloudberries:3,LingonberryBush=Lingonberries:3,Pickable_Mushroom=Mushrooms:2,Pickable_Mushroom_yellow=Yellow Mushrooms,Pickable_Mushroom_blue=Blue Mushrooms,Pickable_Mushroom_Magecap=Magecap,Pickable_Mushroom_JotunPuffs=Jotun Puffs,Pickable_SmokePuff=Smoke Puffs,Pickable_Thistle=Thistle:2,Pickable_Dandelion=Dandelions:3,Pickable_SeedCarrot=Carrot Seeds,Pickable_SeedTurnip=Turnip Seeds,Pickable_SeedOnion=Onion Seeds,Pickable_Barley_Wild=Wild Barley,Pickable_Flax_Wild=Wild Flax,Pickable_Fiddlehead=Fiddlehead,Pickable_RoyalJelly=Royal Jelly", Synced("Plant prefab name (exact) = pin label:N, comma-separated. N = how many must grow close together (within 60 m) for a pin; it stops single raspberry bushes from covering the map. Remove an entry to never pin it."));
			FoodPinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Spotting", "FoodPinSpacing", 300f, Synced("Within this many metres, patches of the same food share one pin (at the biggest patch, with the total count)."));
			OrePinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Spotting", "OrePinSpacing", 100f, Synced("Within this many metres, deposits of the same ore share one pin (with the total count)."));
			FoodPinGrouping = ((BaseUnityPlugin)this).Config.Bind<PinGrouping>("Spotting", "FoodPinGrouping", PinGrouping.Area, Synced("How food is pinned. Area: one pin per food within FoodPinSpacing, with the total count. Patch: one pin per patch (plants within 60 m, at least the :N in FoodNames). Each: a pin on every single plant (many pins)."));
			OrePinGrouping = ((BaseUnityPlugin)this).Config.Bind<PinGrouping>("Spotting", "OrePinGrouping", PinGrouping.Area, Synced("How ore is pinned. Area: one pin per ore within OrePinSpacing, with the total count. Patch: one pin per group of deposits within 60 m. Each: a pin on every single deposit."));
			LiveTracking = ((BaseUnityPlugin)this).Config.Bind<bool>("Live", "LiveTracking", true, Synced("Reveal the map and add pins while the raven flies, instead of all at once when it returns."));
			ShowRavenOnMap = ((BaseUnityPlugin)this).Config.Bind<bool>("Live", "ShowRavenOnMap", true, "Show your flying raven as a feather on the map and minimap (your own choice, not synced).");
			LiveMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Live", "LiveMessages", true, "Show a top-left message when your flying raven spots something (your own choice, not synced).");
			UseFood = ((BaseUnityPlugin)this).Config.Bind<bool>("Food", "UseFood", true, Synced("Ravens eat one stored meal per trip; better food flies farther and faster. Turn off to ignore food entirely."));
			Hungry = ((BaseUnityPlugin)this).Config.Bind<HungryBehaviour>("Food", "HungryRaven", HungryBehaviour.FlySlowly, Synced("What a raven does with no meals stored: FlySlowly (at HungrySpeed) or Refuse to fly."));
			HungrySpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Food", "HungrySpeed", 0.5f, Synced("Range and speed multiplier for a hungry raven when HungryRaven = FlySlowly."));
			MaxMeals = ((BaseUnityPlugin)this).Config.Bind<int>("Food", "MaxMeals", 10, Synced("How many meals a roost can store."));
			MaxFoodSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Food", "MaxFoodSpeed", 4f, Synced("Biggest multiplier a meal can give. Cooked food gives 1 + health / 50, e.g. 30 hp = x1.6, 75 hp = x2.5."));
			RawMeatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Food", "RawMeatSpeed", 1.25f, Synced("Multiplier for raw meat."));
			RawMeatItems = ((BaseUnityPlugin)this).Config.Bind<string>("Food", "RawMeatItems", "RawMeat,DeerMeat,NeckTail,WolfMeat,LoxMeat,SerpentMeat,BugMeat,HareMeat,ChickenMeat,AsksvinMeat,VoltureMeat,BoneMawSerpentMeat", Synced("Comma-separated item prefab names ravens eat raw."));
			RoostTiers.Bind(((BaseUnityPlugin)this).Config);
			PrefabManager.OnVanillaPrefabsAvailable += AddRoostPiece;
			_harmony = new Harmony("com.ravenscout.valheim");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"Raven Scout 1.0.0 loaded");
		}

		private void AddRoostPiece()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= AddRoostPiece;
			PieceConfig val = new PieceConfig();
			val.Name = "Raven Roost";
			val.Description = "Send a raven on a long scouting trip. It maps the land it flies over and pins what it sees.";
			val.PieceTable = "Hammer";
			val.Category = "Misc";
			val.CraftingStation = "piece_workbench";
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig("Wood", 10, 0, true),
				new RequirementConfig("Feathers", 4, 0, true),
				new RequirementConfig("FineWood", 4, 0, true)
			};
			PieceConfig val2 = val;
			CustomPiece val3 = new CustomPiece("piece_ravenroost", "piece_chest_wood", val2);
			GameObject piecePrefab = val3.PiecePrefab;
			Container component = piecePrefab.GetComponent<Container>();
			component.m_name = "Raven Roost";
			component.m_width = 4;
			component.m_height = 2;
			piecePrefab.AddComponent<RavenRoost>();
			RavenFlight.Prepare();
			try
			{
				RoostModel.Decorate(piecePrefab);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Couldn't build the roost model, using the plain chest look: {arg}");
			}
			PieceManager.Instance.AddPiece(val3);
			ScoutReportItem.Register();
		}

		private void Update()
		{
			ScoutWindow.Tick();
			if (Scouting.IsActive)
			{
				ScoutNet.ServerTick();
				ScoutLive.Tick();
				HandleKeys();
			}
		}

		private static void HandleKeys()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && !InventoryGui.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible() && !Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()))
			{
				GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
				RavenRoost ravenRoost = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<RavenRoost>() : null);
				if (Object.op_Implicit((Object)(object)ravenRoost) && ZInput.GetKeyDown(RenameKey.Value, false))
				{
					TextInput.instance.RequestText((TextReceiver)(object)ravenRoost, "Name this roost", 24);
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal class RavenFlight : MonoBehaviour
	{
		private enum Mode
		{
			TakeOff,
			Land
		}

		public const float LandingSeconds = 6f;

		public const float TakeOffSeconds = 12f;

		private const float MinTakeOffSeconds = 3f;

		private const float CruiseSpeed = 5f;

		private const float MaxCruiseSpeed = 30f;

		private const float ClimbSpeed = 1.6f;

		private const float CircleSeconds = 3f;

		private const float FadeSeconds = 1.5f;

		private const float LandingDistance = 30f;

		private const float LandingHeight = 14f;

		private static readonly string[] s_candidatePrefabs = new string[3] { "Crow", "Raven", "Seagal" };

		private static GameObject s_template;

		private static GameObject s_perchedTemplate;

		private static bool s_warned;

		private Mode _mode;

		private Vector3 _origin;

		private Vector3 _target;

		private Vector3 _heading;

		private float _duration;

		private float _circleSeconds = 3f;

		private float _cruiseSpeed = 5f;

		private float _age;

		private Vector3 _baseScale;

		public static GameObject Template
		{
			get
			{
				Prepare();
				return s_template;
			}
		}

		public static GameObject PerchedTemplate
		{
			get
			{
				Prepare();
				return s_perchedTemplate;
			}
		}

		public static void Prepare()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)s_template))
			{
				return;
			}
			GameObject val = null;
			string[] array = s_candidatePrefabs;
			foreach (string text in array)
			{
				val = PrefabManager.Instance.GetPrefab(text);
				if (Object.op_Implicit((Object)(object)val))
				{
					Plugin.Log.LogInfo((object)("Raven visual uses prefab '" + text + "'"));
					break;
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				if (!s_warned)
				{
					s_warned = true;
					Plugin.Log.LogWarning((object)"No bird prefab found; ravens will be invisible.");
				}
			}
			else
			{
				GameObject val2 = new GameObject("RavenScout_Templates");
				val2.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)val2);
				s_template = BuildTemplate(val, val2.transform, landed: false);
				s_perchedTemplate = BuildTemplate(val, val2.transform, landed: true);
			}
		}

		private static GameObject BuildTemplate(GameObject source, Transform holder, bool landed)
		{
			GameObject val = Object.Instantiate<GameObject>(source, holder);
			((Object)val).name = (landed ? "RavenScout_RavenPerched" : "RavenScout_Raven");
			RandomFlyingBird component = val.GetComponent<RandomFlyingBird>();
			if (Object.op_Implicit((Object)(object)component) && !component.m_singleModel && Object.op_Implicit((Object)(object)component.m_flyingModel) && Object.op_Implicit((Object)(object)component.m_landedModel))
			{
				component.m_flyingModel.SetActive(!landed);
				component.m_landedModel.SetActive(landed);
			}
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			Collider[] componentsInChildren2 = val.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Rigidbody[] componentsInChildren3 = val.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			val.AddComponent<BirdPose>().Flying = !landed;
			return val;
		}

		private static RavenFlight Spawn(Vector3 position, Vector3 facing)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)s_template))
			{
				Prepare();
				if (!Object.op_Implicit((Object)(object)s_template))
				{
					return null;
				}
			}
			facing.y = 0f;
			if (((Vector3)(ref facing)).sqrMagnitude < 0.01f)
			{
				facing = Vector3.forward;
			}
			GameObject val = Object.Instantiate<GameObject>(s_template, position, Quaternion.LookRotation(((Vector3)(ref facing)).normalized));
			val.SetActive(true);
			RavenFlight ravenFlight = val.AddComponent<RavenFlight>();
			ravenFlight._baseScale = val.transform.localScale;
			return ravenFlight;
		}

		public static float Launch(Vector3 from, Vector3 to, float flightSeconds, float speedMultiplier)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_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)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(flightSeconds * 0.8f, 3f, 12f);
			Vector3 val = to - from;
			val.y = 0f;
			val = ((((Vector3)(ref val)).sqrMagnitude < 0.01f) ? Vector3.forward : ((Vector3)(ref val)).normalized);
			RavenFlight ravenFlight = Spawn(from, val);
			if (!Object.op_Implicit((Object)(object)ravenFlight))
			{
				return 0f;
			}
			ravenFlight._mode = Mode.TakeOff;
			ravenFlight._origin = from;
			ravenFlight._heading = val;
			ravenFlight._duration = num;
			ravenFlight._circleSeconds = Mathf.Min(3f, num * 0.3f);
			ravenFlight._cruiseSpeed = Mathf.Min(30f, 5f * Mathf.Max(1f, speedMultiplier));
			return num;
		}

		public static void Land(Vector3 roost, Vector3 fromPos, float seconds)
		{
			//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_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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0051: 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_005e: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = fromPos - roost;
			val.y = 0f;
			if (fromPos == Vector3.zero || ((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Random.insideUnitSphere;
				val.y = 0f;
			}
			val = ((((Vector3)(ref val)).sqrMagnitude < 0.01f) ? Vector3.back : ((Vector3)(ref val)).normalized);
			Vector3 val2 = roost + val * 30f + Vector3.up * 14f;
			RavenFlight ravenFlight = Spawn(val2, -val);
			if (Object.op_Implicit((Object)(object)ravenFlight))
			{
				ravenFlight._mode = Mode.Land;
				ravenFlight._origin = val2;
				ravenFlight._target = roost;
				ravenFlight._heading = -val;
				ravenFlight._duration = Mathf.Max(1f, seconds);
			}
		}

		private void Update()
		{
			_age += Time.deltaTime;
			if (_mode == Mode.TakeOff)
			{
				UpdateTakeOff();
			}
			else
			{
				UpdateLanding();
			}
		}

		private void UpdateTakeOff()
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: 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_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_006d: 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_0075: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_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_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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position;
			Vector3 val2;
			if (_age < _circleSeconds)
			{
				float num = _age / _circleSeconds;
				float num2 = num * (float)Math.PI * 2f;
				float num3 = Mathf.Lerp(0.5f, 3f, num);
				Vector3 val = Quaternion.LookRotation(_heading) * new Vector3(Mathf.Sin(num2), 0f, 0f - Mathf.Cos(num2)) * num3;
				position = _origin + val + Vector3.up * (_age * 1.6f * 1.5f);
				val2 = Quaternion.LookRotation(_heading) * new Vector3(Mathf.Cos(num2), 0f, Mathf.Sin(num2));
			}
			else
			{
				float num4 = _age - _circleSeconds;
				position = _origin + Quaternion.LookRotation(_heading) * new Vector3(0f, 0f, -3f) + Vector3.up * (_circleSeconds * 1.6f * 1.5f) + _heading * (num4 * _cruiseSpeed) + Vector3.up * (num4 * 1.6f);
				val2 = _heading;
			}
			((Component)this).transform.position = position;
			((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, Quaternion.LookRotation(val2), Time.deltaTime * 6f);
			FadeAndExpire(_duration);
		}

		private void UpdateLanding()
		{
			//IL_002a: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01(_age / _duration);
			float num2 = 1f - (1f - num) * (1f - num);
			Vector3 position = Vector3.Lerp(_origin, _target, num2);
			position.y += Mathf.Sin(num * (float)Math.PI) * 2f;
			((Component)this).transform.position = position;
			((Component)this).transform.rotation = Quaternion.LookRotation(_heading);
			if (_age >= _duration)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void FadeAndExpire(float lifetime)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			float num = lifetime - _age;
			if (num <= 0f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else if (num < 1.5f)
			{
				((Component)this).transform.localScale = _baseScale * (num / 1.5f);
			}
		}
	}
	internal class BirdPose : MonoBehaviour
	{
		private static readonly int s_flyingHash = Animator.StringToHash("flying");

		private static readonly int s_flappingHash = Animator.StringToHash("flapping");

		public bool Flying;

		private Animator _animator;

		private bool _hasFlying;

		private bool _hasFlapping;

		private void Start()
		{
			_animator = ((Component)this).GetComponentInChildren<Animator>();
			if (Object.op_Implicit((Object)(object)_animator))
			{
				AnimatorControllerParameter[] parameters = _animator.parameters;
				foreach (AnimatorControllerParameter val in parameters)
				{
					_hasFlying |= val.nameHash == s_flyingHash;
					_hasFlapping |= val.nameHash == s_flappingHash;
				}
				Apply();
			}
		}

		private void Update()
		{
			Apply();
		}

		private void Apply()
		{
			if (Object.op_Implicit((Object)(object)_animator) && ((Behaviour)_animator).isActiveAndEnabled)
			{
				if (_hasFlying)
				{
					_animator.SetBool(s_flyingHash, Flying);
				}
				if (_hasFlapping)
				{
					_animator.SetBool(s_flappingHash, Flying);
				}
			}
		}
	}
	internal static class RavenFood
	{
		public const string MealsKey = "ravenscout_meals";

		private static HashSet<string> s_rawMeats;

		private static string s_rawMeatsSource;

		public static float SpeedFor(ItemData item)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			if (item == null)
			{
				return 0f;
			}
			SharedData shared = item.m_shared;
			if ((int)shared.m_itemType == 2 && shared.m_food > 0f)
			{
				return Mathf.Min(Plugin.MaxFoodSpeed.Value, 1f + shared.m_food / 50f);
			}
			string item2 = (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : "");
			if (!RawMeats().Contains(item2))
			{
				return 0f;
			}
			return Plugin.RawMeatSpeed.Value;
		}

		private static HashSet<string> RawMeats()
		{
			string text = Plugin.RawMeatItems.Value ?? "";
			if (s_rawMeats == null || text != s_rawMeatsSource)
			{
				s_rawMeatsSource = text;
				s_rawMeats = new HashSet<string>(from x in text.Split(new char[1] { ',' })
					select x.Trim() into x
					where x.Length > 0
					select x);
			}
			return s_rawMeats;
		}

		public static ItemData BestFood(Inventory inventory)
		{
			ItemData result = null;
			float num = 0f;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				float num2 = SpeedFor(allItem);
				if (num2 > num && !allItem.m_equipped)
				{
					result = allItem;
					num = num2;
				}
			}
			return result;
		}

		public static List<float> ReadMeals(ZDO zdo)
		{
			List<float> list = new List<float>();
			string[] array = zdo.GetString("ravenscout_meals", "").Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				if (float.TryParse(array[i], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result > 0f)
				{
					list.Add(result);
				}
			}
			list.Sort((float a, float b) => b.CompareTo(a));
			return list;
		}

		public static void WriteMeals(ZDO zdo, List<float> meals)
		{
			meals.Sort((float a, float b) => b.CompareTo(a));
			zdo.Set("ravenscout_meals", string.Join(";", meals.Select((float m) => m.ToString("0.###", CultureInfo.InvariantCulture))));
		}

		public static string FormatSpeed(float speed)
		{
			return $"x{speed:0.##}";
		}
	}
	public class RavenRoost : MonoBehaviour, TextReceiver
	{
		private const string TripsLogKey = "ravenscout_trips";

		private const float LandingViewDistance = 80f;

		private ZNetView _nview;

		private Container _container;

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

		public float Heading { get; private set; }

		public float Distance { get; private set; } = 1000f;

		public int TierIndex
		{
			get
			{
				if (Zdo == null)
				{
					return 0;
				}
				return Mathf.Clamp(Zdo.GetInt("ravenscout_tier", 0), 0, RoostTiers.Max);
			}
		}

		internal RoostTier Tier => RoostTiers.Get(TierIndex);

		internal RoostTier NextTier
		{
			get
			{
				if (TierIndex >= RoostTiers.Max)
				{
					return null;
				}
				return RoostTiers.Get(TierIndex + 1);
			}
		}

		private ZDO Zdo
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)_nview) || !_nview.IsValid())
				{
					return null;
				}
				return _nview.GetZDO();
			}
		}

		internal ScoutTrip Trip
		{
			get
			{
				if (Zdo == null)
				{
					return null;
				}
				return Scouting.ReadTrip(Zdo);
			}
		}

		public bool IsAway
		{
			get
			{
				ScoutTrip trip = Trip;
				if (trip != null && Scouting.IsActive)
				{
					return trip.IsAway(Scouting.Now);
				}
				return false;
			}
		}

		public string LastReport
		{
			get
			{
				ZDO zdo = Zdo;
				return ((zdo != null) ? zdo.GetString("ravenscout_report", "") : null) ?? "";
			}
		}

		public string RoostName
		{
			get
			{
				if (Zdo == null)
				{
					return "Raven Roost";
				}
				return Scouting.RoostName(Zdo);
			}
		}

		public bool HasReportToCopy
		{
			get
			{
				if (Zdo != null)
				{
					return !string.IsNullOrEmpty(Zdo.GetString("ravenscout_lasttext", ""));
				}
				return false;
			}
		}

		public int PendingReports
		{
			get
			{
				if (Zdo == null)
				{
					return 0;
				}
				return Scouting.ReadPending(Zdo).Count;
			}
		}

		public float MaxRange => Scouting.RangeFor(NextMealSpeed * Tier.RangeMultiplier);

		public float FlightSpeed => NextMealSpeed * Tier.SpeedMultiplier;

		public float PlannedDistance => Mathf.Clamp(Distance, Plugin.MinDistance.Value, Mathf.Max(Plugin.MinDistance.Value, MaxRange));

		public Vector3 PlannedTarget => Scouting.TargetPoint(((Component)this).transform.position, Heading, PlannedDistance);

		public float PlannedSeconds => Scouting.TripSeconds(Scouting.DistanceXZ(((Component)this).transform.position, PlannedTarget), FlightSpeed);

		public List<float> Meals
		{
			get
			{
				if (Zdo == null)
				{
					return new List<float>();
				}
				return RavenFood.ReadMeals(Zdo);
			}
		}

		public float NextMealSpeed
		{
			get
			{
				if (!Plugin.UseFood.Value)
				{
					return 1f;
				}
				List<float> meals = Meals;
				if (meals.Count <= 0)
				{
					return Mathf.Max(0.05f, Plugin.HungrySpeed.Value);
				}
				return meals[0];
			}
		}

		public bool IsHungry
		{
			get
			{
				if (Plugin.UseFood.Value)
				{
					return Meals.Count == 0;
				}
				return false;
			}
		}

		public bool RefusesToFly
		{
			get
			{
				if (IsHungry)
				{
					return Plugin.Hungry.Value == Plugin.HungryBehaviour.Refuse;
				}
				return false;
			}
		}

		public string MealsStatus
		{
			get
			{
				if (!Plugin.UseFood.Value)
				{
					return "";
				}
				List<float> meals = Meals;
				if (meals.Count > 0)
				{
					return $"Meals: {meals.Count}/{Mathf.Max(1, Plugin.MaxMeals.Value)} (next {RavenFood.FormatSpeed(meals[0])})";
				}
				if (!RefusesToFly)
				{
					return "<color=#ff9a40>Hungry - flies short and slow (" + RavenFood.FormatSpeed(NextMealSpeed) + ")</color>";
				}
				return "<color=#ff6060>Hungry - won't fly until fed</color>";
			}
		}

		public static bool TripsLimited => Plugin.MaxTripsPerDay.Value > 0;

		public int TripsToday
		{
			get
			{
				ZDO zdo = Zdo;
				string[] array = (((zdo != null) ? zdo.GetString("ravenscout_trips", "") : null) ?? "").Split(new char[1] { ':' });
				if (array.Length == 2 && int.TryParse(array[0], out var result) && int.TryParse(array[1], out var result2) && result == Scouting.Day(Scouting.Now))
				{
					return result2;
				}
				return 0;
			}
		}

		public int TripsLeft
		{
			get
			{
				if (!TripsLimited)
				{
					return int.MaxValue;
				}
				return Mathf.Max(0, Plugin.MaxTripsPerDay.Value - TripsToday);
			}
		}

		public string TripsStatus
		{
			get
			{
				if (!TripsLimited)
				{
					return "";
				}
				int value = Plugin.MaxTripsPerDay.Value;
				if (TripsLeft <= 0)
				{
					return $"<color=#ff6060>Tired ({value}/{value} today) - flies again tomorrow</color>";
				}
				return $"Trips today: {TripsToday}/{value}";
			}
		}

		private Transform SeatedRaven => ((Component)this).transform.Find("RavenScout_PerchedRaven");

		public Vector3 SeatPosition
		{
			get
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				Transform seatedRaven = SeatedRaven;
				if (!Object.op_Implicit((Object)(object)seatedRaven))
				{
					return ((Component)this).transform.position + Vector3.up * 1.5f;
				}
				return seatedRaven.position;
			}
		}

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_container = ((Component)this).GetComponent<Container>();
			if (Object.op_Implicit((Object)(object)_nview) && _nview.GetZDO() != null)
			{
				((MonoBehaviour)this).InvokeRepeating("UpdateSeat", 0.5f, 0.5f);
				((MonoBehaviour)this).InvokeRepeating("DeliverReports", 1f, 2f);
				RoostTiers.ValidateItems();
			}
		}

		public void Upgrade(Player player)
		{
			RoostTier nextTier = NextTier;
			if (Zdo != null && Object.op_Implicit((Object)(object)player) && nextTier != null && EnsureOwner(player) && Costs.TryPay(player, nextTier.Requirements()))
			{
				Zdo.Set("ravenscout_tier", nextTier.Index);
				((Character)player).Message((MessageType)2, $"Upgraded to {nextTier.Name}: range x{nextTier.RangeMultiplier:0.##}, speed x{nextTier.SpeedMultiplier:0.##}", 0, (Sprite)null, false);
				Plugin.Log.LogInfo((object)("'" + RoostName + "' upgraded to " + nextTier.Name));
			}
		}

		public string GetText()
		{
			ZDO zdo = Zdo;
			return ((zdo != null) ? zdo.GetString("ravenscout_name", "") : null) ?? "";
		}

		public void SetText(string text)
		{
			if (Zdo != null && EnsureOwner(Player.m_localPlayer))
			{
				Zdo.Set("ravenscout_name", (text ?? "").Trim());
			}
		}

		public void CopyReport(Player player)
		{
			if (Zdo == null || !Object.op_Implicit((Object)(object)player) || !Plugin.ShareReports.Value)
			{
				return;
			}
			string text = Zdo.GetString("ravenscout_lasttext", "");
			if (string.IsNullOrEmpty(text))
			{
				((Character)player).Message((MessageType)2, "No report to copy yet - send the raven first", 0, (Sprite)null, false);
				return;
			}
			ItemData val = ScoutReportItem.Create(text, RoostName, Zdo.GetInt("ravenscout_lastday", 0), Zdo.GetString("ravenscout_lastguide", ""));
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (val == null || !inventory.CanAddItem(val, -1))
			{
				((Character)player).Message((MessageType)2, "Your bag is full", 0, (Sprite)null, false);
			}
			else if (Costs.TryPay(player, Costs.Parse(Plugin.CopyCost.Value)))
			{
				inventory.AddItem(val);
				((Character)player).Message((MessageType)2, "A copy of the report is in your bag", 0, (Sprite)null, false);
			}
		}

		private void DeliverReports()
		{
			if (Zdo == null || !_nview.IsOwner() || !Scouting.IsActive || _container.GetInventory() == null)
			{
				return;
			}
			List<PendingReport> list = Scouting.ReadPending(Zdo);
			if (list.Count == 0)
			{
				return;
			}
			Inventory inventory = _container.GetInventory();
			List<PendingReport> list2 = new List<PendingReport>();
			foreach (PendingReport item in list)
			{
				ItemData val = ScoutReportItem.Create(item.Text, item.Roost, item.Day, item.Guide);
				if (val == null || !inventory.CanAddItem(val, -1) || !inventory.AddItem(val))
				{
					list2.Add(item);
				}
			}
			if (list2.Count != list.Count)
			{
				Scouting.WritePending(Zdo, list2);
			}
		}

		public void SetHeading(float degrees)
		{
			Heading = Mathf.Repeat(Mathf.Round(degrees), 360f);
		}

		public void SetDistance(float metres)
		{
			Distance = Mathf.Clamp(Mathf.Round(metres / 50f) * 50f, Plugin.MinDistance.Value, Mathf.Max(Plugin.MinDistance.Value, MaxRange));
		}

		public bool Feed(Player player, ItemData item)
		{
			if (Zdo == null || !Object.op_Implicit((Object)(object)player))
			{
				return false;
			}
			float num = RavenFood.SpeedFor(item);
			if (num <= 0f)
			{
				return false;
			}
			if (!EnsureOwner(player))
			{
				return true;
			}
			List<float> meals = Meals;
			int num2 = Mathf.Max(1, Plugin.MaxMeals.Value);
			if (meals.Count >= num2)
			{
				((Character)player).Message((MessageType)2, "The raven is full", 0, (Sprite)null, false);
				return true;
			}
			if (!((Humanoid)player).GetInventory().RemoveOneItem(item))
			{
				return true;
			}
			meals.Add(num);
			RavenFood.WriteMeals(Zdo, meals);
			((Character)player).Message((MessageType)2, Localization.instance.Localize($"The raven ate {item.m_shared.m_name} ({RavenFood.FormatSpeed(num)}: {Scouting.FormatDistance(Scouting.RangeFor(num * Tier.RangeMultiplier))} range) - {meals.Count}/{num2} meals"), 0, (Sprite)null, false);
			return true;
		}

		public void FeedBest(Player player)
		{
			ItemData val = RavenFood.BestFood(((Humanoid)player).GetInventory());
			if (val == null)
			{
				((Character)player).Message((MessageType)2, "You have nothing the raven will eat", 0, (Sprite)null, false);
			}
			else
			{
				Feed(player, val);
			}
		}

		private bool EnsureOwner(Player player)
		{
			if (Zdo == null)
			{
				return false;
			}
			if (_nview.IsOwner())
			{
				return true;
			}
			if (!_container.IsInUse() && Zdo.GetInt(ZDOVars.s_inUse, 0) == 0)
			{
				_nview.ClaimOwnership();
			}
			if (!_nview.IsOwner())
			{
				if (Object.op_Implicit((Object)(object)player))
				{
					((Character)player).Message((MessageType)2, "Someone else is using this roost", 0, (Sprite)null, false);
				}
				return false;
			}
			return true;
		}

		public void Send(Player player)
		{
			//IL_00a3: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			if (Zdo == null || !Object.op_Implicit((Object)(object)player) || !Scouting.IsActive || !EnsureOwner(player))
			{
				return;
			}
			double now = Scouting.Now;
			ScoutTrip trip = Trip;
			if (trip != null && trip.IsAway(now))
			{
				((Character)player).Message((MessageType)2, "The raven is still out scouting - back in " + Scouting.FormatDuration(trip.ReturnAt - now), 0, (Sprite)null, false);
				return;
			}
			if (TripsLimited && TripsLeft <= 0)
			{
				((Character)player).Message((MessageType)2, "The raven is tired - it rests until tomorrow", 0, (Sprite)null, false);
				return;
			}
			if (RefusesToFly)
			{
				((Character)player).Message((MessageType)2, "Your raven is hungry - feed it first", 0, (Sprite)null, false);
				return;
			}
			float nextMealSpeed = NextMealSpeed;
			float flightSpeed = FlightSpeed;
			Vector3 plannedTarget = PlannedTarget;
			float num = Scouting.DistanceXZ(((Component)this).transform.position, plannedTarget);
			if (num < Plugin.MinDistance.Value * 0.5f)
			{
				((Character)player).Message((MessageType)2, "That way is the edge of the world", 0, (Sprite)null, false);
				return;
			}
			float num2 = Scouting.TripSeconds(num, flightSpeed);
			ScoutTrip trip2 = new ScoutTrip
			{
				SentAt = now,
				ReturnAt = now + (double)num2,
				From = ((Component)this).transform.position,
				Target = plannedTarget,
				Sender = player.GetPlayerName(),
				Meal = nextMealSpeed,
				SenderNoMap = Game.m_noMap,
				Tier = TierIndex
			};
			Scouting.WriteTrip(Zdo, trip2);
			ScoutNet.TripStarted(Zdo.m_uid);
			List<float> meals = Meals;
			if (Plugin.UseFood.Value && meals.Count > 0)
			{
				meals.RemoveAt(0);
				RavenFood.WriteMeals(Zdo, meals);
			}
			if (TripsLimited)
			{
				Zdo.Set("ravenscout_trips", $"{Scouting.Day(now)}:{TripsToday + 1}");
			}
			RavenFlight.Launch(SeatPosition, plannedTarget, num2, flightSpeed);
			ScoutNet.BroadcastTakeOff(SeatPosition, plannedTarget, num2, flightSpeed);
			UpdateSeat();
			string text = Scouting.CompassName(Scouting.Heading(((Component)this).transform.position, plannedTarget));
			((Character)player).Message((MessageType)2, "Raven flies " + Scouting.FormatDistance(num) + " " + text + " - back in " + Scouting.FormatDuration(num2), 0, (Sprite)null, false);
			Plugin.Log.LogInfo((object)$"Scout sent {num:0} m {text} ({Heading:0} deg) from {((Component)this).transform.position}, meal {RavenFood.FormatSpeed(nextMealSpeed)}, {num2:0} s");
		}

		private void UpdateSeat()
		{
			//IL_00a0: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			Transform seatedRaven = SeatedRaven;
			if (!Object.op_Implicit((Object)(object)seatedRaven) || !Scouting.IsActive)
			{
				return;
			}
			ScoutTrip trip = Trip;
			double now = Scouting.Now;
			bool flag = trip?.IsAway(now) ?? false;
			if (((Component)seatedRaven).gameObject.activeSelf == flag)
			{
				((Component)seatedRaven).gameObject.SetActive(!flag);
			}
			if (flag)
			{
				Player localPlayer = Player.m_localPlayer;
				double num = trip.ReturnAt - now;
				float num2 = Mathf.Clamp((float)(trip.ReturnAt - trip.SentAt) * 0.5f, 1.5f, 6f);
				if (Object.op_Implicit((Object)(object)localPlayer) && num <= (double)num2 && Vector3.Distance(((Component)localPlayer).transform.position, ((Component)this).transform.position) <= 80f && s_landingsShown.Add(trip.Key(Zdo.m_uid)))
				{
					RavenFlight.Land(SeatPosition, trip.Target, (float)Math.Max(0.5, num));
				}
			}
		}

		public string GetExtraHoverText()
		{
			//IL_0037: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			if (Zdo == null || !Scouting.IsActive)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append($"\n<color=orange>{RoostName}</color>  <color=grey>{Tier.Name}</color>  [<color=yellow><b>{Plugin.RenameKey.Value}</b></color>] Rename");
			ScoutTrip trip = Trip;
			double now = Scouting.Now;
			if (trip != null && trip.IsAway(now))
			{
				string text = Scouting.CompassName(Scouting.Heading(trip.From, trip.Target));
				stringBuilder.Append("\nRaven out scouting " + Scouting.FormatDistance(trip.Distance) + " " + text + " - back in " + Scouting.FormatDuration(trip.ReturnAt - now));
			}
			else if (trip != null && !trip.Reported)
			{
				stringBuilder.Append("\n<color=yellow>Raven is back - its news is for " + trip.Sender + "</color>");
			}
			else
			{
				stringBuilder.Append("\nRaven ready  <color=grey>range " + Scouting.FormatDistance(MaxRange) + "</color>");
			}
			if (Plugin.UseFood.Value)
			{
				stringBuilder.Append("\n" + MealsStatus);
				stringBuilder.Append("\n<color=grey>Use food from your hotbar on the roost to feed</color>");
			}
			if (TripsLimited)
			{
				stringBuilder.Append("\n" + TripsStatus);
			}
			int pendingReports = PendingReports;
			if (pendingReports > 0)
			{
				stringBuilder.Append(string.Format("\n<color=yellow>{0} Scout Report{1} waiting - make room in the box</color>", pendingReports, (pendingReports == 1) ? "" : "s"));
			}
			return stringBuilder.ToString();
		}
	}
	internal static class RoostModel
	{
		private static readonly string[] s_poleCandidates = new string[3] { "wood_pole2", "wood_pole", "wood_pole_log" };

		private const float PoleHeight = 2.2f;

		private const float PoleThickness = 0.2f;

		private const float BirdScale = 1f;

		public static void Decorate(GameObject roost)
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			Bounds chestBounds = LocalBounds(roost, roost.transform);
			Vector3? poleTop = AddPole(roost, chestBounds);
			AddBird(roost, poleTop);
		}

		private static Vector3? AddPole(GameObject roost, Bounds chestBounds)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			string[] array = s_poleCandidates;
			foreach (string text in array)
			{
				val = PrefabManager.Instance.GetPrefab(text);
				if (Object.op_Implicit((Object)(object)val))
				{
					Plugin.Log.LogInfo((object)("Roost post uses prefab '" + text + "'"));
					break;
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				Plugin.Log.LogWarning((object)"No wooden pole prefab found; roost keeps the plain chest look.");
				return null;
			}
			WearNTear component = val.GetComponent<WearNTear>();
			GameObject val2 = Object.Instantiate<GameObject>((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_new)) ? component.m_new : val, roost.transform);
			((Object)val2).name = "RavenScout_Pole";
			val2.SetActive(true);
			MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren<MonoBehaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localScale = Vector3.one;
			Bounds val3 = LocalBounds(val2, roost.transform);
			if (((Bounds)(ref val3)).size.y < 0.01f)
			{
				Object.DestroyImmediate((Object)(object)val2);
				return null;
			}
			float num = Mathf.Max(new float[3]
			{
				((Bounds)(ref val3)).size.x,
				((Bounds)(ref val3)).size.z,
				0.01f
			});
			float num2 = 0.2f / num;
			val2.transform.localScale = new Vector3(num2, 2.2f / ((Bounds)(ref val3)).size.y, num2);
			val3 = LocalBounds(val2, roost.transform);
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(((Bounds)(ref chestBounds)).max.x + ((Bounds)(ref val3)).extents.x + 0.05f - ((Bounds)(ref val3)).center.x, ((Bounds)(ref chestBounds)).min.y - ((Bounds)(ref val3)).min.y, ((Bounds)(ref chestBounds)).center.z - ((Bounds)(ref val3)).center.z);
			Transform transform = val2.transform;
			transform.localPosition += val4;
			val3 = LocalBounds(val2, roost.transform);
			return new Vector3(((Bounds)(ref val3)).center.x, ((Bounds)(ref val3)).max.y, ((Bounds)(ref val3)).center.z);
		}

		private static void AddBird(GameObject roost, Vector3? poleTop)
		{
			//IL_0033: 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_0053: 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)
			//IL_0074: 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)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			GameObject perchedTemplate = RavenFlight.PerchedTemplate;
			if (Object.op_Implicit((Object)(object)perchedTemplate))
			{
				GameObject obj = Object.Instantiate<GameObject>(perchedTemplate, roost.transform);
				((Object)obj).name = "RavenScout_PerchedRaven";
				obj.SetActive(true);
				obj.transform.localRotation = Quaternion.identity;
				obj.transform.localScale = perchedTemplate.transform.localScale * 1f;
				obj.transform.localPosition = Vector3.zero;
				Bounds val = LocalBounds(obj, roost.transform);
				Vector3 value = default(Vector3);
				if (poleTop.HasValue)
				{
					value = poleTop.Value;
				}
				else
				{
					Bounds val2 = LocalBounds(roost, roost.transform);
					((Vector3)(ref value))..ctor(((Bounds)(ref val2)).center.x, ((Bounds)(ref val2)).max.y, ((Bounds)(ref val2)).center.z);
				}
				obj.transform.localPosition = value - new Vector3(((Bounds)(ref val)).center.x, ((Bounds)(ref val)).min.y, ((Bounds)(ref val)).center.z);
			}
		}

		public static Bounds LocalBounds(GameObject part, Transform space)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			bool any = false;
			Bounds result = default(Bounds);
			Matrix4x4 toSpace = space.worldToLocalMatrix;
			MeshFilter[] componentsInChildren = part.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)((Component)val).GetComponent<MeshRenderer>()) && IsShown(((Component)val).transform, part.transform))
				{
					Add(val.sharedMesh, ((Component)val).transform);
				}
			}
			SkinnedMeshRenderer[] componentsInChildren2 = part.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			foreach (SkinnedMeshRenderer val2 in componentsInChildren2)
			{
				if (IsShown(((Component)val2).transform, part.transform))
				{
					Add(val2.sharedMesh, ((Component)val2).transform);
				}
			}
			return result;
			void Add(Mesh mesh, Transform t)
			{
				//IL_000a: 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_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: 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_0052: 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_005c: 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)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: 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_0075: 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_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)
				if (Object.op_Implicit((Object)(object)mesh))
				{
					Matrix4x4 val3 = toSpace * t.localToWorldMatrix;
					Bounds bounds = mesh.bounds;
					for (int j = 0; j < 8; j++)
					{
						Vector3 val4 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
						Vector3 val5 = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(val4);
						if (!any)
						{
							result = new Bounds(val5, Vector3.zero);
							any = true;
						}
						else
						{
							((Bounds)(ref result)).Encapsulate(val5);
						}
					}
				}
			}
		}

		private static bool IsShown(Transform t, Transform root)
		{
			while (Object.op_Implicit((Object)(object)t) && (Object)(object)t != (Object)(object)root)
			{
				if (!((Component)t).gameObject.activeSelf)
				{
					return false;
				}
				t = t.parent;
			}
			return true;
		}
	}
	internal class RoostTier
	{
		public int Index;

		public string Name;

		public string Biome;

		public ConfigEntry<string> Cost;

		public ConfigEntry<float> Range;

		public ConfigEntry<float> Speed;

		public ConfigEntry<float> Sight;

		public float RangeMultiplier => Mathf.Max(0.1f, Range.Value);

		public float SpeedMultiplier => Mathf.Max(0.1f, Speed.Value);

		public float SightMultiplier => Mathf.Max(0.1f, Sight.Value);

		public List<Cost> Requirements()
		{
			return Costs.Parse(Cost.Value);
		}
	}
	internal static class RoostTiers
	{
		public const string TierKey = "ravenscout_tier";

		private static readonly List<RoostTier> s_tiers = new List<RoostTier>();

		private static bool s_validated;

		internal static ConfigEntry<int> OresFromTier;

		internal static ConfigEntry<int> FoodFromTier;

		public static IReadOnlyList<RoostTier> All => s_tiers;

		public static int Max => s_tiers.Count - 1;

		public static RoostTier Get(int index)
		{
			return s_tiers[Mathf.Clamp(index, 0, s_tiers.Count - 1)];
		}

		public static void Bind(ConfigFile config)
		{
			OresFromTier = config.Bind<int>("Tiers", "OresFromTier", 1, Plugin.Synced("Lowest roost tier whose raven spots ore (0 = Wooden, 1 = Bronze, ...). 0 = every roost."));
			FoodFromTier = config.Bind<int>("Tiers", "FoodFromTier", 2, Plugin.Synced("Lowest roost tier whose raven spots wild food (also needs SpotFood = true). 0 = every roost."));
			Add(config, "Wooden Roost", "Meadows", "", 1f, 1f, 1f);
			Add(config, "Bronze Roost", "Black Forest", "Bronze:5,BronzeNails:10", 1.25f, 1.1f, 1f);
			Add(config, "Iron Roost", "Swamp", "Iron:10,Guck:5", 1.5f, 1.2f, 1.25f);
			Add(config, "Silver Roost", "Mountains", "Silver:10,WolfPelt:4", 1.75f, 1.35f, 1.25f);
			Add(config, "Black Metal Roost", "Plains", "BlackMetal:10,LinenThread:10", 2f, 1.5f, 1.25f);
			Add(config, "Eitr Roost", "Mistlands", "BlackCore:2,Eitr:10,Carapace:10", 2.5f, 1.75f, 1.5f);
			Add(config, "Flametal Roost", "Ashlands", "FlametalNew:10,CelestialFeather:3", 3f, 2f, 1.5f);
			Add(config, "Deep North Roost", "Deep North", "FlametalNew:30,MoltenCore:2", 4f, 2.5f, 1.5f);
		}

		private static void Add(ConfigFile config, string name, string biome, string cost, float range, float speed, float sight)
		{
			int count = s_tiers.Count;
			string text = $"Tier {count} - {name}";
			s_tiers.Add(new RoostTier
			{
				Index = count,
				Name = name,
				Biome = biome,
				Cost = config.Bind<string>(text, "UpgradeCost", cost, Plugin.Synced((count == 0) ? "Not used: this is the tier you build." : "Items to upgrade to this tier, as PrefabName:Amount, comma-separated.")),
				Range = config.Bind<float>(text, "Range", range, Plugin.Synced("Range multiplier; multiplies with BaseRange and the meal.")),
				Speed = config.Bind<float>(text, "Speed", speed, Plugin.Synced("Speed multiplier; multiplies with the meal.")),
				Sight = config.Bind<float>(text, "Sight", sight, Plugin.Synced("Multiplies RevealRadius and SpotRadius: how wide a strip this raven maps and sees."))
			});
		}

		public static bool SpotsOre(int tier)
		{
			if (Plugin.SpotOres.Value)
			{
				return tier >= OresFromTier.Value;
			}
			return false;
		}

		public static bool SpotsFood(int tier)
		{
			if (Plugin.SpotFood.Value)
			{
				return tier >= FoodFromTier.Value;
			}
			return false;
		}

		public static void ValidateItems()
		{
			if (s_validated || !Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return;
			}
			s_validated = true;
			foreach (RoostTier item in s_tiers.Skip(1))
			{
				List<string> list = Costs.Missing(item.Requirements());
				if (list.Count > 0)
				{
					Plugin.Log.LogWarning((object)(item.Name + ": unknown upgrade item(s) " + string.Join(", ", list) + " - this tier can't be reached until its UpgradeCost is changed in the config."));
				}
			}
		}
	}
	internal class ScoutTrip
	{
		public double SentAt;

		public double ReturnAt;

		public Vector3 From;

		public Vector3 Target;

		public string Sender = "";

		public float Meal = 1f;

		public bool Reported;

		public bool SenderNoMap;

		public int Tier;

		public float Distance => Scouting.DistanceXZ(From, Target);

		public bool IsAway(double now)
		{
			return now < ReturnAt;
		}

		public string Key(ZDOID roost)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return $"{roost}:{SentAt:R}";
		}
	}
	internal class Finding
	{
		public enum Kind
		{
			Dungeon,
			Boss,
			Trader,
			Other,
			Ore,
			Food
		}

		public Kind Type;

		public string Label;

		public Vector3 Position;

		public int Count = 1;
	}
	internal class TripResult
	{
		public string Key;

		public double SentAt;

		public double ReturnAt;

		public Vector3 From;

		public Vector3 Target;

		public float RevealRadius;

		public string Report;

		public bool ApplyMap = true;

		public bool GaveReport;

		public string RoostName = "";

		public string Sender = "";

		public List<Finding> Findings = new List<Finding>();

		public string ReportText;

		public string Guide;
	}
	internal class PendingReport
	{
		public string Text;

		public string Roost;

		public int Day;

		public string Guide = "";
	}
	internal static class Scouting
	{
		private class NameRule
		{
			public readonly Finding.Kind Kind;

			public readonly Dictionary<string, string> Names;

			public NameRule(Finding.Kind kind, string names)
			{
				Kind = kind;
				Names = ParseNames(names);
			}
		}

		private class ObjectRule
		{
			public Finding.Kind Kind;

			public string Label;

			public int MinCount;
		}

		public const string TripKey = "ravenscout_trip";

		public const string ReportKey = "ravenscout_report";

		public const string NameKey = "ravenscout_name";

		public const string PendingKey = "ravenscout_pending";

		public const string LastTextKey = "ravenscout_lasttext";

		public const string LastDayKey = "ravenscout_lastday";

		public const string LastGuideKey = "ravenscout_lastguide";

		public const string SharedKey = "ravenscout_shared";

		public const int SharedHistory = 10;

		private const int PendingVersionMarker = -2;

		public const string DefaultRoostName = "Raven Roost";

		private const int TripVersion = 3;

		private const int ResultVersion = 4;

		private const float WorldRadius = 10000f;

		private static readonly FieldInfo s_objectsBySector = AccessTools.Field(typeof(ZDOMan), "m_objectsBySector");

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

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

		private const int GuideTargets = 8;

		private const float ClusterDistance = 60f;

		public static bool IsActive
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance) && ZDOMan.instance != null)
				{
					return ZRoutedRpc.instance != null;
				}
				return false;
			}
		}

		public static bool IsServer
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		public static double Now => ZNet.instance.GetTimeSeconds();

		public static bool WorldHasNoMap
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZoneSystem.instance))
				{
					return ZoneSystem.instance.GetGlobalKey((GlobalKeys)31);
				}
				return false;
			}
		}

		public static int Day(double time)
		{
			if (!Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				return 0;
			}
			return EnvMan.instance.GetDay(time);
		}

		public static ScoutTrip ReadTrip(ZDO zdo)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//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_0079: 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)
			byte[] array = ((zdo != null) ? zdo.GetByteArray("ravenscout_trip", (byte[])null) : null);
			if (array == null || array.Length == 0)
			{
				return null;
			}
			ZPackage val = new ZPackage(array);
			int num = val.ReadInt();
			if (num < 1 || num > 3)
			{
				Plugin.Log.LogWarning((object)$"Unknown trip version {num}; ignoring.");
				return null;
			}
			ScoutTrip scoutTrip = new ScoutTrip
			{
				SentAt = val.ReadDouble(),
				ReturnAt = val.ReadDouble(),
				From = val.ReadVector3(),
				Target = val.ReadVector3(),
				Sender = val.ReadString(),
				Meal = val.ReadSingle(),
				Reported = val.ReadBool()
			};
			if (num >= 2)
			{
				scoutTrip.SenderNoMap = val.ReadBool();
			}
			if (num >= 3)
			{
				scoutTrip.Tier = val.ReadInt();
			}
			return scoutTrip;
		}

		public static void WriteTrip(ZDO zdo, ScoutTrip trip)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0027: 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)
			ZPackage val = new ZPackage();
			val.Write(3);
			val.Write(trip.SentAt);
			val.Write(trip.ReturnAt);
			val.Write(trip.From);
			val.Write(trip.Target);
			val.Write(trip.Sender ?? "");
			val.Write(trip.Meal);
			val.Write(trip.Reported);
			val.Write(trip.SenderNoMap);
			val.Write(trip.Tier);
			zdo.Set("ravenscout_trip", val.GetArray());
		}

		public static string RoostName(ZDO zdo)
		{
			string text = ((zdo != null) ? zdo.GetString("ravenscout_name", "") : null);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return "Raven Roost";
		}

		public static List<PendingReport> ReadPending(ZDO zdo)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			List<PendingReport> list = new List<PendingReport>();
			byte[] array = ((zdo != null) ? zdo.GetByteArray("ravenscout_pending", (byte[])null) : null);
			if (array == null || array.Length == 0)
			{
				return list;
			}
			ZPackage val = new ZPackage(array);
			int num = val.ReadInt();
			bool flag = num == -2;
			int num2 = (flag ? val.ReadInt() : num);
			for (int i = 0; i < num2; i++)
			{
				PendingReport pendingReport = new PendingReport
				{
					Text = val.ReadString(),
					Roost = val.ReadString(),
					Day = val.ReadInt()
				};
				if (flag)
				{
					pendingReport.Guide = val.ReadString();
				}
				list.Add(pendingReport);
			}
			return list;
		}

		public static void WritePending(ZDO zdo, List<PendingReport> list)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(-2);
			val.Write(list.Count);
			foreach (PendingReport item in list)
			{
				val.Write(item.Text ?? "");
				val.Write(item.Roost ?? "");
				val.Write(item.Day);
				val.Write(item.Guide ?? "");
			}
			zdo.Set("ravenscout_pending", val.GetArray());
		}

		public static List<byte[]> ReadShared(ZDO zdo)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			List<byte[]> list = new List<byte[]>();
			byte[] array = ((zdo != null) ? zdo.GetByteArray("ravenscout_shared", (byte[])null) : null);
			if (array == null || array.Length == 0)
			{
				return list;
			}
			ZPackage val = new ZPackage(array);
			int num = val.ReadInt();
			for (int i = 0; i < num; i++)
			{
				list.Add(val.ReadByteArray());
			}
			return list;
		}

		public static void AddShared(ZDO zdo, byte[] result)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			List<byte[]> list = ReadShared(zdo);
			list.Add(result);
			if (list.Count > 10)
			{
				list.RemoveRange(0, list.Count - 10);
			}
			ZPackage val = new ZPackage();
			val.Write(list.Count);
			foreach (byte[] item in list)
			{
				val.Write(item);
			}
			zdo.Set("ravenscout_shared", val.GetArray());
		}

		public static List<ZDO> GetAllRoostZdos()
		{
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("piece_ravenroost", list, ref num))
			{
			}
			list.RemoveAll((ZDO z) => z == null || !z.IsValid());
			return list;
		}

		public static float DistanceXZ(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			return Vector2.Distance(new Vector2(a.x, a.z), new Vector2(b.x, b.z));
		}

		public static float RangeFor(float meal)
		{
			return Mathf.Max(Plugin.MinDistance.Value, Plugin.BaseRange.Value * meal);
		}

		public static float TripSeconds(float distance, float meal)
		{
			return Mathf.Max(Plugin.MinTripSeconds.Value, 2f * distance / 100f * Plugin.SecondsPer100m.Value / Mathf.Max(0.05f, meal));
		}

		public static Vector3 TargetPoint(Vector3 from, float degrees, float distance)
		{
			//IL_0020: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			//IL_0095: 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_0065: 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_0070: 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_0048: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			float num = degrees * ((float)Math.PI / 180f);
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(Mathf.Sin(num), 0f, Mathf.Cos(num));
			Vector3 val2 = from + val * distance;
			for (int i = 0; i < 400; i++)
			{
				Vector2 val3 = new Vector2(val2.x, val2.z);
				if (!(((Vector2)(ref val3)).magnitude > 10000f) || !(distance > 0f))
				{
					break;
				}
				distance = Mathf.Max(0f, distance - 50f);
				val2 = from + val * distance;
			}
			val2.y = from.y;
			return val2;
		}

		public static string CompassName(float degrees)
		{
			string[] obj = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" };
			int num = Mathf.RoundToInt(Mathf.Repeat(degrees, 360f) / 45f) % 8;
			return obj[num];
		}

		public static float Heading(Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			return Mathf.Repeat(Mathf.Atan2(to.x - from.x, to.z - from.z) * 57.29578f, 360f);
		}

		public static string FormatDuration(double seconds)
		{
			if (seconds < 0.0)
			{
				seconds = 0.0;
			}
			int num = Mathf.CeilToInt((float)seconds);
			if (num < 3600)
			{
				return $"{num / 60}:{num % 60:00}";
			}
			return $"{num / 3600}h {num % 3600 / 60:00}m";
		}

		public static string FormatDistance(float metres)
		{
			if (!(metres >= 1000f))
			{
				return $"{Mathf.RoundToInt(metres)} m";
			}
			return $"{metres / 1000f:0.0} km";
		}

		private static float DistanceToRoute(Vector3 p, Vector3 a, Vector3 b)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0030: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_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_0079: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(p.x - a.x, p.z - a.z);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(b.x - a.x, b.z - a.z);
			float num = ((((Vector2)(ref val2)).sqrMagnitude < 0.01f) ? 0f : Mathf.Clamp01(Vector2.Dot(val, val2) / ((Vector2)(ref val2)).sqrMagnitude));
			Vector2 val3 = val - val2 * num;
			return ((Vector2)(ref val3)).magnitude;
		}

		public static TripResult Survey(ScoutTrip trip, string key)
		{
			//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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			TripResult tripResult = new TripResult
			{
				Key = key,
				SentAt = trip.SentAt,
				ReturnAt = trip.ReturnAt,
				From = trip.From,
				Target = trip.Target,
				RevealRadius = Plugin.RevealRadius.Value * RoostTiers.Get(trip.Tier).SightMultiplier
			};
			float radius = Mathf.Max(0f, Plugin.SpotRadius.Value * RoostTiers.Get(trip.Tier).SightMultiplier);
			FindPlaces(trip, radius, tripResult.Findings);
			bool wildLand = FindObjects(trip, radius, tripResult.Findings);
			tripResult.Report = Report(trip, tripResult.Findings, wildLand);
			tripResult.ReportText = ScoutWords.Write(trip, tripResult.Findings, wildLand);
			tripResult.Guide = GuideFor(tripResult.Findings);
			return tripResult;
		}

		public static string GuideFor(List<Finding> findings)
		{
			Finding.Kind[] order = new Finding.Kind[6]
			{
				Finding.Kind.Boss,
				Finding.Kind.Dungeon,
				Finding.Kind.Trader,
				Finding.Kind.Other,
				Finding.Kind.Ore,
				Finding.Kind.Food
			};
			IEnumerable<Finding> source = findings.OrderBy((Finding f) => Array.IndexOf(order, f.Type)).Take(8);
			return string.Join(";", source.Select((Finding f) => (f.Label ?? "").Replace("|", "/").Replace(";", ",") + "|" + f.Position.x.ToString("0.#", CultureInfo.InvariantCulture) + "|" + f.Position.z.ToString("0.#", CultureInfo.InvariantCulture)));
		}

		private static void FindPlaces(ScoutTrip trip, float radius, List<Finding> findings)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: 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)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			List<NameRule> list = new List<NameRule>();
			if (Plugin.SpotDungeons.Value)
			{
				list.Add(new NameRule(Finding.Kind.Dungeon, Plugin.DungeonNames.Value));
			}
			if (Plugin.SpotBosses.Value)
			{
				list.Add(new NameRule(Finding.Kind.Boss, Plugin.BossNames.Value));
			}
			if (Plugin.SpotTraders.Value)
			{
				list.Add(new NameRule(Finding.Kind.Trader, Plugin.TraderNames.Value));
			}
			if (Plugin.SpotOther.Value)
			{
				list.Add(new NameRule(Finding.Kind.Other, Plugin.OtherNames.Value));
			}
			if (list.Count == 0 || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>();
			foreach (LocationInstance location in ZoneSystem.instance.GetLocationList())
			{
				if (location.m_location != null && !(DistanceToRoute(location.m_position, trip.From, trip.Target) > radius))
				{
					string text = location.m_location.m_prefab.Name ?? location.m_location.m_prefabName ?? "";
					if (!Match(list, text, out var kind, out var label))
					{
						hashSet.Add(text);
						continue;
					}
					findings.Add(new Finding
					{
						Type = kind,
						Label = label,
						Position = location.m_position
					});
				}
			}
			List<string> list2 = (from n in hashSet
				where s_reportedUnknownLocations.Add(n)
				orderby n
				select n).ToList();
			if (list2.Count > 0)
			{
				Plugin.Log.LogInfo((object)("Raven flew past places it doesn't pin: " + string.Join(", "