plugins/Lur/Lur.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Ezomic.Core;
using Ezomic.Shared;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("Thijssen Software")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Robbin Thijssen")]
[assembly: AssemblyDescription("Sound a horn in one of Hildir's dungeons and its mini-boss wakes again.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ed4086fb33547df831bf919c89c899dc9da769d4")]
[assembly: AssemblyProduct("Lur")]
[assembly: AssemblyTitle("Lur")]
[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 Ezomic.Shared
{
	public static class Prefabs
	{
		private sealed class Kept
		{
			internal string Name;

			internal Func<GameObject> Build;

			internal bool Item;

			internal string Tool;

			internal GameObject Prefab;

			internal int Failures;

			internal bool Abandoned;
		}

		private static ManualLogSource _log;

		private static GameObject _holder;

		private static readonly List<Kept> Standing = new List<Kept>();

		private const int MaxFailures = 5;

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

		private static FieldRef<ZNetScene, Dictionary<int, GameObject>> _named;

		private static MethodInfo _updateRegisters;

		public static ManualLogSource Log
		{
			get
			{
				return _log ?? (_log = Logger.CreateLogSource("Prefabs"));
			}
			set
			{
				_log = value;
			}
		}

		public static Transform Holder
		{
			get
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Expected O, but got Unknown
				if ((Object)(object)_holder == (Object)null)
				{
					_holder = new GameObject(Log.SourceName + "Prefabs");
					_holder.SetActive(false);
					Object.DontDestroyOnLoad((Object)(object)_holder);
				}
				return _holder.transform;
			}
		}

		public static void Keep(string name, Func<GameObject> build, bool item = false, string buildTool = null)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}
			if (build == null)
			{
				throw new ArgumentNullException("build");
			}
			foreach (Kept item2 in Standing)
			{
				if (!(item2.Name != name))
				{
					item2.Build = build;
					item2.Item = item;
					item2.Tool = buildTool;
					item2.Failures = 0;
					item2.Abandoned = false;
					return;
				}
			}
			Standing.Add(new Kept
			{
				Name = name,
				Build = build,
				Item = item,
				Tool = buildTool
			});
			Log.LogInfo((object)("Keeping " + name + " registered."));
		}

		public static void Drop(string name)
		{
			Standing.RemoveAll((Kept k) => k.Name == name);
		}

		public static void Tick()
		{
			if (Standing.Count == 0)
			{
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				for (int i = 0; i < Standing.Count; i++)
				{
					Apply(Standing[i], instance);
				}
			}
		}

		private static void Apply(Kept kept, ZNetScene scene)
		{
			if (!kept.Abandoned && (!((Object)(object)kept.Prefab == (Object)null) || TryBuild(kept)))
			{
				if ((Object)(object)scene.GetPrefab(kept.Name) == (Object)null)
				{
					Register(kept.Prefab);
				}
				if (kept.Item)
				{
					RegisterItem(kept.Prefab);
				}
				if (!string.IsNullOrEmpty(kept.Tool))
				{
					AddToTool(kept.Prefab, kept.Tool);
				}
			}
		}

		private static bool TryBuild(Kept kept)
		{
			GameObject val = null;
			try
			{
				val = kept.Build();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Building " + kept.Name + " failed: " + ex.Message));
			}
			if ((Object)(object)val != (Object)null)
			{
				kept.Prefab = val;
				kept.Failures = 0;
				if (((Object)val).name != kept.Name)
				{
					((Object)val).name = kept.Name;
				}
				return true;
			}
			if (++kept.Failures < 5)
			{
				return false;
			}
			kept.Abandoned = true;
			Log.LogError((object)(kept.Name + " could not be built after " + 5 + " attempts and will not be retried. Anything already built with it in a world is untouched; it simply will not be placeable this session."));
			return false;
		}

		public static bool Known(string name)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				return (Object)(object)ZNetScene.instance.GetPrefab(name) != (Object)null;
			}
			return false;
		}

		public static GameObject Clone(GameObject source, string name)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			bool forceDisableInit = ZNetView.m_forceDisableInit;
			ZNetView.m_forceDisableInit = true;
			GameObject val;
			try
			{
				val = Object.Instantiate<GameObject>(source, Holder);
			}
			finally
			{
				ZNetView.m_forceDisableInit = forceDisableInit;
			}
			((Object)val).name = name;
			return val;
		}

		public static GameObject Donor(string commaSeparated, out string chosen)
		{
			chosen = null;
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			string[] array = (commaSeparated ?? "").Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0)
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(text);
					if (!((Object)(object)prefab == (Object)null))
					{
						chosen = text;
						return prefab;
					}
				}
			}
			return null;
		}

		public static bool Register(GameObject prefab)
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)prefab == (Object)null)
			{
				return false;
			}
			if ((Object)(object)instance.GetPrefab(((Object)prefab).name) != (Object)null)
			{
				return true;
			}
			if (!instance.m_prefabs.Contains(prefab))
			{
				instance.m_prefabs.Add(prefab);
			}
			try
			{
				NamedPrefabs(instance)[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab;
			}
			catch (Exception ex)
			{
				ComplainOnce("scene:" + ((Object)prefab).name, "Could not register " + ((Object)prefab).name + " with ZNetScene: " + ex.Message);
				return false;
			}
			Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ZNetScene."));
			return true;
		}

		public static bool RegisterItem(GameObject prefab)
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)prefab == (Object)null)
			{
				return false;
			}
			if (instance.m_items == null || instance.m_items.Count == 0)
			{
				return false;
			}
			if ((Object)(object)instance.GetItemPrefab(((Object)prefab).name) != (Object)null)
			{
				return true;
			}
			if (!instance.m_items.Contains(prefab))
			{
				instance.m_items.Add(prefab);
			}
			try
			{
				UpdateRegisters(instance);
			}
			catch (Exception ex)
			{
				ComplainOnce("db:" + ((Object)prefab).name, "Could not refresh ObjectDB for " + ((Object)prefab).name + ": " + ex.Message);
				return false;
			}
			Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ObjectDB."));
			return true;
		}

		public static PieceTable ToolPieces(string toolPrefab)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(toolPrefab))
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(toolPrefab);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null)
			{
				return null;
			}
			PieceTable buildPieces = val.m_itemData.m_shared.m_buildPieces;
			if (!((Object)(object)buildPieces != (Object)null) || buildPieces.m_pieces == null)
			{
				return null;
			}
			return buildPieces;
		}

		public static bool InTool(GameObject prefab, string toolPrefab)
		{
			PieceTable val = ToolPieces(toolPrefab);
			if ((Object)(object)val != (Object)null && (Object)(object)prefab != (Object)null)
			{
				return val.m_pieces.Contains(prefab);
			}
			return false;
		}

		public static bool AddToTool(GameObject prefab, string toolPrefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			PieceTable val = ToolPieces(toolPrefab);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (val.m_pieces.Contains(prefab))
			{
				return true;
			}
			val.m_pieces.Add(prefab);
			Log.LogInfo((object)(((Object)prefab).name + " added to the " + toolPrefab + "."));
			return true;
		}

		private static void ComplainOnce(string key, string message)
		{
			if (Complained.Add(key))
			{
				Log.LogError((object)message);
			}
		}

		private static Dictionary<int, GameObject> NamedPrefabs(ZNetScene scene)
		{
			if (_named == null)
			{
				_named = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs");
			}
			return _named.Invoke(scene);
		}

		private static void UpdateRegisters(ObjectDB db)
		{
			if (_updateRegisters == null)
			{
				_updateRegisters = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null);
			}
			if (_updateRegisters == null)
			{
				throw new MissingMethodException("ObjectDB.UpdateRegisters");
			}
			_updateRegisters.Invoke(db, null);
		}
	}
}
namespace Lur
{
	internal static class Dungeons
	{
		private const Theme Trio = (Theme)3584;

