Decompiled source of ValynAxeClues v0.4.1

plugins/ValynAxeClues.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyVersion("0.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 ValynMods.AxeClues
{
	[BepInPlugin("valyn.mods.axeclues", "Valyn Axe Clues", "0.4.1")]
	public sealed class AxeCluesPlugin : BaseUnityPlugin
	{
		private struct Candidate
		{
			public string Key;

			public Vector3 Position;

			public float Distance;

			public string Head;

			public string Landmark;

			public bool WaterCrossing;

			public bool Valid;
		}

		internal static AxeCluesPlugin Instance;

		private static readonly FieldInfo RuneText = AccessTools.Field(typeof(RuneStone), "m_text");

		private static readonly FieldInfo CurrentContainer = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");

		private static readonly FieldInfo KnownTexts = AccessTools.Field(typeof(Player), "m_knownTexts");

		private static readonly FieldInfo TextsDialogField = AccessTools.Field(typeof(InventoryGui), "m_textsDialog");

		private static readonly FieldInfo JournalTexts = AccessTools.Field(typeof(TextsDialog), "m_texts");

		private static readonly MethodInfo SelectedText = AccessTools.Method(typeof(TextsDialog), "GetSelectedText", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetupTexts = AccessTools.Method(typeof(TextsDialog), "Setup", (Type[])null, (Type[])null);

		private static readonly MethodInfo CurrentDay = AccessTools.Method(typeof(EnvMan), "GetCurrentDay", (Type[])null, (Type[])null);

		private const string JournalKey = "Scratched notes";

		private const string RuneClueMarker = "\n\nScratches beneath the old words:\n";

		private const string OldRuneClueMarker = "\n\nAnother hand has scratched a trail beneath the old words:\n";

		private List<LocationInstance> locations = new List<LocationInstance>();

		private readonly HashSet<string> checkedSites = new HashSet<string>();

		private readonly HashSet<string> readLids = new HashSet<string>();

		private ConfigEntry<float> clueRange;

		private ConfigEntry<bool> avoidWaterCrossings;

		private ConfigEntry<string> checkedWorldSites;

		private ConfigEntry<string> readWorldLids;

		private ConfigFile worldConfig;

		private string worldProgressDirectory;

		private Harmony harmony;

		private long worldUid = long.MinValue;

		private float nextEmptyCheck;

		private float nearEmptySince;

		private string nearEmptyKey;

		private string pendingRuneClue;

		private string pendingRuneSource;

		private object randomRuneText;

		private string originalRandomRuneText;

		private List<Candidate> pendingTrail;

		private readonly List<Candidate> trail = new List<Candidate>();

		private readonly LineRenderer[] arrows = (LineRenderer[])(object)new LineRenderer[3];

		private Material arrowMaterial;

		private float trailStarted = -1f;

		private float trailDelay = 0.5f;

		private int trailLastIndex = -1;

		private bool trailWarning;

		private bool journalWarning;

		private bool fontWarning;

		private MethodInfo guiButton;

		private Player migratedPlayer;

		private void Awake()
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			Instance = this;
			clueRange = ((BaseUnityPlugin)this).Config.Bind<float>("Clues", "Maximum clue distance", 1800f, "Only describe candidate ruins within this straight-line distance in game units.");
			avoidWaterCrossings = ((BaseUnityPlugin)this).Config.Bind<bool>("Clues", "Avoid water crossings", true, "Only describe ruins connected to the clue source by an approximate dry-land route. Disable to use the old nearest-site behavior.");
			worldProgressDirectory = Path.Combine(Paths.ConfigPath, "ValynAxeCluesWorlds");
			try
			{
				MigrateLegacyProgress();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not move existing axe clue progress; mod stopped to preserve it: " + ex));
				Instance = null;
				return;
			}
			if (RuneText == null || CurrentContainer == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"RuneStone or InventoryGui fields changed; axe clues cannot start on this game version.");
				return;
			}
			harmony = new Harmony("valyn.mods.axeclues");
			harmony.PatchAll(typeof(AxeCluesPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Valyn Axe Clues 0.4.1 ready. Read a Meadows runestone or open a Meadows chest to discover clues.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			ClearArrows();
			if ((Object)(object)arrowMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)arrowMaterial);
			}
			Instance = null;
		}

		private void Update()
		{
			if (Instance != this)
			{
				return;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				StopTrail();
				return;
			}
			EnsureWorld();
			MigrateNotes(Player.m_localPlayer);
			UpdateTrail();
			if (!(Time.time < nextEmptyCheck) && Ready())
			{
				nextEmptyCheck = Time.time + 2f;
				CheckEmptyRuin();
			}
		}

		private void EnsureWorld()
		{
			long worldUID = ZNet.instance.GetWorldUID();
			if (worldUID != worldUid)
			{
				worldUid = worldUID;
				StopTrail();
				nearEmptyKey = null;
				checkedSites.Clear();
				readLids.Clear();
				worldConfig = OpenWorldConfig(worldUID);
				checkedWorldSites = worldConfig.Bind<string>("Progress", "Checked sites", "", "Visited axe-head ruins. Clear to reset search progress for this world.");
				readWorldLids = worldConfig.Bind<string>("Progress", "Read chest notes", "", "Chests that already revealed a clue. Clear to repeat their notes for testing.");
				string[] array = checkedWorldSites.Value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string item in array)
				{
					checkedSites.Add(item);
				}
				string[] array2 = readWorldLids.Value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string item2 in array2)
				{
					readLids.Add(item2);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("World " + worldUID + ": " + checkedSites.Count + " checked ruins, " + readLids.Count + " previously read chest notes."));
			}
		}

		private string WorldProgressPath(long uid)
		{
			return Path.Combine(worldProgressDirectory, "world-" + uid.ToString(CultureInfo.InvariantCulture) + ".dat");
		}

		private ConfigFile OpenWorldConfig(long uid)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Directory.CreateDirectory(worldProgressDirectory);
			return new ConfigFile(WorldProgressPath(uid), false);
		}

		private static bool LegacyWorldEntry(ConfigDefinition definition, out long uid, out string section)
		{
			uid = 0L;
			section = null;
			if (!definition.Section.StartsWith("World ", StringComparison.Ordinal))
			{
				return false;
			}
			string text = definition.Section.Substring("World ".Length);
			bool flag = text.EndsWith(" rune scratches", StringComparison.Ordinal);
			if (flag)
			{
				text = text.Substring(0, text.Length - " rune scratches".Length);
			}
			if (!long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out uid))
			{
				return false;
			}
			if (flag && definition.Key.StartsWith("rune:", StringComparison.Ordinal))
			{
				section = "Rune scratches";
			}
			else if (!flag && (definition.Key == "Checked sites" || definition.Key == "Read chest notes"))
			{
				section = "Progress";
			}
			return section != null;
		}

		private void MigrateLegacyProgress()
		{
			HashSet<ConfigDefinition> hashSet = new HashSet<ConfigDefinition>(((BaseUnityPlugin)this).Config.Keys);
			if (!(AccessTools.Field(typeof(ConfigFile), "<OrphanedEntries>k__BackingField")?.GetValue(((BaseUnityPlugin)this).Config) is Dictionary<ConfigDefinition, string> dictionary))
			{
				throw new InvalidOperationException("Cannot read older world entries from BepInEx config.");
			}
			foreach (ConfigDefinition key in dictionary.Keys)
			{
				hashSet.Add(key);
			}
			Dictionary<long, List<ConfigDefinition>> dictionary2 = new Dictionary<long, List<ConfigDefinition>>();
			foreach (ConfigDefinition item in hashSet)
			{
				if (LegacyWorldEntry(item, out var uid, out var _))
				{
					if (!dictionary2.TryGetValue(uid, out var value))
					{
						dictionary2.Add(uid, value = new List<ConfigDefinition>());
					}
					value.Add(item);
				}
			}
			if (dictionary2.Count == 0)
			{
				return;
			}
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			try
			{
				foreach (KeyValuePair<long, List<ConfigDefinition>> item2 in dictionary2)
				{
					ConfigFile val = OpenWorldConfig(item2.Key);
					long uid2;
					foreach (ConfigDefinition item3 in item2.Value)
					{
						LegacyWorldEntry(item3, out uid2, out var section2);
						string value2 = ((BaseUnityPlugin)this).Config.Bind<string>(item3.Section, item3.Key, "", "Previous axe clue progress").Value;
						ConfigEntry<string> val2 = val.Bind<string>(section2, item3.Key, "", "World-specific axe clue progress");
						if (string.IsNullOrEmpty(val2.Value) && !string.IsNullOrEmpty(value2))
						{
							val2.Value = value2;
						}
					}
					val.Save();
					foreach (ConfigDefinition item4 in item2.Value)
					{
						((BaseUnityPlugin)this).Config.Remove(item4);
					}
					ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
					string[] obj = new string[5]
					{
						"Moved ",
						item2.Value.Count.ToString(),
						" progress entries for world ",
						null,
						null
					};
					uid2 = item2.Key;
					obj[3] = uid2.ToString();
					obj[4] = " out of the main config.";
					logger.LogInfo((object)string.Concat(obj));
				}
				((BaseUnityPlugin)this).Config.Save();
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		internal static long BeforeWorldDeleted(string name, object source)
		{
			AxeCluesPlugin instance = Instance;
			if (instance == null)
			{
				return long.MinValue;
			}
			try
			{
				foreach (World world in SaveSystem.GetWorldList())
				{
					if (world.m_worldName == name && object.Equals(AccessTools.Field(typeof(World), "m_fileSource")?.GetValue(world), source))
					{
						return world.m_uid;
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)("Cannot identify deleted world: " + ex.Message));
			}
			return long.MinValue;
		}

		internal static void AfterWorldDeleted(long uid)
		{
			AxeCluesPlugin instance = Instance;
			if (instance == null || uid == long.MinValue)
			{
				return;
			}
			try
			{
				foreach (World world in SaveSystem.GetWorldList())
				{
					if (world.m_uid == uid)
					{
						return;
					}
				}
				string path = instance.WorldProgressPath(uid);
				if (File.Exists(path))
				{
					File.Delete(path);
				}
				((BaseUnityPlugin)instance).Logger.LogInfo((object)("Removed axe clue progress for deleted world " + uid + "."));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)("Could not clean deleted world progress: " + ex.Message));
			}
		}

		private bool Ready()
		{
			return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.LocationsGenerated;
		}

		private bool IsMeadows(Vector3 point)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			return WorldGenerator.instance != null && (int)WorldGenerator.instance.GetBiome(point) == 1;
		}

		private static bool Carries(string prefab)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == prefab)
				{
					return true;
				}
			}
			return false;
		}

		private Candidate FindCandidate(bool curious, Vector3 origin, LandReachability land = null, bool preferLand = true)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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_0152: 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)
			string text = (curious ? "WoodHouse6" : "WoodHouse2");
			Candidate candidate = default(Candidate);
			Candidate candidate2 = default(Candidate);
			float num = float.MaxValue;
			float num2 = float.MaxValue;
			locations.Clear();
			if (!ZoneSystem.instance.FindLocations(text, ref locations))
			{
				return candidate;
			}
			foreach (LocationInstance location in locations)
			{
				Vector3 position = location.m_position;
				string text2 = Key(text, position);
				if (checkedSites.Contains(text2))
				{
					continue;
				}
				float num3 = HorizontalDistance(origin, position);
				if (num3 > Mathf.Max(100f, clueRange.Value) || (num3 >= num && num3 >= num2))
				{
					continue;
				}
				bool flag = land?.Reaches(position) ?? true;
				float num4 = BroadWaterLength(origin, position);
				bool flag2 = !flag || num4 >= 48f;
				if (!(flag2 ? (num3 >= num2) : (num3 >= num)))
				{
					Candidate candidate3 = new Candidate
					{
						Key = text2,
						Position = position,
						Distance = num3,
						Valid = true,
						WaterCrossing = flag2,
						Head = (curious ? "Curious" : "Mysterious"),
						Landmark = (curious ? "a tall broken timber house" : "a low abandoned timber house")
					};
					if (flag2)
					{
						num2 = num3;
						candidate2 = candidate3;
					}
					else
					{
						num = num3;
						candidate = candidate3;
					}
				}
			}
			if (!preferLand && candidate2.Valid && (!candidate.Valid || candidate2.Distance < candidate.Distance))
			{
				return candidate2;
			}
			return candidate.Valid ? candidate : candidate2;
		}

		private string ComposeClue(Vector3 origin, out List<Candidate> targets)
		{
			//IL_0059: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			targets = new List<Candidate>();
			if (!Ready())
			{
				return null;
			}
			bool flag = Carries("AxeHead1");
			bool flag2 = Carries("AxeHead2");
			if (flag && flag2)
			{
				return null;
			}
			List<string> list = new List<string>();
			LandReachability land = (avoidWaterCrossings.Value ? new LandReachability(origin, Mathf.Max(100f, clueRange.Value)) : null);
			if (!flag2)
			{
				AddLine(curious: false, origin, list, targets, land);
			}
			if (!flag)
			{
				AddLine(curious: true, origin, list, targets, land);
			}
			return (list.Count == 0) ? null : string.Join("\n", list);
		}

		private void AddLine(bool curious, Vector3 origin, List<string> lines, List<Candidate> targets, LandReachability land)
		{
			//IL_0003: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			Candidate item = FindCandidate(curious, origin, land, avoidWaterCrossings.Value);
			if (item.Valid)
			{
				targets.Add(item);
				int num = Mathf.Max(100, Mathf.RoundToInt(item.Distance / 100f) * 100);
				lines.Add("\"" + num + " paces " + Direction(origin, item.Position) + " — " + (curious ? "tall timbers" : "low timbers") + (item.WaterCrossing ? ", across the water" : "") + "\"");
				((BaseUnityPlugin)this).Logger.LogInfo((object)(item.Head + " clue: source " + Point(origin) + ", target " + item.Key + " at " + Point(item.Position) + ", " + Mathf.RoundToInt(item.Distance) + " paces; longest direct water stretch " + Mathf.RoundToInt(BroadWaterLength(origin, item.Position)) + " paces; " + (item.WaterCrossing ? "water crossing indicated" : "land route indicated") + "; world UID " + worldUid + "."));
			}
		}

		private static float BroadWaterLength(Vector3 from, Vector3 to)
		{
			//IL_001b: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (WorldGenerator.instance == null)
			{
				return 0f;
			}
			float num = HorizontalDistance(from, to);
			int num2 = Mathf.Max(1, Mathf.CeilToInt(num / 8f));
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 1; i < num2; i++)
			{
				float num5 = (float)i / (float)num2;
				float num6 = Mathf.Lerp(from.x, to.x, num5);
				float num7 = Mathf.Lerp(from.z, to.z, num5);
				if (WorldGenerator.instance.GetHeight(num6, num7) * 200f < 30.3f)
				{
					num4 += num / (float)num2;
					num3 = Mathf.Max(num3, num4);
				}
				else
				{
					num4 = 0f;
				}
			}
			return num3;
		}

		internal static void BeforeRune(RuneStone stone, Humanoid user, bool hold, out string original)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			original = null;
			AxeCluesPlugin instance = Instance;
			if (instance == null || hold || (Object)(object)user != (Object)(object)Player.m_localPlayer || !instance.Ready() || !instance.IsMeadows(((Component)stone).transform.position))
			{
				return;
			}
			instance.EnsureWorld();
			instance.MigrateNotes(Player.m_localPlayer);
			string text = Key("rune", ((Component)stone).transform.position);
			ConfigEntry<string> val = instance.worldConfig.Bind<string>("Rune scratches", text, "", "Clue fixed when this runestone was first read. Clear only to reroll this stone.");
			List<Candidate> targets;
			string text2 = DecodeRune(val.Value, out targets);
			if (text2 == null)
			{
				text2 = instance.ComposeClue(((Component)stone).transform.position, out targets);
				if (!string.IsNullOrEmpty(text2))
				{
					val.Value = EncodeRune(text2, targets);
					instance.worldConfig.Save();
				}
			}
			if (!string.IsNullOrEmpty(text2))
			{
				instance.pendingTrail = targets;
				instance.pendingRuneSource = text;
				instance.pendingRuneClue = "\n\nScratches beneath the old words:\n" + text2;
				original = (string)RuneText.GetValue(stone);
				RuneText.SetValue(stone, original + "\n\n<size=75%>Scratches beneath the old words:\n" + text2 + "</size>");
			}
		}

		internal static void AfterRune(RuneStone stone, string original)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (original != null)
			{
				RuneText.SetValue(stone, original);
			}
			AxeCluesPlugin instance = Instance;
			if (instance != null)
			{
				if (original != null && instance.pendingTrail != null)
				{
					instance.QueueTrail(instance.pendingTrail, chest: false);
					instance.AppendNote(Player.m_localPlayer, "Runestone " + Point(((Component)stone).transform.position), instance.pendingRuneSource, instance.pendingRuneClue.Substring("\n\nScratches beneath the old words:\n".Length));
				}
				if (instance.randomRuneText != null)
				{
					AccessTools.Field(instance.randomRuneText.GetType(), "m_text")?.SetValue(instance.randomRuneText, instance.originalRandomRuneText);
					instance.randomRuneText = null;
					instance.originalRandomRuneText = null;
				}
				instance.pendingRuneClue = null;
				instance.pendingRuneSource = null;
				instance.pendingTrail = null;
			}
		}

		internal static void AddRandomRuneClue(object randomText)
		{
			AxeCluesPlugin instance = Instance;
			if (instance != null && randomText != null && instance.pendingRuneClue != null)
			{
				FieldInfo fieldInfo = AccessTools.Field(randomText.GetType(), "m_text");
				if (!(fieldInfo == null))
				{
					instance.randomRuneText = randomText;
					instance.originalRandomRuneText = (string)fieldInfo.GetValue(randomText);
					fieldInfo.SetValue(randomText, instance.originalRandomRuneText + "\n\n<size=75%>Scratches beneath the old words:\n" + instance.pendingRuneClue.Substring("\n\nScratches beneath the old words:\n".Length) + "</size>");
				}
			}
		}

		private static string EncodeRune(string clue, List<Candidate> targets)
		{
			List<string> list = new List<string> { Convert.ToBase64String(Encoding.UTF8.GetBytes(clue)) };
			foreach (Candidate target in targets)
			{
				list.Add(target.Head + "," + target.Position.x.ToString("R", CultureInfo.InvariantCulture) + "," + target.Position.z.ToString("R", CultureInfo.InvariantCulture));
			}
			return string.Join("|", list);
		}

		private static string DecodeRune(string saved, out List<Candidate> targets)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			targets = new List<Candidate>();
			if (string.IsNullOrEmpty(saved))
			{
				return null;
			}
			try
			{
				string[] array = saved.Split('|');
				string result = Encoding.UTF8.GetString(Convert.FromBase64String(array[0]));
				for (int i = 1; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(',');
					targets.Add(new Candidate
					{
						Head = array2[0],
						Valid = true,
						Position = new Vector3(float.Parse(array2[1], CultureInfo.InvariantCulture), 0f, float.Parse(array2[2], CultureInfo.InvariantCulture))
					});
				}
				return result;
			}
			catch
			{
				return null;
			}
		}

		internal static void KeepRuneOutOfJournal(ref string text)
		{
			if (Instance?.pendingRuneClue != null && text != null)
			{
				int num = text.IndexOf("\n\n<size=75%>Scratches beneath the old words:", StringComparison.Ordinal);
				if (num >= 0)
				{
					text = text.Substring(0, num);
				}
			}
		}

		internal static void UsePlainScratchFont(TextViewer viewer)
		{
			AxeCluesPlugin instance = Instance;
			if (instance?.pendingRuneClue == null)
			{
				return;
			}
			try
			{
				object obj = AccessTools.Field(typeof(TextViewer), "m_text")?.GetValue(viewer);
				object obj2 = AccessTools.Field(typeof(TextViewer), "m_runeText")?.GetValue(viewer);
				object obj3 = obj?.GetType().GetProperty("font")?.GetValue(obj);
				if (obj2 == null)
				{
					return;
				}
				Object val = (Object)((obj3 is Object) ? obj3 : null);
				if (val == null)
				{
					return;
				}
				Type type = obj.GetType().Assembly.GetType("TMPro.MaterialReferenceManager");
				AccessTools.Method(type, "AddFontAsset", (Type[])null, (Type[])null)?.Invoke(null, new object[1] { obj3 });
				PropertyInfo property = obj2.GetType().GetProperty("text");
				if (property?.GetValue(obj2) is string text)
				{
					int num = text.IndexOf("<size=75%>Scratches beneath the old words:", StringComparison.Ordinal);
					if (num >= 0)
					{
						property.SetValue(obj2, text.Substring(0, num) + "<font=\"" + val.name + "\">" + text.Substring(num).Replace("</size>", "</size></font>"));
					}
				}
			}
			catch (Exception ex)
			{
				if (!instance.fontWarning)
				{
					instance.fontWarning = true;
					((BaseUnityPlugin)instance).Logger.LogWarning((object)("Plain scratch font unavailable: " + ex.Message));
				}
			}
		}

		internal static Container BeforeInventoryHide(InventoryGui gui)
		{
			return (Container)((Instance == null) ? null : /*isinst with value type is only supported in some contexts*/);
		}

		internal static void AfterInventoryHide(Container chest)
		{
			//IL_0042: 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_0068: 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_0076: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			AxeCluesPlugin instance = Instance;
			if (instance == null || (Object)(object)chest == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			instance.EnsureWorld();
			if (!instance.Ready() || !instance.IsMeadows(((Component)chest).transform.position))
			{
				return;
			}
			Vector3 position = ((Component)chest).transform.position;
			instance.MarkNearbyRuins(position);
			string text = Key("lid", position);
			if (!instance.readLids.Contains(text))
			{
				List<Candidate> targets;
				string text2 = instance.ComposeClue(position, out targets);
				if (!string.IsNullOrEmpty(text2))
				{
					instance.readLids.Add(text);
					instance.readWorldLids.Value = string.Join(";", instance.readLids);
					instance.worldConfig.Save();
					instance.QueueTrail(targets, chest: true);
					string text3 = "Scratches inside the chest lid:\n" + text2;
					instance.AppendNote(Player.m_localPlayer, "Chest " + Point(position), text, text2);
					((Character)Player.m_localPlayer).Message((MessageType)2, text3, 0, (Sprite)null, false);
				}
			}
		}

		private void MarkNearbyRuins(Vector3 point)
		{
			//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_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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			string[] array = new string[2] { "WoodHouse2", "WoodHouse6" };
			foreach (string text in array)
			{
				locations.Clear();
				ZoneSystem.instance.FindLocations(text, ref locations);
				foreach (LocationInstance location in locations)
				{
					if (HorizontalDistance(point, location.m_position) < 20f)
					{
						flag |= checkedSites.Add(Key(text, location.m_position));
					}
				}
			}
			if (flag)
			{
				SaveChecked();
			}
		}

		private void CheckEmptyRuin()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			Candidate candidate = default(Candidate);
			bool[] array = new bool[2] { false, true };
			foreach (bool curious in array)
			{
				Candidate candidate2 = FindCandidate(curious, position, null, preferLand: false);
				if (candidate2.Valid && candidate2.Distance < 12f && (!candidate.Valid || candidate2.Distance < candidate.Distance))
				{
					candidate = candidate2;
				}
			}
			if (!candidate.Valid)
			{
				nearEmptyKey = null;
			}
			else if (candidate.Key != nearEmptyKey)
			{
				nearEmptyKey = candidate.Key;
				nearEmptySince = Time.time;
			}
			else
			{
				if (Time.time - nearEmptySince < 8f)
				{
					return;
				}
				Container[] array2 = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
				foreach (Container val in array2)
				{
					if (HorizontalDistance(((Component)val).transform.position, candidate.Position) < 18f)
					{
						return;
					}
				}
				checkedSites.Add(candidate.Key);
				SaveChecked();
				nearEmptyKey = null;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("No chest found at " + candidate.Key + " at " + Point(candidate.Position) + "; marked checked."));
				((Character)Player.m_localPlayer).Message((MessageType)2, "Only empty timbers remain here. Perhaps another carved trail will point onward.", 0, (Sprite)null, false);
			}
		}

		private void SaveChecked()
		{
			checkedWorldSites.Value = string.Join(";", checkedSites);
			worldConfig.Save();
		}

		private void QueueTrail(List<Candidate> targets, bool chest)
		{
			StopTrail();
			trail.AddRange(targets);
			trailDelay = (chest ? 5f : 0.5f);
			trailStarted = -1f;
			trailLastIndex = -1;
		}

		private void StopTrail()
		{
			trail.Clear();
			trailStarted = -1f;
			trailLastIndex = -1;
			ClearArrows();
		}

		private void ClearArrows()
		{
			for (int i = 0; i < arrows.Length; i++)
			{
				if ((Object)(object)arrows[i] != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)arrows[i]).gameObject);
				}
				arrows[i] = null;
			}
		}

		private void UpdateTrail()
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: 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_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: 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_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: 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)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			if (trail.Count == 0)
			{
				return;
			}
			if ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible())
			{
				ClearArrows();
				return;
			}
			if (trailStarted < 0f)
			{
				trailStarted = Time.time + trailDelay;
			}
			float num = Time.time - trailStarted;
			if (num < 0f)
			{
				return;
			}
			int num2 = Mathf.FloorToInt(num / 7f);
			if (num2 >= trail.Count)
			{
				StopTrail();
			}
			else
			{
				if (!EnsureArrows())
				{
					return;
				}
				if (num2 != trailLastIndex)
				{
					trailLastIndex = num2;
					((Character)Player.m_localPlayer).Message((MessageType)2, "A faint trail traces scratch " + (num2 + 1) + ".", 0, (Sprite)null, false);
				}
				Vector3 position = ((Component)Player.m_localPlayer).transform.position;
				Vector3 val = trail[num2].Position - position;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
				{
					ClearArrows();
					return;
				}
				((Vector3)(ref val)).Normalize();
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(0f - val.z, 0f, val.x);
				float num3 = 7f - num % 7f;
				float num4 = Mathf.Clamp01(num3 / 1.4f);
				Color val3 = ((num2 == 0) ? new Color(0.25f, 0.95f, 0.9f, num4) : new Color(1f, 0.75f, 0.32f, num4));
				for (int i = 0; i < arrows.Length; i++)
				{
					LineRenderer val4 = arrows[i];
					Color startColor = (val4.endColor = val3);
					val4.startColor = startColor;
					Vector3 val6 = position + val * (4f + (float)i * 3.5f);
					Vector3 val7 = val6 - val * 1.15f;
					val4.SetPosition(0, Ground(val7 + val2 * 0.65f));
					val4.SetPosition(1, Ground(val6));
					val4.SetPosition(2, Ground(val7 - val2 * 0.65f));
				}
			}
		}

		private Vector3 Ground(Vector3 point)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			if (ZoneSystem.instance.GetGroundHeight(point, ref num))
			{
				point.y = num + 0.24f;
			}
			else
			{
				point.y = ((Component)Player.m_localPlayer).transform.position.y + 0.12f;
			}
			return point;
		}

		private bool EnsureArrows()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			if ((Object)(object)arrows[0] != (Object)null)
			{
				return true;
			}
			Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color");
			if ((Object)(object)val == (Object)null)
			{
				if (!trailWarning)
				{
					trailWarning = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)"No shader available for the clue trail.");
				}
				StopTrail();
				return false;
			}
			if ((Object)(object)arrowMaterial == (Object)null)
			{
				arrowMaterial = new Material(val);
			}
			for (int i = 0; i < arrows.Length; i++)
			{
				GameObject val2 = new GameObject("Axe clue fleeting trail");
				val2.layer = 2;
				LineRenderer val3 = val2.AddComponent<LineRenderer>();
				((Renderer)val3).sharedMaterial = arrowMaterial;
				val3.useWorldSpace = true;
				val3.positionCount = 3;
				float startWidth = (val3.endWidth = 0.12f);
				val3.startWidth = startWidth;
				arrows[i] = val3;
			}
			return true;
		}

		private void AppendNote(Player player, string source, string id, string clue, bool old = false)
		{
			if (!(KnownTexts?.GetValue(player) is Dictionary<string, string> dictionary) || string.IsNullOrEmpty(clue))
			{
				return;
			}
			string value;
			string text = (dictionary.TryGetValue("Scratched notes", out value) ? value : "");
			string text2 = "{" + worldUid + ":" + id + "}";
			if (!text.Contains(text2))
			{
				int num = (((Object)(object)EnvMan.instance != (Object)null && CurrentDay != null) ? ((int)CurrentDay.Invoke(EnvMan.instance, null)) : 0);
				float num2 = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetDayFraction() : 0f);
				int num3 = Mathf.FloorToInt(Mathf.Repeat(num2, 1f) * 1440f);
				string text3 = (old ? "Earlier" : ("Day " + num + " · " + (num3 / 60).ToString("00") + ":" + (num3 % 60).ToString("00")));
				string text4 = "<size=72%><color=#BEB6A5>" + text3 + " · " + source + "</color></size>\n" + clue.Trim() + "<size=1%><color=#00000000>" + text2 + "</color></size>";
				string text5 = ((text.Length == 0) ? text4 : (text + "\n\n" + text4));
				if (text.Length == 0)
				{
					player.AddKnownText("Scratched notes", text5);
				}
				else
				{
					dictionary["Scratched notes"] = text5;
				}
			}
		}

		private void MigrateNotes(Player player)
		{
			if ((Object)(object)player == (Object)(object)migratedPlayer || !(KnownTexts?.GetValue(player) is Dictionary<string, string> dictionary))
			{
				return;
			}
			migratedPlayer = player;
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, string> item in dictionary)
			{
				if (item.Key.StartsWith("Trail note ", StringComparison.Ordinal) || RuneMarkerIndex(item.Value) >= 0)
				{
					list.Add(item.Key);
				}
			}
			foreach (string item2 in list)
			{
				string text = dictionary[item2];
				if (item2.StartsWith("Trail note ", StringComparison.Ordinal))
				{
					string text2 = text;
					int num = text2.IndexOf('\n');
					if (num >= 0)
					{
						text2 = text2.Substring(num + 1);
					}
					AppendNote(player, "Chest " + item2.Substring("Trail note ".Length), "legacy:" + item2, text2, old: true);
					dictionary.Remove(item2);
					continue;
				}
				int num2 = RuneMarkerIndex(text);
				string text3 = text.Substring(num2).Trim();
				int num3 = text3.IndexOf('\n');
				if (num3 >= 0)
				{
					text3 = text3.Substring(num3 + 1).Trim();
				}
				AppendNote(player, "Runestone · " + item2, "legacy:" + item2, text3, old: true);
				dictionary[item2] = text.Substring(0, num2);
			}
			if (list.Count > 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Moved " + list.Count + " older clues into Scratched notes."));
			}
		}

		private void OnGUI()
		{
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible())
			{
				return;
			}
			object? obj = TextsDialogField?.GetValue(InventoryGui.instance);
			TextsDialog val = (TextsDialog)((obj is TextsDialog) ? obj : null);
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || JournalTexts == null || SelectedText == null || !(JournalTexts.GetValue(val) is IList { Count: not 0 } list))
			{
				return;
			}
			int num = (int)SelectedText.Invoke(val, null);
			if (num < 0 || num >= list.Count)
			{
				return;
			}
			Type type = list[num].GetType();
			string text = AccessTools.Field(type, "m_topic")?.GetValue(list[num]) as string;
			if (text != "Scratched notes" || !(KnownTexts?.GetValue(Player.m_localPlayer) is Dictionary<string, string> dictionary) || !dictionary.ContainsKey("Scratched notes"))
			{
				return;
			}
			if (guiButton == null)
			{
				guiButton = Type.GetType("UnityEngine.GUI, UnityEngine.IMGUIModule")?.GetMethod("Button", new Type[2]
				{
					typeof(Rect),
					typeof(string)
				});
				if (guiButton == null)
				{
					if (!journalWarning)
					{
						journalWarning = true;
						((BaseUnityPlugin)this).Logger.LogWarning((object)"Journal delete button unavailable: Unity IMGUI was not found.");
					}
					return;
				}
			}
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width * 0.76f, (float)Screen.height * 0.84f, 210f, 32f);
			if ((bool)guiButton.Invoke(null, new object[2] { val2, "Clear scratched notes" }))
			{
				dictionary.Remove("Scratched notes");
				SetupTexts?.Invoke(val, new object[1] { Player.m_localPlayer });
				((Character)Player.m_localPlayer).Message((MessageType)2, "Scratched notes cleared.", 0, (Sprite)null, false);
			}
		}

		private static int RuneMarkerIndex(string content)
		{
			int num = content.IndexOf("\n\nScratches beneath the old words:\n", StringComparison.Ordinal);
			return (num >= 0) ? num : content.IndexOf("\n\nAnother hand has scratched a trail beneath the old words:\n", StringComparison.Ordinal);
		}

		private static string Key(string prefix, Vector3 p)
		{
			//IL_0015: 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)
			return prefix + ":" + Mathf.RoundToInt(p.x) + ":" + Mathf.RoundToInt(p.z);
		}

		private static string Point(Vector3 p)
		{
			//IL_0011: 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)
			return "(" + Mathf.RoundToInt(p.x) + ", " + Mathf.RoundToInt(p.z) + ")";
		}

		private static float HorizontalDistance(Vector3 a, Vector3 b)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		private static string Direction(Vector3 from, Vector3 to)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			string[] array = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" };
			float num = Mathf.Atan2(to.x - from.x, to.z - from.z) * 57.29578f;
			return array[Mathf.RoundToInt((num + 360f) / 45f) % 8];
		}
	}
	internal sealed class LandReachability
	{
		private const float Step = 24f;

		private const int MaxSamples = 30000;

		private readonly Vector3 origin;

		private readonly float maxRange;

		private readonly Dictionary<long, bool> dry = new Dictionary<long, bool>();

		private readonly HashSet<long> connected = new HashSet<long>();

		private bool built;

		internal LandReachability(Vector3 origin, float maxRange)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			this.origin = origin;
			this.maxRange = Mathf.Min(4000f, maxRange + 180f);
		}

		internal bool Reaches(Vector3 target)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if (!built)
			{
				Build();
			}
			if (WorldGenerator.instance.GetHeight(target.x, target.z) * 200f < 30.3f)
			{
				return false;
			}
			int num = Mathf.RoundToInt((target.x - origin.x) / 24f);
			int num2 = Mathf.RoundToInt((target.z - origin.z) / 24f);
			for (int i = num - 1; i <= num + 1; i++)
			{
				for (int j = num2 - 1; j <= num2 + 1; j++)
				{
					if (!connected.Contains(Key(i, j)))
					{
						continue;
					}
					Vector3 val = Point(i, j);
					if (!(HorizontalDistance(val, target) > 27.599998f))
					{
						Vector3 val2 = (val + target) * 0.5f;
						if (WorldGenerator.instance.GetHeight(val2.x, val2.z) * 200f >= 30.3f)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private void Build()
		{
			built = true;
			if (WorldGenerator.instance == null || !Dry(0, 0))
			{
				return;
			}
			Queue<long> queue = new Queue<long>();
			long item = Key(0, 0);
			connected.Add(item);
			queue.Enqueue(item);
			int num = Mathf.CeilToInt(maxRange / 24f);
			while (queue.Count > 0 && dry.Count < 30000)
			{
				long num2 = queue.Dequeue();
				int num3 = (int)(num2 >> 32);
				int num4 = (int)num2;
				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						if (i == 0 && j == 0)
						{
							continue;
						}
						int num5 = num3 + i;
						int num6 = num4 + j;
						if (num5 * num5 + num6 * num6 <= num * num)
						{
							long item2 = Key(num5, num6);
							if (!connected.Contains(item2) && Dry(num5, num6) && (i == 0 || j == 0 || (Dry(num3 + i, num4) && Dry(num3, num4 + j))))
							{
								connected.Add(item2);
								queue.Enqueue(item2);
							}
						}
					}
				}
			}
		}

		private bool Dry(int x, int z)
		{
			//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_002e: 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)
			long key = Key(x, z);
			if (dry.TryGetValue(key, out var value))
			{
				return value;
			}
			Vector3 val = Point(x, z);
			value = WorldGenerator.instance.GetHeight(val.x, val.z) * 200f >= 30.3f;
			dry.Add(key, value);
			return value;
		}

		private Vector3 Point(int x, int z)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(origin.x + (float)x * 24f, 0f, origin.z + (float)z * 24f);
		}

		private static long Key(int x, int z)
		{
			return ((long)x << 32) | (uint)z;
		}

		private static float HorizontalDistance(Vector3 a, Vector3 b)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}
	}
	[HarmonyPatch(typeof(RuneStone), "Interact", new Type[]
	{
		typeof(Humanoid),
		typeof(bool),
		typeof(bool)
	})]
	internal static class RuneStoneCluePatch
	{
		private static void Prefix(RuneStone __instance, Humanoid character, bool hold, out string __state)
		{
			AxeCluesPlugin.BeforeRune(__instance, character, hold, out __state);
		}

		private static void Postfix(RuneStone __instance, string __state)
		{
			AxeCluesPlugin.AfterRune(__instance, __state);
		}
	}
	[HarmonyPatch(typeof(RuneStone), "GetRandomText")]
	internal static class RandomRuneCluePatch
	{
		private static void Postfix(object __result)
		{
			AxeCluesPlugin.AddRandomRuneClue(__result);
		}
	}
	[HarmonyPatch(typeof(Player), "AddKnownText", new Type[]
	{
		typeof(string),
		typeof(string)
	})]
	internal static class KeepRuneJournalCleanPatch
	{
		private static void Prefix(ref string text)
		{
			AxeCluesPlugin.KeepRuneOutOfJournal(ref text);
		}
	}
	[HarmonyPatch(typeof(TextViewer), "ShowText", new Type[]
	{
		typeof(Style),
		typeof(string),
		typeof(string),
		typeof(bool)
	})]
	internal static class PlainScratchFontPatch
	{
		private static void Postfix(TextViewer __instance)
		{
			AxeCluesPlugin.UsePlainScratchFont(__instance);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	internal static class ChestCluePatch
	{
		private static void Prefix(InventoryGui __instance, out Container __state)
		{
			__state = AxeCluesPlugin.BeforeInventoryHide(__instance);
		}

		private static void Postfix(Container __state)
		{
			AxeCluesPlugin.AfterInventoryHide(__state);
		}
	}
	[HarmonyPatch(typeof(World), "RemoveWorld")]
	internal static class WorldProgressCleanupPatch
	{
		private static void Prefix(object[] __args, out long __state)
		{
			__state = AxeCluesPlugin.BeforeWorldDeleted(__args[0] as string, __args[1]);
		}

		private static void Postfix(long __state)
		{
			AxeCluesPlugin.AfterWorldDeleted(__state);
		}
	}
}