		internal unsafe static DungeonGenerator Containing(Vector3 point)
		{
			//IL_0017: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			DungeonGenerator val = null;
			foreach (DungeonGenerator item in Live())
			{
				if (Enabled(item.m_themes) && Inside(item, point))
				{
					if ((Object)(object)val != (Object)null)
					{
						ManualLogSource log = LurPlugin.Log;
						Vector3 val2 = point;
						log.LogWarning((object)("Two dungeons overlap at " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString() + " - refusing to guess which."));
						return null;
					}
					val = item;
				}
			}
			return val;
		}

		internal static IEnumerable<DungeonGenerator> Live()
		{
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] roots = ((Scene)(ref activeScene)).GetRootGameObjects();
			DungeonGenerator val2 = default(DungeonGenerator);
			ZNetView val3 = default(ZNetView);
			foreach (GameObject val in roots)
			{
				if (!((Object)(object)val == (Object)null) && val.TryGetComponent<DungeonGenerator>(ref val2) && !((Object)(object)val2 == (Object)null) && val.TryGetComponent<ZNetView>(ref val3) && !((Object)(object)val3 == (Object)null) && val3.IsValid())
				{
					yield return val2;
				}
			}
		}

		internal static bool Enabled(Theme themes)
		{
			//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_000b: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			if ((themes & 0xE00) == 0)
			{
				return false;
			}
			if ((themes & 0x200) != 0)
			{
				return LurConfig.WakeCrypt.Value;
			}
			if ((themes & 0x400) != 0)
			{
				return LurConfig.WakeCave.Value;
			}
			if ((themes & 0x800) != 0)
			{
				return LurConfig.WakeTower.Value;
			}
			return false;
		}

		internal static string Describe(DungeonGenerator dg)
		{
			if ((Object)(object)dg == (Object)null)
			{
				return "<none>";
			}
			return Utils.GetPrefabName(((Component)dg).gameObject) + " [" + ((object)Unsafe.As<Theme, Theme>(ref dg.m_themes)/*cast due to .constrained prefix*/).ToString() + "]";
		}

		internal static bool Inside(DungeonGenerator dg, Vector3 point)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//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_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_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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)dg == (Object)null)
			{
				return false;
			}
			float num = Mathf.Max(0f, LurConfig.RoomPadding.Value);
			Room[] componentsInChildren = ((Component)dg).GetComponentsInChildren<Room>();
			foreach (Room val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 val2 = Quaternion.Inverse(((Component)val).transform.rotation) * (point - ((Component)val).transform.position);
					Vector3 val3 = Vector3Int.op_Implicit(val.m_size) * 0.5f;
					if (Mathf.Abs(val2.x) <= val3.x + num && Mathf.Abs(val2.y) <= val3.y + num && Mathf.Abs(val2.z) <= val3.z + num)
					{
						return true;
					}
				}
			}
			if (!LurConfig.UseLocationRadiusFallback.Value)
			{
				return false;
			}
			Location location = Location.GetLocation(((Component)dg).transform.position, true);
			if ((Object)(object)location == (Object)null)
			{
				return false;
			}
			return location.IsInside(point, 0f, false);
		}

		internal static bool Ready(DungeonGenerator dg)
		{
			if ((Object)(object)dg == (Object)null)
			{
				return false;
			}
			return ((Component)dg).GetComponentsInChildren<Room>().Length != 0;
		}

		internal static List<CreatureSpawner> Spawners(DungeonGenerator dg)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			List<CreatureSpawner> list = new List<CreatureSpawner>();
			if ((Object)(object)dg == (Object)null)
			{
				return list;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			CreatureSpawner val2 = default(CreatureSpawner);
			ZNetView val3 = default(ZNetView);
			foreach (GameObject val in rootGameObjects)
			{
				if (!((Object)(object)val == (Object)null) && val.TryGetComponent<CreatureSpawner>(ref val2) && !((Object)(object)val2 == (Object)null) && val.TryGetComponent<ZNetView>(ref val3) && !((Object)(object)val3 == (Object)null) && val3.IsValid() && Inside(dg, val.transform.position))
				{
					list.Add(val2);
				}
			}
			return list;
		}

		internal static List<CreatureSpawner> BossSpawners(DungeonGenerator dg)
		{
			List<CreatureSpawner> list = new List<CreatureSpawner>();
			foreach (CreatureSpawner item in Spawners(dg))
			{
				if (IsBoss(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		internal static CreatureSpawner Boss(DungeonGenerator dg)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			List<CreatureSpawner> list = new List<CreatureSpawner>();
			foreach (CreatureSpawner item in Spawners(dg))
			{
				if (IsBoss(item))
				{
					list.Add(item);
				}
			}
			if (list.Count == 0)
			{
				return null;
			}
			if (list.Count == 1)
			{
				return list[0];
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return list[0];
			}
			CreatureSpawner result = list[0];
			float num = float.MaxValue;
			foreach (CreatureSpawner item2 in list)
			{
				float num2 = Vector3.Distance(((Component)localPlayer).transform.position, ((Component)item2).transform.position);
				if (!(num2 >= num))
				{
					num = num2;
					result = item2;
				}
			}
			return result;
		}

		internal static bool IsBoss(CreatureSpawner spawner)
		{
			if ((Object)(object)spawner == (Object)null)
			{
				return false;
			}
			if ((Object)(object)spawner.m_creaturePrefab == (Object)null)
			{
				return false;
			}
			Character val = default(Character);
			if (!spawner.m_creaturePrefab.TryGetComponent<Character>(ref val))
			{
				return false;
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			string defeatSetGlobalKey = val.m_defeatSetGlobalKey;
			if (string.IsNullOrEmpty(defeatSetGlobalKey))
			{
				return false;
			}
			if (val.m_boss)
			{
				return true;
			}
			return !VanillaKey(defeatSetGlobalKey);
		}

		private static bool VanillaKey(string key)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GlobalKeys result;
				return Enum.TryParse<GlobalKeys>(key, ignoreCase: true, out result) && Enum.IsDefined(typeof(GlobalKeys), result);
			}
			catch
			{
				return false;
			}
		}

		internal static List<CreatureSpawner> Groupmates(CreatureSpawner boss, List<CreatureSpawner> candidates)
		{
			//IL_0071: 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)
			List<CreatureSpawner> list = new List<CreatureSpawner>();
			if ((Object)(object)boss == (Object)null || candidates == null)
			{
				return list;
			}
			if (boss.m_spawnGroupRadius <= 0f || boss.m_maxGroupSpawned < 1)
			{
				return list;
			}
			foreach (CreatureSpawner candidate in candidates)
			{
				if (!((Object)(object)candidate == (Object)null) && !((Object)(object)candidate == (Object)(object)boss) && candidate.m_spawnGroupID == boss.m_spawnGroupID)
				{
					float num = boss.m_spawnGroupRadius + candidate.m_spawnGroupRadius;
					if (!(Vector3.Distance(((Component)boss).transform.position, ((Component)candidate).transform.position) > num))
					{
						list.Add(candidate);
					}
				}
			}
			return list;
		}

		internal static bool HoldsTombstone(DungeonGenerator dg)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			TombStone val2 = default(TombStone);
			foreach (GameObject val in rootGameObjects)
			{
				if (!((Object)(object)val == (Object)null) && val.TryGetComponent<TombStone>(ref val2) && !((Object)(object)val2 == (Object)null) && Inside(dg, val.transform.position))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class Icons
	{
		public static Sprite Load(string fileName, string label)
		{
			//IL_0069: 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)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(fileName))
			{
				return null;
			}
			string path = Path.Combine(Path.GetDirectoryName(typeof(Icons).Assembly.Location), fileName);
			if (!File.Exists(path))
			{
				LurPlugin.LogOnce("No " + fileName + " beside the dll - " + label + " will use the donor's icon, which is someone else's picture.");
				return null;
			}
			try
			{
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				if (!LoadPng(val, File.ReadAllBytes(path)))
				{
					return null;
				}
				((Object)val).name = label + "_icon";
				((Object)val).hideFlags = (HideFlags)61;
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			}
			catch (Exception ex)
			{
				LurPlugin.Log.LogError((object)("Could not read " + fileName + ": " + ex.Message));
				return null;
			}
		}

		public static string For(string modelFile)
		{
			if (string.IsNullOrEmpty(modelFile))
			{
				return null;
			}
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(modelFile);
			if (!string.IsNullOrEmpty(fileNameWithoutExtension))
			{
				return fileNameWithoutExtension + "_icon.png";
			}
			return null;
		}

		private static bool LoadPng(Texture2D texture, byte[] data)
		{
			Type type = AccessTools.TypeByName("UnityEngine.ImageConversion");
			if (type == null)
			{
				LurPlugin.LogOnce("UnityEngine.ImageConversion is missing - cannot read icons.");
				return false;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, (Type[])null) ?? AccessTools.Method(type, "LoadImage", new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo == null)
			{
				LurPlugin.LogOnce("No LoadImage overload found on UnityEngine.ImageConversion.");
				return false;
			}
			object[] parameters = ((methodInfo.GetParameters().Length != 3) ? new object[2] { texture, data } : new object[3] { texture, data, false });
			return (bool)methodInfo.Invoke(null, parameters);
		}
	}
	internal static class LurConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> WakeCrypt;

		internal static ConfigEntry<bool> WakeCave;

		internal static ConfigEntry<bool> WakeTower;

		internal static ConfigEntry<float> CooldownDays;

		internal static ConfigEntry<float> RoomPadding;

		internal static ConfigEntry<float> WatchSeconds;

		internal static ConfigEntry<bool> UseLocationRadiusFallback;

		internal static ConfigEntry<int> Price;

		internal static ConfigEntry<int> Stack;

		internal static ConfigEntry<string> SoldAfterKey;

		internal static ConfigEntry<string> ItemName;

		internal static ConfigEntry<string> ItemDonor;

		internal static ConfigEntry<string> SoundEffectPrefab;

		internal static ConfigEntry<bool> Diagnose;

		internal static ConfigEntry<bool> Verbose;

		internal static void Bind(ConfigFile cfg)
		{
			Enabled = cfg.Bind<bool>("Lur", "Enabled", true, "Off leaves the plugin loaded and changing nothing. The horn still exists in any inventory that holds one; sounding it simply does nothing.");
			ItemName = cfg.Bind<string>("Lur", "ItemName", "Lur", "The horn's display name. This is the label only. The prefab name is fixed in code and can never change: ZNetScene keys on it and discards the ZDO of anything it cannot resolve, so a rename would delete every horn already sitting in a chest, silently.");
			WakeCrypt = cfg.Bind<bool>("Dungeons", "WakeCrypt", true, "Wake the Smouldering Tomb (Hildir's Black Forest crypt).");
			WakeCave = cfg.Bind<bool>("Dungeons", "WakeCave", true, "Wake the Howling Cavern (Hildir's mountain cave).");
			WakeTower = cfg.Bind<bool>("Dungeons", "WakeTower", true, "Wake the Sealed Tower (Hildir's plains fortress). This one is a ground location rather than a sky interior. It needs no separate code path - Lur deletes nothing and so has no height test anywhere - but it is the one of the three least proven in play.");
			CooldownDays = cfg.Bind<float>("Dungeons", "CooldownDays", 5f, "In-game days before the same dungeon can be woken again. 0 leaves the horn's price as the only cost. Measured on the world clock, so time spent with nobody online does not count.");
			RoomPadding = cfg.Bind<float>("Dungeons", "RoomPadding", 1f, "Metres of slack added to each room's box when deciding what is inside the dungeon. Raise it if a boss refuses to wake and the log shows its spawner just outside.");
			UseLocationRadiusFallback = cfg.Bind<bool>("Dungeons", "UseLocationRadiusFallback", false, "Also count anything inside the Location's own radius as part of the dungeon, not just the generator's rooms. Off by default because it is looser and can reach a spawner standing outside the tower wall. Turn it on only if the diagnostic log shows the tower's boss spawner is not in any room - that is the single case it exists for.");
			WatchSeconds = cfg.Bind<float>("Dungeons", "WatchSeconds", 30f, "How long to wait for something to actually spawn before giving up and putting the spawners back as they were. On a timeout the horn is not consumed. Must comfortably exceed the spawners' own interval.");
			Price = cfg.Bind<int>("Store", "Price", 500, "What Hildir charges, in coins. Her own stock runs a few hundred to somewhat over a thousand, so this sits mid-range. Together with CooldownDays it is the entire cost of a rematch.");
			Stack = cfg.Bind<int>("Store", "Stack", 1, "How many horns one purchase buys. Vanilla clamps this to the item's own max stack size at the till.");
			SoldAfterKey = cfg.Bind<string>("Store", "SoldAfterKey", "", "A global key Hildir requires before she will stock the horn. Empty means always on sale, which is the recommended setting: sounding it already refuses in a dungeon whose boss is still alive. 'bosshildir1' is the value for a host who wants the shop gated as well. An unknown key is not an error - the row simply never appears, so a typo reads as 'she does not sell it'.");
			ItemDonor = cfg.Bind<string>("Lur", "ItemDonor", "SurtlingCore", "Vanilla item to take the horn's machinery from. Its appearance is not used.");
			SoundEffectPrefab = cfg.Bind<string>("Lur", "SoundEffectPrefab", "", "Name of a vanilla effect prefab to play where the horn is sounded. Empty for none. Resolved through ZNetScene; a name that does not exist is logged and skipped, so a rename in a game update costs the noise and nothing else.");
			Diagnose = cfg.Bind<bool>("Diagnostics", "Diagnose", false, "Log a full census of every Hildir dungeon as it loads: its generator, its themes, its rooms, and every spawner near it with an inside-or-outside verdict. This is how the open questions about the Sealed Tower get answered, and it is the first thing to turn on if the horn does nothing.");
			Verbose = cfg.Bind<bool>("Diagnostics", "Verbose", false, "Write what was found and what was changed to BepInEx/LogOutput.log. Note that exceptions land in Player.log instead, not here.");
		}
	}
	internal static class LurItem
	{
		public const string Name = "Lur";

		private const string Mesh = "lur.obj";

		private const string Icon = "lur.png";

		internal static GameObject Build()
		{
			//IL_006b: 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)
			ModelData modelData = ObjMesh.Load(Path.Combine(Path.GetDirectoryName(typeof(LurItem).Assembly.Location), "lur.obj"));
			if (modelData == null)
			{
				LurPlugin.Log.LogError((object)"No lur.obj beside the dll - cannot build Lur. The mod will keep retrying, and Hildir will not stock the horn until it succeeds.");
				return null;
			}
			GameObject val = Donor();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Prefabs.Clone(val, "Lur");
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			val2.transform.localRotation = Quaternion.identity;
			Visual(val2, modelData);
			ItemDrop component = val2.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				LurPlugin.Log.LogError((object)("Donor " + ((Object)val).name + " has no usable ItemDrop."));
				return null;
			}
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = LurConfig.ItemName.Value;
			shared.m_description = "A coiled horn of bone and iron, worn smooth at the mouth.";
			shared.m_itemType = (ItemType)1;
			shared.m_maxStackSize = 10;
			shared.m_weight = 1f;
			shared.m_teleportable = true;
			shared.m_questItem = false;
			Sprite val3 = Icons.Load("lur.png", "Lur");
			if ((Object)(object)val3 != (Object)null)
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { val3 };
			}
			component.m_itemData.m_stack = 1;
			component.m_itemData.m_dropPrefab = val2;
			LurPlugin.Log.LogInfo((object)("Built Lur from " + ((Object)val).name + "."));
			return val2;
		}

		private static GameObject Donor()
		{
			ZNetScene instance = ZNetScene.instance;
			string[] array = new string[3]
			{
				LurConfig.ItemDonor.Value,
				"SurtlingCore",
				"Wood"
			};
			foreach (string text in array)
			{
				if (!string.IsNullOrEmpty(text))
				{
					GameObject prefab = instance.GetPrefab(text);
					if ((Object)(object)prefab != (Object)null)
					{
						return prefab;
					}
					LurPlugin.LogOnce("Item donor '" + text + "' does not exist.");
				}
			}
			return null;
		}

		private static void Visual(GameObject clone, ModelData model)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] componentsInChildren = clone.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
					if ((Object)(object)component != (Object)null)
					{
						Object.DestroyImmediate((Object)(object)component);
					}
					Object.DestroyImmediate((Object)(object)val);
				}
			}
			Light[] componentsInChildren2 = clone.GetComponentsInChildren<Light>(true);
			foreach (Light val2 in componentsInChildren2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			ParticleSystem[] componentsInChildren3 = clone.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val3 in componentsInChildren3)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val3);
				}
			}
			ParticleSystemRenderer[] componentsInChildren4 = clone.GetComponentsInChildren<ParticleSystemRenderer>(true);
			foreach (ParticleSystemRenderer val4 in componentsInChildren4)
			{
				if ((Object)(object)val4 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val4);
				}
			}
			GameObject val5 = new GameObject("lur_visual");
			val5.transform.SetParent(clone.transform, false);
			val5.AddComponent<MeshFilter>().sharedMesh = model.Mesh;
			((Renderer)val5.AddComponent<MeshRenderer>()).sharedMaterials = Skins.Skin(model.Groups);
			Skins.Remap(model.Mesh, model.Groups);
			Ground(clone, model);
		}

		private static void Ground(GameObject clone, ModelData model)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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)
			if (!((Object)(object)clone.GetComponentInChildren<Collider>(true) != (Object)null) && !((Object)(object)model.Mesh == (Object)null))
			{
				Bounds bounds = model.Mesh.bounds;
				BoxCollider obj = clone.AddComponent<BoxCollider>();
				obj.center = ((Bounds)(ref bounds)).center;
				obj.size = ((Bounds)(ref bounds)).size;
				LurPlugin.LogOnce("Donor left no collider on Lur - added one from the mesh bounds so it does not fall through the world.");
			}
		}
	}
	internal static class LurPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		private static bool UseItem(Humanoid __instance, ItemData item, bool fromInventoryGui)
		{
			try
			{
				if (!LurConfig.Enabled.Value)
				{
					return true;
				}
				if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				if (fromInventoryGui)
				{
					return true;
				}
				if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
				{
					return true;
				}
				if (((Object)item.m_dropPrefab).name != "Lur")
				{
					return true;
				}
				Sounding.Sound(Player.m_localPlayer);
				return false;
			}
			catch (Exception ex)
			{
				LurPlugin.Log.LogError((object)("Sounding the horn threw, so it did nothing: " + ex));
				return true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(DungeonGenerator), "Awake")]
		private static void GeneratorAwake(DungeonGenerator __instance)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					((MonoBehaviour)__instance).StartCoroutine(Census(__instance));
				}
			}
			catch (Exception ex)
			{
				LurPlugin.Log.LogError((object)("Dungeon census threw: " + ex));
			}
		}

		private static IEnumerator Census(DungeonGenerator dg)
		{
			yield return (object)new WaitForSeconds(5f);
			if ((Object)(object)dg == (Object)null || (dg.m_themes & 0xE00) == 0)
			{
				yield break;
			}
			Room[] componentsInChildren = ((Component)dg).GetComponentsInChildren<Room>();
			Vector3 position = ((Component)dg).transform.position;
			LurPlugin.Log.LogInfo((object)$"Hildir dungeon: {Utils.GetPrefabName(((Component)dg).gameObject)} themes={dg.m_themes} at {position} interior={Character.InInterior(position)} rooms={componentsInChildren.Length} enabled={Dungeons.Enabled(dg.m_themes)}");
			if (!LurConfig.Diagnose.Value)
			{
				yield break;
			}
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Room val = componentsInChildren[i];
				if (!((Object)(object)val == (Object)null))
				{
					LurPlugin.Log.LogInfo((object)$"  room {i}: {((Object)val).name} size={val.m_size} at {((Component)val).transform.position}");
				}
			}
			List<CreatureSpawner> list = Dungeons.Spawners(dg);
			LurPlugin.Log.LogInfo((object)("  spawners inside: " + list.Count));
			foreach (CreatureSpawner item in list)
			{
				ZNetView component = ((Component)item).GetComponent<ZNetView>();
				ZDO val2 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
				LurPlugin.Log.LogInfo((object)string.Format("    {0} respawn={1} trigger={2} day={3} night={4} req='{5}' block='{6}' group='{7}' connection={8}", Utils.GetPrefabName(((Component)item).gameObject), item.m_respawnTimeMinuts, item.m_triggerDistance, item.m_spawnAtDay, item.m_spawnAtNight, item.m_requiredGlobalKey, item.m_blockingGlobalKey, item.m_spawnGroupID, (val2 != null) ? ((object)val2.GetConnectionType()/*cast due to .constrained prefix*/).ToString() : "<no zdo>"));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
		private static void AvailableItems(Trader __instance, List<TradeItem> __result)
		{
			try
			{
				Store.Offer(__instance, __result);
			}
			catch (Exception ex)
			{
				LurPlugin.Log.LogError((object)("Offering the horn threw, so it is not stocked: " + ex));
			}
		}
	}
	[BepInPlugin("ezomic.valheim.lur", "Lur", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class LurPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ezomic.valheim.lur";

		public const string PluginName = "Lur";

		public const string PluginVersion = "1.0.0";

		public const string PluginAuthor = "Robbin Thijssen";

		private const string CoreGuid = "ezomic.valheim.core";

		internal static ManualLogSource Log;

		internal static bool CorePresent;

		private Harmony _harmony;

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

		private void Awake()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			LurConfig.Bind(((BaseUnityPlugin)this).Config);
			TryRegisterWithCore();
			Prefabs.Log = ((BaseUnityPlugin)this).Logger;
			Prefabs.Keep("Lur", LurItem.Build, item: true);
			_harmony = new Harmony("ezomic.valheim.lur");
			_harmony.PatchAll(typeof(LurPatches));
			Log.LogInfo((object)"Lur 1.0.0 by Robbin Thijssen - ready.");
		}

		private void TryRegisterWithCore()
		{
			CorePresent = Chainloader.PluginInfos.ContainsKey("ezomic.valheim.core");
			if (!CorePresent)
			{
				Log.LogInfo((object)"Core not installed - running standalone, without the version gate.");
			}
			else
			{
				RegisterWithCore();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void RegisterWithCore()
		{
			Suite.Register("ezomic.valheim.lur", "Lur", "1.0.0", ((BaseUnityPlugin)this).Config, (Requirement)0, (Assembly)null);
			Suite.Sync((ConfigEntryBase[])(object)new ConfigEntryBase[11]
			{
				(ConfigEntryBase)LurConfig.Enabled,
				(ConfigEntryBase)LurConfig.WakeCrypt,
				(ConfigEntryBase)LurConfig.WakeCave,
				(ConfigEntryBase)LurConfig.WakeTower,
				(ConfigEntryBase)LurConfig.CooldownDays,
				(ConfigEntryBase)LurConfig.RoomPadding,
				(ConfigEntryBase)LurConfig.WatchSeconds,
				(ConfigEntryBase)LurConfig.UseLocationRadiusFallback,
				(ConfigEntryBase)LurConfig.Price,
				(ConfigEntryBase)LurConfig.Stack,
				(ConfigEntryBase)LurConfig.SoldAfterKey
			});
			Suite.Local((ConfigEntryBase[])(object)new ConfigEntryBase[2]
			{
				(ConfigEntryBase)LurConfig.Diagnose,
				(ConfigEntryBase)LurConfig.Verbose
			});
		}

		private void Update()
		{
			Prefabs.Tick();
		}

		internal static void LogOnce(string message)
		{
			if (Said.Add(message))
			{
				Log.LogWarning((object)message);
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
	internal sealed class ModelData
	{
		public Mesh Mesh;

		public string[] Groups;
	}
	internal static class ObjMesh
	{
		public static ModelData Load(string path)
		{
			if (!File.Exists(path))
			{
				LurPlugin.Log.LogWarning((object)("No model at " + path));
				return null;
			}
			try
			{
				return Parse(File.ReadAllLines(path), Path.GetFileNameWithoutExtension(path));
			}
			catch (Exception ex)
			{
				LurPlugin.Log.LogError((object)("Could not read " + path + ": " + ex.Message));
				return null;
			}
		}

		private static ModelData Parse(string[] lines, string name)
		{
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: 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_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			List<Vector2> list2 = new List<Vector2>();
			List<Vector3> list3 = new List<Vector3>();
			List<Color> list4 = new List<Color>();
			List<string> list5 = new List<string>();
			List<List<int>> list6 = new List<List<int>>();
			Dictionary<string, int> index = new Dictionary<string, int>();
			Dictionary<string, int> lookup = new Dictionary<string, int>();
			List<Vector3> list7 = new List<Vector3>();
			List<Vector2> list8 = new List<Vector2>();
			List<Vector3> list9 = new List<Vector3>();
			List<Color> outShades = new List<Color>();
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			List<int> triangles = Bucket("", list5, list6, index);
			for (int i = 0; i < lines.Length; i++)
			{
				string text = lines[i].Trim();
				if (text.Length == 0 || text[0] == '#')
				{
					continue;
				}
				string[] array = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length < 2)
				{
					continue;
				}
				switch (array[0])
				{
				case "v":
					if (array.Length >= 4)
					{
						list.Add(new Vector3(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture), float.Parse(array[3], invariantCulture)));
						if (array.Length >= 7)
						{
							list4.Add(new Color(float.Parse(array[4], invariantCulture), float.Parse(array[5], invariantCulture), float.Parse(array[6], invariantCulture), 1f));
						}
					}
					break;
				case "vt":
					if (array.Length >= 3)
					{
						list2.Add(new Vector2(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture)));
					}
					break;
				case "vn":
					if (array.Length >= 4)
					{
						list3.Add(new Vector3(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture), float.Parse(array[3], invariantCulture)));
					}
					break;
				case "usemtl":
					triangles = Bucket(array[1].Trim(), list5, list6, index);
					break;
				case "f":
					AddFace(array, list, list2, list3, list4, lookup, list7, list8, list9, outShades, triangles);
					break;
				}
			}
			for (int num = list6.Count - 1; num >= 0; num--)
			{
				if (list6[num].Count == 0)
				{
					list6.RemoveAt(num);
					list5.RemoveAt(num);
				}
			}
			if (list7.Count == 0 || list6.Count == 0)
			{
				LurPlugin.Log.LogError((object)("Model " + name + " has no geometry."));
				return null;
			}
			Mesh val = new Mesh
			{
				name = name
			};
			if (list7.Count > 65535)
			{
				val.indexFormat = (IndexFormat)1;
				LurPlugin.Log.LogInfo((object)(name + " needs 32 bit indices (" + list7.Count + " verts)."));
			}
			val.SetVertices(list7);
			if (list8.Count == list7.Count)
			{
				val.SetUVs(0, list8);
			}
			val.subMeshCount = list6.Count;
			for (int j = 0; j < list6.Count; j++)
			{
				val.SetTriangles(list6[j], j);
			}
			if (list9.Count == list7.Count)
			{
				val.SetNormals(list9);
			}
			else
			{
				val.RecalculateNormals();
			}
			Color[] array2 = (Color[])(object)new Color[list7.Count];
			for (int k = 0; k < array2.Length; k++)
			{
				array2[k] = Color.white;
			}
			val.colors = array2;
			val.RecalculateBounds();
			val.RecalculateTangents();
			int num2 = 0;
			for (int l = 0; l < list6.Count; l++)
			{
				num2 += list6[l].Count;
			}
			LurPlugin.Log.LogInfo((object)string.Format("Loaded {0}: {1} verts, {2} tris, parts [{3}]", name, list7.Count, num2 / 3, string.Join(", ", list5.ToArray())));
			return new ModelData
			{
				Mesh = val,
				Groups = list5.ToArray()
			};
		}

		private static List<int> Bucket(string material, List<string> names, List<List<int>> buckets, Dictionary<string, int> index)
		{
			if (index.TryGetValue(material, out var value))
			{
				return buckets[value];
			}
			index[material] = buckets.Count;
			names.Add(material);
			buckets.Add(new List<int>());
			return buckets[buckets.Count - 1];
		}

		private static void AddFace(string[] parts, List<Vector3> positions, List<Vector2> uvs, List<Vector3> normals, List<Color> shades, Dictionary<string, int> lookup, List<Vector3> outPositions, List<Vector2> outUvs, List<Vector3> outNormals, List<Color> outShades, List<int> triangles)
		{
			//IL_0055: 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_006c: 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_0098: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			List<int> list = new List<int>(parts.Length - 1);
			for (int i = 1; i < parts.Length; i++)
			{
				string text = parts[i];
				if (!lookup.TryGetValue(text, out var value))
				{
					string[] fields = text.Split(new char[1] { '/' });
					int num = Index(fields, 0, positions.Count);
					if (num < 0)
					{
						continue;
					}
					outPositions.Add(positions[num]);
					outShades.Add((num < shades.Count) ? shades[num] : Color.white);
					int num2 = Index(fields, 1, uvs.Count);
					outUvs.Add((num2 >= 0) ? uvs[num2] : Vector2.zero);
					int num3 = Index(fields, 2, normals.Count);
					outNormals.Add((num3 >= 0) ? normals[num3] : Vector3.up);
					value = (lookup[text] = outPositions.Count - 1);
				}
				list.Add(value);
			}
			for (int j = 2; j < list.Count; j++)
			{
				triangles.Add(list[0]);
				triangles.Add(list[j - 1]);
				triangles.Add(list[j]);
			}
		}

		private static int Index(string[] fields, int slot, int count)
		{
			if (slot >= fields.Length)
			{
				return -1;
			}
			string text = fields[slot];
			if (string.IsNullOrEmpty(text))
			{
				return -1;
			}
			if (!int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return -1;
			}
			if (result > 0)
			{
				result--;
			}
			else if (result < 0)
			{
				result = count + result;
			}
			if (result < 0 || result >= count)
			{
				return -1;
			}
			return result;
		}
	}
	internal static class PropIndex
	{
		private static Dictionary<string, GameObject> _index;

		private static readonly string[] Chaff = new string[5] { "destruction", "broken", "lod", "vfx", "sfx" };

		public static GameObject Find(string name)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(name);
				if ((Object)(object)prefab != (Object)null)
				{
					return prefab;
				}
			}
			if (_index == null)
			{
				BuildIndex();
			}
			if (!_index.TryGetValue(name, out var value))
			{
				return null;
			}
			return value;
		}

		private static void BuildIndex()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			_index = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);
			GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.transform.parent != (Object)null || (Object)(object)val.GetComponentInChildren<MeshRenderer>(true) == (Object)null)
				{
					continue;
				}
				Scene scene = val.scene;
				bool flag = ((Scene)(ref scene)).IsValid();
				if (_index.TryGetValue(((Object)val).name, out var value))
				{
					if (flag)
					{
						continue;
					}
					scene = value.scene;
					if (!((Scene)(ref scene)).IsValid())
					{
						continue;
					}
				}
				_index[((Object)val).name] = val;
			}
			LurPlugin.Log.LogInfo((object)("Prop index built: " + _index.Count + " candidates with meshes."));
		}

		public static void Search(string keywords)
		{
			if (string.IsNullOrEmpty(keywords))
			{
				return;
			}
			if (_index == null)
			{
				BuildIndex();
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (string key in _index.Keys)
			{
				hashSet.Add(key);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
				{
					if ((Object)(object)prefab != (Object)null)
					{
						hashSet.Add(((Object)prefab).name);
					}
				}
			}
			string[] array = keywords.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				List<string> list = new List<string>();
				foreach (string item in hashSet)
				{
					if (item.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0)
					{
						continue;
					}
					string text2 = item.ToLowerInvariant();
					string text3 = text.ToLowerInvariant();
					bool flag = false;
					string[] chaff = Chaff;
					foreach (string value in chaff)
					{
						if (text2.Contains(value) && !text3.Contains(value))
						{
							flag = true;
						}
					}
					if (!flag)
					{
						list.Add(item);
					}
				}
				list.Sort();
				LurPlugin.Log.LogInfo((object)("Prefabs matching '" + text + "' (" + list.Count + "): " + string.Join(", ", list.GetRange(0, Math.Min(40, list.Count)).ToArray())));
			}
		}
	}
	internal static class Skins
	{
		private const string GlowGroup = "core";

		private const string Emission = "_EmissionColor";

		private static readonly Dictionary<string, string[]> Donors = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"bark",
				new string[3] { "wood_wall", "wood_beam", "piece_chest_wood" }
			},
			{
				"wood",
				new string[3] { "wood_wall", "wood_beam", "piece_chest_wood" }
			},
			{
				"seed",
				new string[2] { "wood_beam", "wood_wall" }
			},
			{
				"stone",
				new string[3] { "stone_wall_2x1", "piece_stonecutter", "smelter" }
			},
			{
				"bone",
				new string[3] { "BoneFragments", "TrophyDeer", "wood_beam" }
			},
			{
				"iron",
				new string[3] { "Iron", "IronScrap", "stone_wall_2x1" }
			},
			{
				"moss",
				new string[5] { "sapling_carrot", "sapling_turnip", "Bush01", "shrub_2", "piece_beehive" }
			},
			{
				"cap",
				new string[4] { "Pickable_Mushroom", "Pickable_Mushroom_yellow", "Pickable_Mushroom_blue", "sapling_carrot" }
			},
			{
				"bloom",
				new string[2] { "Pickable_Dandelion", "sapling_carrot" }
			},
			{
				"cloth",
				new string[4] { "rug_lox", "rug_deer", "rug_fur", "wood_wall" }
			},
			{
				"meal",
				new string[2] { "BoneFragments", "stone_wall_2x1" }
			},
			{
				"rope",
				new string[2] { "wood_wall", "wood_beam" }
			},
			{
				"bud",
				new string[3] { "Pickable_Thistle", "Pickable_Dandelion", "sapling_carrot" }
			}
		};

		private static readonly Dictionary<string, Material> Cache = new Dictionary<string, Material>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, Rect> Atlas = new Dictionary<string, Rect>(StringComparer.OrdinalIgnoreCase);

		public static void Invalidate()
		{
			Cache.Clear();
			Atlas.Clear();
		}

		public static Material For(string group)
		{
			if (Cache.TryGetValue(group, out var value))
			{
				return value;
			}
			if (group == "core")
			{
				Material val = Pick(group, mustEmit: true);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return Pick(group, mustEmit: false);
		}

		private static Material Pick(string group, bool mustEmit)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			string[] array = DonorsFor(group);
			foreach (string text in array)
			{
				GameObject val = PropIndex.Find(text);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				MeshRenderer[] componentsInChildren = val.GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren)
				{
					Material sharedMaterial = ((Renderer)val2).sharedMaterial;
					if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null) && sharedMaterial.HasProperty("_MainTex") && !((Object)(object)sharedMaterial.GetTexture("_MainTex") == (Object)null) && (!mustEmit || sharedMaterial.HasProperty("_EmissionColor")))
					{
						Cache[group] = sharedMaterial;
						Atlas[group] = UvRegion((Renderer)(object)val2);
						LurPlugin.Log.LogInfo((object)string.Format("'{0}' skinned with {1} from {2} (shader {3}){4}, atlas {5}.", group, ((Object)sharedMaterial).name, text, ((Object)sharedMaterial.shader).name, mustEmit ? " [emissive]" : "", Atlas[group]));
						return sharedMaterial;
					}
				}
			}
			if (mustEmit)
			{
				return null;
			}
			LurPlugin.Log.LogWarning((object)("No material found for group '" + group + "'."));
			Cache[group] = null;
			return null;
		}

		private static string[] DonorsFor(string group)
		{
			if (!Donors.TryGetValue(group, out var value))
			{
				return Donors["wood"];
			}
			return value;
		}

		public static Material[] Skin(string[] groups)
		{
			Material[] array = (Material[])(object)new Material[groups.Length];
			for (int i = 0; i < groups.Length; i++)
			{
				array[i] = For(groups[i]);
			}
			return array;
		}

		private static Rect UvRegion(Renderer renderer)
		{
			//IL_006f: 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_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 0f, 1f, 1f);
			MeshFilter val2 = (((Object)(object)renderer != (Object)null) ? ((Component)renderer).GetComponent<MeshFilter>() : null);
			Mesh val3 = (((Object)(object)val2 != (Object)null) ? val2.sharedMesh : null);
			if ((Object)(object)val3 == (Object)null)
			{
				return val;
			}
			Vector2[] uv;
			int[] triangles;
			try
			{
				if (!val3.isReadable)
				{
					return val;
				}
				uv = val3.uv;
				triangles = val3.triangles;
			}
			catch
			{
				return val;
			}
			if (uv == null || uv.Length == 0 || triangles == null || triangles.Length < 3)
			{
				return val;
			}
			float num = 0f;
			Rect result = val;
			for (int i = 0; i + 2 < triangles.Length; i += 3)
			{
				int num2 = triangles[i];
				int num3 = triangles[i + 1];
				int num4 = triangles[i + 2];
				if (num2 >= uv.Length || num3 >= uv.Length || num4 >= uv.Length)
				{
					continue;
				}
				float num5 = Mathf.Min(uv[num2].x, Mathf.Min(uv[num3].x, uv[num4].x));
				float num6 = Mathf.Max(uv[num2].x, Mathf.Max(uv[num3].x, uv[num4].x));
				float num7 = Mathf.Min(uv[num2].y, Mathf.Min(uv[num3].y, uv[num4].y));
				float num8 = Mathf.Max(uv[num2].y, Mathf.Max(uv[num3].y, uv[num4].y));
				float num9 = num6 - num5;
				float num10 = num8 - num7;
				if (!(num9 <= 0.005f) && !(num10 <= 0.005f) && !(num9 > 1f) && !(num10 > 1f))
				{
					float num11 = num9 * num10;
					if (!(num11 <= num))
					{
						num = num11;
						((Rect)(ref result))..ctor(num5, num7, num9, num10);
					}
				}
			}
			if (!(num > 0f))
			{
				return val;
			}
			return result;
		}

		public static void Remap(Mesh mesh, string[] groups)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)mesh == (Object)null || groups == null)
			{
				return;
			}
			Vector2[] uv = mesh.uv;
			if (uv == null || uv.Length == 0)
			{
				return;
			}
			int num = Mathf.Min(groups.Length, mesh.subMeshCount);
			bool[] array = new bool[uv.Length];
			for (int i = 0; i < num; i++)
			{
				if (!Atlas.TryGetValue(groups[i], out var value) || (((Rect)(ref value)).width >= 0.999f && ((Rect)(ref value)).height >= 0.999f))
				{
					continue;
				}
				int[] triangles = mesh.GetTriangles(i);
				foreach (int num2 in triangles)
				{
					if (num2 >= 0 && num2 < uv.Length && !array[num2])
					{
						array[num2] = true;
						uv[num2] = new Vector2(((Rect)(ref value)).x + Mathf.Clamp01(uv[num2].x) * ((Rect)(ref value)).width, ((Rect)(ref value)).y + Mathf.Clamp01(uv[num2].y) * ((Rect)(ref value)).height);
					}
				}
			}
			mesh.uv = uv;
		}
	}
	internal static class Sounding
	{
		internal struct Cleared
		{
			internal ZDO Zdo;

			internal ConnectionType Type;

			internal ZDOID Target;
		}

		internal static readonly int SoundedKey = StringExtensionMethods.GetStableHashCode("ezomic_lur_sounded");

		internal static bool Sound(Player player)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			Vector3 position = ((Component)player).transform.position;
			DungeonGenerator val = Dungeons.Containing(position);
			if ((Object)(object)val == (Object)null)
			{
				Refuse(player, "Nothing sleeps here.");
				return false;
			}
			if (!Dungeons.Ready(val))
			{
				Refuse(player, "The stone is still settling.");
				return false;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				Refuse(player, "Nothing sleeps here.");
				return false;
			}
			ZDO zDO = component.GetZDO();
			if (zDO == null)
			{
				Refuse(player, "Nothing sleeps here.");
				return false;
			}
			if (!OffCooldown(zDO, player))
			{
				return false;
			}
			if (Dungeons.HoldsTombstone(val))
			{
				Refuse(player, "Someone lies unclaimed here.");
				return false;
			}
			List<Cleared> list = Wake(val, player);
			if (list.Count == 0)
			{
				return false;
			}
			CreatureSpawner val2 = Dungeons.Boss(val);
			GameObject val3 = (((Object)(object)val2 != (Object)null) ? val2.m_creaturePrefab : null);
			ManualLogSource log = LurPlugin.Log;
			string[] obj = new string[11]
			{
				"Sounded in ",
				Dungeons.Describe(val),
				" - re-armed ",
				list.Count.ToString(),
				" spawner(s), boss spawner ",
				((Object)(object)val2 != (Object)null) ? Utils.GetPrefabName(((Component)val2).gameObject) : "<none>",
				" at ",
				null,
				null,
				null,
				null
			};
			object obj2;
			if (!((Object)(object)val2 != (Object)null))
			{
				obj2 = "-";
			}
			else
			{
				Vector3 position2 = ((Component)val2).transform.position;
				obj2 = ((Vector3)(ref position2)).ToString("F1");
			}
			obj[7] = (string)obj2;
			obj[8] = " holding ";
			obj[9] = (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "<none>");
			obj[10] = ", watching.";
			log.LogInfo((object)string.Concat(obj));
			Effect(position);
			Watch watch = ((Component)val).gameObject.AddComponent<Watch>();
			watch.Observe = Observable(Dungeons.BossSpawners(val), Dungeons.Spawners(val));
			watch.Begin(list, zDO, player, ((Object)(object)val3 != (Object)null) ? StringExtensionMethods.GetStableHashCode(((Object)val3).name) : 0);
			return true;
		}

		private static bool OffCooldown(ZDO generator, Player player)
		{
			float num = Mathf.Max(0f, LurConfig.CooldownDays.Value);
			if (num <= 0f)
			{
				return true;
			}
			long num2 = generator.GetLong(SoundedKey, 0L);
			if (num2 == 0L)
			{
				return true;
			}
			long num3 = (long)ZNet.instance.GetTimeSeconds();
			long num4 = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.m_dayLengthSec : 1200);
			long num5 = (long)(num * (float)num4) - (num3 - num2);
			if (num5 <= 0)
			{
				return true;
			}
			long num6 = (num5 + num4 - 1) / num4;
			Refuse(player, (num6 <= 1) ? "This place has not settled. Not long now." : ("This place has not settled. " + num6 + " days yet."));
			return false;
		}

		private static List<Cleared> Wake(DungeonGenerator dg, Player player)
		{
			//IL_01a6: 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_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: 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_0208: Unknown result type (might be due to invalid IL or missing references)
			List<Cleared> list = new List<Cleared>();
			List<CreatureSpawner> list2 = Dungeons.Spawners(dg);
			List<CreatureSpawner> list3 = Dungeons.BossSpawners(dg);
			if ((Object)(object)Dungeons.Boss(dg) == (Object)null)
			{
				LurPlugin.Log.LogWarning((object)(Dungeons.Describe(dg) + ": no boss spawner found among " + list2.Count + " spawner(s). Turn on Diagnose and revisit to see what each of them holds."));
				Refuse(player, "Nothing sleeps here.");
				return list;
			}
			List<CreatureSpawner> list4 = new List<CreatureSpawner>();
			foreach (CreatureSpawner item in list3)
			{
				if (!list4.Contains(item))
				{
					list4.Add(item);
				}
				foreach (CreatureSpawner item2 in Dungeons.Groupmates(item, list2))
				{
					if (!list4.Contains(item2))
					{
						list4.Add(item2);
					}
				}
			}
			string text = "Nothing sleeps here.";
			bool flag = false;
			foreach (CreatureSpawner item3 in list4)
			{
				if (!Clearable(item3, out var refusal))
				{
					text = refusal;
					continue;
				}
				flag = true;
				break;
			}
			if (!flag)
			{
				LurPlugin.Log.LogInfo((object)(Dungeons.Describe(dg) + ": none of " + list4.Count + " boss/group spawner(s) can be cleared - " + text));
				Refuse(player, text);
				return list;
			}
			foreach (CreatureSpawner item4 in list4)
			{
				ZDO val = ZdoOf(item4);
				if (val != null)
				{
					ConnectionType connectionType = val.GetConnectionType();
					ZDOID connectionZDOID = val.GetConnectionZDOID((ConnectionType)3);
					if (Clearable(item4, out var _))
					{
						val.SetOwner(ZDOMan.GetSessionID());
						val.Set(ZDOVars.s_aliveTime, 0L);
						val.SetConnection((ConnectionType)0, ZDOID.None);
						list.Add(new Cleared
						{
							Zdo = val,
							Type = connectionType,
							Target = connectionZDOID
						});
					}
				}
			}
			LurPlugin.Log.LogInfo((object)$"{Dungeons.Describe(dg)}: {list2.Count} spawner(s) present, {list3.Count} hold a boss, {list4.Count} in the group, cleared {list.Count}.");
			if (list.Count == 0)
			{
				Refuse(player, "Nothing sleeps here.");
			}
			return list;
		}

		private static bool Clearable(CreatureSpawner spawner, out string refusal)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			refusal = "Nothing sleeps here.";
			ZDO val = ZdoOf(spawner);
			if (val == null)
			{
				return false;
			}
			if ((int)val.GetConnectionType() == 0)
			{
				refusal = "It is already awake.";
				return false;
			}
			ZDOID connectionZDOID = val.GetConnectionZDOID((ConnectionType)3);
			if (!((ZDOID)(ref connectionZDOID)).IsNone() && ZDOMan.instance.GetZDO(connectionZDOID) != null)
			{
				refusal = "It is already awake.";
				return false;
			}
			if (!spawner.m_spawnInPlayerBase && (Object)(object)EffectArea.IsPointInsideArea(((Component)spawner).transform.position, (Type)4, 0f) != (Object)null)
			{
				refusal = "Something built here keeps it away.";
				return false;
			}
			if (Blocked(spawner))
			{
				refusal = "Nothing here answers the horn.";
				return false;
			}
			return true;
		}

		private static ZDO ZdoOf(CreatureSpawner spawner)
		{
			if ((Object)(object)spawner == (Object)null)
			{
				return null;
			}
			ZNetView component = ((Component)spawner).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return null;
			}
			return component.GetZDO();
		}

		private static List<ZDO> Observable(List<CreatureSpawner> bosses, List<CreatureSpawner> all)
		{
			List<CreatureSpawner> list = new List<CreatureSpawner>();
			foreach (CreatureSpawner boss in bosses)
			{
				if (!list.Contains(boss))
				{
					list.Add(boss);
				}
				foreach (CreatureSpawner item in Dungeons.Groupmates(boss, all))
				{
					if (!list.Contains(item))
					{
						list.Add(item);
					}
				}
			}
			List<ZDO> list2 = new List<ZDO>();
			foreach (CreatureSpawner item2 in list)
			{
				ZDO val = ZdoOf(item2);
				if (val != null)
				{
					list2.Add(val);
				}
			}
			return list2;
		}

		private static bool Blocked(CreatureSpawner spawner)
		{
			List<string> globalKeys = ZoneSystem.instance.GetGlobalKeys();
			if (!string.IsNullOrEmpty(spawner.m_blockingGlobalKey) && globalKeys.Contains(spawner.m_blockingGlobalKey))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(spawner.m_requiredGlobalKey))
			{
				return !globalKeys.Contains(spawner.m_requiredGlobalKey);
			}
			return false;
		}

		internal static void Succeeded(ZDO generator, Player player)
		{
			if (generator != null)
			{
				generator.Set(SoundedKey, (long)ZNet.instance.GetTimeSeconds());
			}
			LurPlugin.Log.LogInfo((object)"Something woke - the horn is spent.");
			if (!((Object)(object)player == (Object)null))
			{
				Consume(player);
				((Character)player).Message((MessageType)2, "Something wakes.", 0, (Sprite)null);
			}
		}

		internal static void TimedOut(List<Cleared> cleared, Player player)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			foreach (Cleared item in cleared)
			{
				if (item.Zdo != null)
				{
					item.Zdo.SetConnection(item.Type, item.Target);
				}
			}
			LurPlugin.Log.LogInfo((object)("Nothing stirred - put " + cleared.Count + " spawner(s) back as they were. The horn was not spent."));
			if (!((Object)(object)player == (Object)null))
			{
				((Character)player).Message((MessageType)2, "Nothing stirred.", 0, (Sprite)null);
			}
		}

		private static void Consume(Player player)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory != null)
			{
				ItemData item = inventory.GetItem("Lur", -1, true);
				if (item != null)
				{
					inventory.RemoveOneItem(item);
				}
			}
		}

		private static void Effect(Vector3 at)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			string value = LurConfig.SoundEffectPrefab.Value;
			if (!string.IsNullOrEmpty(value))
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(value);
				if ((Object)(object)prefab == (Object)null)
				{
					LurPlugin.LogOnce("Sound effect prefab '" + value + "' does not exist - the horn is silent. Anything else about it is unaffected.");
				}
				else
				{
					Object.Instantiate<GameObject>(prefab, at, Quaternion.identity);
				}
			}
		}

		private static void Refuse(Player player, string message)
		{
			if (!((Object)(object)player == (Object)null))
			{
				((Character)player).Message((MessageType)2, message, 0, (Sprite)null);
			}
		}
	}
	internal class Watch : MonoBehaviour
	{
		private List<Sounding.Cleared> _cleared;

		private ZDO _generator;

		private Player _player;

		private int _wanted;

		internal List<ZDO> Observe;

		internal void Begin(List<Sounding.Cleared> cleared, ZDO generator, Player player, int wantedPrefabHash)
		{
			_cleared = cleared;
			_generator = generator;
			_player = player;
			_wanted = wantedPrefabHash;
			((MonoBehaviour)this).StartCoroutine(Run());
		}

		private IEnumerator Run()
		{
			float deadline = Time.time + Mathf.Max(1f, LurConfig.WatchSeconds.Value);
			while (Time.time < deadline)
			{
				foreach (ZDO item in (Observe != null && Observe.Count > 0) ? Observe : Cleared())
				{
					if (item != null && (int)item.GetConnectionType() == 3)
					{
						ZDOID connectionZDOID = item.GetConnectionZDOID((ConnectionType)3);
						if (!((ZDOID)(ref connectionZDOID)).IsNone() && IsWanted(item, connectionZDOID))
						{
							Sounding.Succeeded(_generator, _player);
							Done();
							yield break;
						}
					}
				}
				yield return (object)new WaitForSeconds(0.5f);
			}
			Sounding.TimedOut(_cleared, _player);
			Done();
		}

		private List<ZDO> Cleared()
		{
			List<ZDO> list = new List<ZDO>();
			foreach (Sounding.Cleared item in _cleared)
			{
				if (item.Zdo != null)
				{
					list.Add(item.Zdo);
				}
			}
			return list;
		}

		private bool IsWanted(ZDO zdo, ZDOID target)
		{
			//IL_000f: 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)
			if (_wanted == 0)
			{
				return true;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(target);
			if (zDO == null)
			{
				return true;
			}
			if (zDO.GetPrefab() == _wanted)
			{
				return true;
			}
			ManualLogSource log = LurPlugin.Log;
			string[] obj = new string[7]
			{
				"Something spawned, but not what the horn was for - expected prefab hash ",
				_wanted.ToString(),
				", got ",
				zDO.GetPrefab().ToString(),
				" at ",
				null,
				null
			};
			Vector3 position = zDO.GetPosition();
			obj[5] = ((Vector3)(ref position)).ToString("F1");
			obj[6] = ". The horn was not spent. This means the boss spawner was mis-identified, so turn on Diagnose and report the census.";
			log.LogError((object)string.Concat(obj));
			if ((Object)(object)_player != (Object)null)
			{
				((Character)_player).Message((MessageType)2, "Something else stirs.", 0, (Sprite)null);
			}
			return false;
		}

		private void Done()
		{
			_cleared = null;
			_generator = null;
			_player = null;
			Object.Destroy((Object)(object)this);
		}
	}
	internal static class Store
	{
		private const string Merchant = "Hildir";

		private static TradeItem _row;

		private static ItemDrop _drop;

		private static TradeItem Row()
		{
			//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_007e: 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_00b2: Expected O, but got Unknown
			if (_row != null && (Object)(object)_drop != (Object)null)
			{
				return _row;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("Lur");
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			ItemDrop component = prefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			_drop = component;
			_row = new TradeItem
			{
				m_prefab = component,
				m_stack = Mathf.Max(1, LurConfig.Stack.Value),
				m_price = Mathf.Max(0, LurConfig.Price.Value),
				m_requiredGlobalKey = (LurConfig.SoldAfterKey.Value ?? "")
			};
			LurPlugin.Log.LogInfo((object)("Hildir will stock Lur at " + _row.m_price + " coins."));
			return _row;
		}

		internal static void Offer(Trader trader, List<TradeItem> items)
		{
			if (!LurConfig.Enabled.Value || (Object)(object)trader == (Object)null || items == null || Utils.GetPrefabName(((Component)trader).gameObject) != "Hildir")
			{
				return;
			}
			TradeItem val = Row();
			if (val != null)
			{
				val.m_price = Mathf.Max(0, LurConfig.Price.Value);
				val.m_stack = Mathf.Max(1, LurConfig.Stack.Value);
				val.m_requiredGlobalKey = LurConfig.SoldAfterKey.Value ?? "";
				if ((string.IsNullOrEmpty(val.m_requiredGlobalKey) || ZoneSystem.instance.GetGlobalKey(val.m_requiredGlobalKey)) && !items.Contains(val))
				{
					items.Add(val);
				}
			}
		}
	}
}