Decompiled source of Skyla v0.8.0

Skyla.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using Tali_Skyla.GUI;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Skyla")]
[assembly: AssemblyDescription("Tali.Skyla")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyProduct("Skyla")]
[assembly: AssemblyCopyright("Copyright © Tali")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6941129c-0802-45bb-b0e2-2a2c7a44bc81")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyCompany("Tali")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Tali_Skyla
{
	internal class ArmorStandPatch
	{
		[HarmonyPatch(typeof(ArmorStand), "UseItem")]
		public static class ArmorStand_UseItem_Patch
		{
			public static bool Prefix(ItemStand __instance, Switch caller, Humanoid user, ItemData item)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_ITEMSTAND);
				}
				return false;
			}
		}
	}
	public class Assets
	{
		private sealed class AddedChime
		{
			public Skyla.ChimeType Chime;

			public string PrefabName;

			public string DisplayName;

			public string Description;
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		public class ObjectDB_Awake_Patch
		{
			public static void Postfix(ObjectDB __instance)
			{
				RegisterIntoObjectDB(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		public class ObjectDB_CopyOtherDB_Patch
		{
			public static void Postfix(ObjectDB __instance)
			{
				RegisterIntoObjectDB(__instance);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		public class ZNetScene_Awake_Patch
		{
			public static bool Prefix(ZNetScene __instance)
			{
				LoadAssets();
				GameObject[] s_prefabs = Assets.s_prefabs;
				foreach (GameObject val in s_prefabs)
				{
					if ((Object)(object)val.GetComponent<ZNetView>() != (Object)null)
					{
						__instance.m_prefabs.Add(val);
					}
				}
				return true;
			}

			public static void Postfix(ZNetScene __instance)
			{
				s_applyBlessingFXPrefab = __instance.GetPrefab(s_applyBlessingFX);
				s_activateFXPrefab = __instance.GetPrefab(s_activateFX);
				s_deactivateFXPrefab = __instance.GetPrefab(s_deactivateFX);
			}
		}

		private static bool assetsLoaded = false;

		public static string s_resourceName = "skyla";

		public static GameObject[] s_prefabs = null;

		public static Recipe[] s_recipes = null;

		private static string s_applyBlessingFX = "vfx_skyla_applyblessing";

		public static GameObject s_applyBlessingFXPrefab;

		private static string s_activateFX = "sfx_skyla_activate";

		public static GameObject s_activateFXPrefab;

		private static string s_deactivateFX = "sfx_skyla_deactivate";

		public static GameObject s_deactivateFXPrefab;

		private static GameObject s_balmyPrefab;

		private static readonly AddedChime[] s_addedChimes = new AddedChime[3]
		{
			new AddedChime
			{
				Chime = Skyla.ChimeType.CHIME_VIGOUR,
				PrefabName = "Skyla_Chime_Vigour",
				DisplayName = "Chime of Vigour",
				Description = "Eikthyr's restlessness, bound in bronze. Applied to a Skýla, everything done in range costs less stamina."
			},
			new AddedChime
			{
				Chime = Skyla.ChimeType.CHIME_WARMTH,
				PrefabName = "Skyla_Chime_Warmth",
				DisplayName = "Chime of Warmth",
				Description = "Struck from Moder's own heat. Applied to a Skýla, cold and freezing cannot take hold in range."
			},
			new AddedChime
			{
				Chime = Skyla.ChimeType.CHIME_EMBERS,
				PrefabName = "Skyla_Chime_Embers",
				DisplayName = "Chime of Embers",
				Description = "An ember of the Ashlands that will not die. Applied to a Skýla, fires in range never burn through their fuel."
			}
		};

		private static readonly Dictionary<Skyla.ChimeType, GameObject> s_addedPrefabs = new Dictionary<Skyla.ChimeType, GameObject>();

		private static AssetBundle GetAssetBundleFromResources(string filename)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			return AssetBundle.LoadFromStream(executingAssembly.GetManifestResourceStream(executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(filename))));
		}

		public static void LoadAssets()
		{
			if (!assetsLoaded)
			{
				AssetBundle assetBundleFromResources = GetAssetBundleFromResources(s_resourceName);
				if ((Object)(object)assetBundleFromResources == (Object)null)
				{
					Debug.Log((object)("Failed to load AssetBundle " + s_resourceName));
					return;
				}
				s_prefabs = assetBundleFromResources.LoadAllAssets<GameObject>();
				s_recipes = assetBundleFromResources.LoadAllAssets<Recipe>();
				Debug.Log((object)$"Loaded {s_prefabs.Length} prefabs and {s_recipes.Length} recipes from assetBundle {s_resourceName}");
				assetBundleFromResources.Unload(false);
				SkylaGUI.Init();
				assetsLoaded = true;
			}
		}

		public static void RegisterIntoObjectDB(ObjectDB db)
		{
			if ((Object)(object)db == (Object)null)
			{
				return;
			}
			LoadAssets();
			if (s_prefabs == null)
			{
				return;
			}
			Dictionary<int, GameObject> itemByHash = GetItemByHash(db);
			int num = 0;
			GameObject[] array = s_prefabs;
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ItemDrop component = val.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				if (!db.m_items.Contains(val))
				{
					db.m_items.Add(val);
				}
				int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name);
				itemByHash[stableHashCode] = val;
				string text = component.m_itemData?.m_shared?.m_name;
				bool flag = false;
				if (!string.IsNullOrEmpty(text) && PerkConfig.s_chimeMap.TryGetValue(text, out var value))
				{
					flag = true;
				}
				else if (TryMatchChimeByPrefabName(((Object)val).name, out value))
				{
					flag = true;
					if (!string.IsNullOrEmpty(text) && !PerkConfig.s_chimeMap.ContainsKey(text))
					{
						PerkConfig.s_chimeMap[text] = value;
					}
				}
				if (flag)
				{
					Chime.AddChime(val);
					PerkConfig.s_chimePrefabMap[value] = val;
					num++;
					Debug.Log((object)$"[Skyla] Registered Chime item '{((Object)val).name}' shared='{text}' -> {value}");
				}
				else if ((Object)(object)component != (Object)null)
				{
					Debug.Log((object)("[Skyla] Prefab '" + ((Object)val).name + "' has ItemDrop shared='" + text + "' but did not match a Chime."));
				}
			}
			EnsureBalmyChime(db, itemByHash);
			EnsureAddedUtilityChimes(db, itemByHash);
			if (s_recipes != null)
			{
				Recipe[] array2 = s_recipes;
				foreach (Recipe val2 in array2)
				{
					if ((Object)(object)val2 != (Object)null && !db.m_recipes.Contains(val2))
					{
						db.m_recipes.Add(val2);
					}
				}
			}
			AccessTools.DeclaredMethod(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null)?.Invoke(db, null);
			Skyla.EnsureSkylaInHammer();
			Debug.Log((object)$"[Skyla] ObjectDB register done — {PerkConfig.s_chimePrefabMap.Count} Chime prefab(s) in map (pass registered {num}).");
		}

		private static void EnsureBalmyChime(ObjectDB db, Dictionary<int, GameObject> itemByHash)
		{
			if ((Object)(object)db == (Object)null)
			{
				return;
			}
			GameObject itemPrefab = db.GetItemPrefab("Skyla_Chime_Balmy");
			if ((Object)(object)itemPrefab != (Object)null)
			{
				s_balmyPrefab = itemPrefab;
				PerkConfig.s_chimePrefabMap[Skyla.ChimeType.CHIME_CLEAR] = itemPrefab;
				PerkConfig.s_chimeMap["Balmy Chime"] = Skyla.ChimeType.CHIME_CLEAR;
				return;
			}
			if ((Object)(object)s_balmyPrefab == (Object)null && PerkConfig.s_chimePrefabMap.TryGetValue(Skyla.ChimeType.CHIME_CLEAR, out var value) && (Object)(object)value != (Object)null && ((Object)value).name == "Skyla_Chime_Balmy")
			{
				s_balmyPrefab = value;
			}
			if ((Object)(object)s_balmyPrefab == (Object)null)
			{
				GameObject value2 = null;
				if (!PerkConfig.s_chimePrefabMap.TryGetValue(Skyla.ChimeType.CHIME_SNOW, out value2) || (Object)(object)value2 == (Object)null)
				{
					using Dictionary<Skyla.ChimeType, GameObject>.Enumerator enumerator = PerkConfig.s_chimePrefabMap.GetEnumerator();
					if (enumerator.MoveNext())
					{
						value2 = enumerator.Current.Value;
					}
				}
				if ((Object)(object)value2 == (Object)null)
				{
					Debug.LogError((object)"[Skyla] Cannot synthesize Balmy Chime — no donor chime prefab.");
					return;
				}
				GameObject val = Object.Instantiate<GameObject>(value2);
				((Object)val).name = "Skyla_Chime_Balmy";
				Object.DontDestroyOnLoad((Object)(object)val);
				((Object)val).hideFlags = (HideFlags)61;
				val.SetActive(false);
				ItemDrop component = val.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData?.m_shared == null)
				{
					Debug.LogError((object)"[Skyla] Balmy Chime clone has no ItemDrop/shared data.");
					Object.Destroy((Object)(object)val);
					return;
				}
				component.m_itemData.m_shared.m_name = "Balmy Chime";
				component.m_itemData.m_shared.m_description = "A soft meadow chime. Applied to a Skýla, it clears the weather in range.";
				component.m_itemData.m_dropPrefab = val;
				Chime.AddChime(val);
				s_balmyPrefab = val;
				Debug.Log((object)("[Skyla] Synthesized missing Balmy Chime from '" + ((Object)value2).name + "'."));
			}
			if (!db.m_items.Contains(s_balmyPrefab))
			{
				db.m_items.Add(s_balmyPrefab);
			}
			if (itemByHash != null)
			{
				itemByHash[StringExtensionMethods.GetStableHashCode(((Object)s_balmyPrefab).name)] = s_balmyPrefab;
			}
			PerkConfig.s_chimePrefabMap[Skyla.ChimeType.CHIME_CLEAR] = s_balmyPrefab;
			PerkConfig.s_chimeMap["Balmy Chime"] = Skyla.ChimeType.CHIME_CLEAR;
			Debug.Log((object)"[Skyla] Balmy Chime registered into ObjectDB.");
		}

		private static void EnsureAddedUtilityChimes(ObjectDB db, Dictionary<int, GameObject> itemByHash)
		{
			if ((Object)(object)db == (Object)null)
			{
				return;
			}
			AddedChime[] array = s_addedChimes;
			foreach (AddedChime addedChime in array)
			{
				GameObject itemPrefab = db.GetItemPrefab(addedChime.PrefabName);
				GameObject value;
				if ((Object)(object)itemPrefab != (Object)null)
				{
					value = itemPrefab;
					s_addedPrefabs[addedChime.Chime] = itemPrefab;
				}
				else if (!s_addedPrefabs.TryGetValue(addedChime.Chime, out value) || (Object)(object)value == (Object)null)
				{
					value = SynthesizeChime(addedChime);
					if ((Object)(object)value == (Object)null)
					{
						continue;
					}
					s_addedPrefabs[addedChime.Chime] = value;
				}
				if (!db.m_items.Contains(value))
				{
					db.m_items.Add(value);
				}
				if (itemByHash != null)
				{
					itemByHash[StringExtensionMethods.GetStableHashCode(((Object)value).name)] = value;
				}
				PerkConfig.s_chimePrefabMap[addedChime.Chime] = value;
				PerkConfig.s_chimeMap[addedChime.DisplayName] = addedChime.Chime;
			}
		}

		private static GameObject SynthesizeChime(AddedChime spec)
		{
			GameObject value = null;
			Skyla.ChimeType[] array = new Skyla.ChimeType[4]
			{
				Skyla.ChimeType.CHIME_INDUSTRY,
				Skyla.ChimeType.CHIME_COMFORT,
				Skyla.ChimeType.CHIME_FARMING,
				Skyla.ChimeType.CHIME_COOKING
			};
			foreach (Skyla.ChimeType key in array)
			{
				if (PerkConfig.s_chimePrefabMap.TryGetValue(key, out value) && (Object)(object)value != (Object)null)
				{
					break;
				}
				value = null;
			}
			if ((Object)(object)value == (Object)null)
			{
				using Dictionary<Skyla.ChimeType, GameObject>.Enumerator enumerator = PerkConfig.s_chimePrefabMap.GetEnumerator();
				if (enumerator.MoveNext())
				{
					value = enumerator.Current.Value;
				}
			}
			if ((Object)(object)value == (Object)null)
			{
				Debug.LogError((object)("[Skyla] Cannot synthesize " + spec.DisplayName + " — no donor chime prefab."));
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(value);
			((Object)val).name = spec.PrefabName;
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.SetActive(false);
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData?.m_shared == null)
			{
				Debug.LogError((object)("[Skyla] " + spec.DisplayName + " clone has no ItemDrop/shared data."));
				Object.Destroy((Object)(object)val);
				return null;
			}
			component.m_itemData.m_shared.m_name = spec.DisplayName;
			component.m_itemData.m_shared.m_description = spec.Description;
			component.m_itemData.m_dropPrefab = val;
			Chime.AddChime(val);
			Debug.Log((object)("[Skyla] Synthesized " + spec.DisplayName + " from '" + ((Object)value).name + "'."));
			return val;
		}

		public static void EnsureBalmyInCurrentObjectDB()
		{
			ObjectDB instance = ObjectDB.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				Dictionary<int, GameObject> itemByHash = GetItemByHash(instance);
				EnsureBalmyChime(instance, itemByHash);
				EnsureAddedUtilityChimes(instance, itemByHash);
				AccessTools.DeclaredMethod(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null)?.Invoke(instance, null);
			}
		}

		private static bool TryMatchChimeByPrefabName(string prefabName, out Skyla.ChimeType chime)
		{
			chime = Skyla.ChimeType.CHIME_FARMING;
			if (string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			string text = prefabName.ToLowerInvariant();
			if (text.Contains("fertility") || text.Contains("farming"))
			{
				chime = Skyla.ChimeType.CHIME_FARMING;
				return true;
			}
			if (text.Contains("hearth") || text.Contains("cooking"))
			{
				chime = Skyla.ChimeType.CHIME_COOKING;
				return true;
			}
			if (text.Contains("comfort"))
			{
				chime = Skyla.ChimeType.CHIME_COMFORT;
				return true;
			}
			if (text.Contains("industry"))
			{
				chime = Skyla.ChimeType.CHIME_INDUSTRY;
				return true;
			}
			if (text.Contains("blizzard") || text.Contains("snowstorm"))
			{
				chime = Skyla.ChimeType.CHIME_SNOWSTORM;
				return true;
			}
			if (text.Contains("snow"))
			{
				chime = Skyla.ChimeType.CHIME_SNOW;
				return true;
			}
			if (text.Contains("ash"))
			{
				chime = Skyla.ChimeType.CHIME_ASHRAIN;
				return true;
			}
			if (text.Contains("tempest") || text.Contains("mistland"))
			{
				chime = Skyla.ChimeType.CHIME_MISTLANDS_STORM;
				return true;
			}
			if (text.Contains("storm") || text.Contains("thunder"))
			{
				chime = Skyla.ChimeType.CHIME_STORM;
				return true;
			}
			if (text.Contains("balmy") || text.Contains("clear"))
			{
				chime = Skyla.ChimeType.CHIME_CLEAR;
				return true;
			}
			return false;
		}

		private static Dictionary<int, GameObject> GetItemByHash(ObjectDB objDB)
		{
			FieldInfo field = typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic);
			if (!(field != null))
			{
				return new Dictionary<int, GameObject>();
			}
			return (Dictionary<int, GameObject>)field.GetValue(objDB);
		}
	}
	internal class BeehivePatch
	{
		[HarmonyPatch(typeof(Beehive), "Interact")]
		public static class Beehive_Interact_Patch
		{
			public static bool Prefix(Beehive __instance, Humanoid character, bool repeat, bool alt)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_BEEHIVE);
				}
				return false;
			}
		}
	}
	internal static class BossAltarGuard
	{
		[HarmonyPatch(typeof(OfferingBowl), "Awake")]
		public static class OfferingBowl_Awake_Patch
		{
			public static void Postfix(OfferingBowl __instance)
			{
				Register(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		public static class Player_UpdatePlacementGhost_Patch
		{
			private static readonly FieldInfo f_ghost = AccessTools.Field(typeof(Player), "m_placementGhost");

			private static readonly FieldInfo f_status = AccessTools.Field(typeof(Player), "m_placementStatus");

			private static readonly MethodInfo m_setValid = AccessTools.Method(typeof(Player), "SetPlacementGhostValid", new Type[1] { typeof(bool) }, (Type[])null);

			public static void Postfix(Player __instance)
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				if (!(f_ghost == null) && !(f_status == null))
				{
					object? value = f_ghost.GetValue(__instance);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if (!((Object)(object)val == (Object)null) && IsSkyla(val) && IsBlocked(val.transform.position, out var _))
					{
						f_status.SetValue(__instance, (object)(PlacementStatus)3);
						m_setValid?.Invoke(__instance, new object[1] { false });
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		public static class Player_TryPlacePiece_Patch
		{
			private static readonly FieldInfo f_ghost = AccessTools.Field(typeof(Player), "m_placementGhost");

			public static bool Prefix(Player __instance, ref bool __result)
			{
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				if (f_ghost == null)
				{
					return true;
				}
				object? value = f_ghost.GetValue(__instance);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val == (Object)null || !IsSkyla(val))
				{
					return true;
				}
				if (!IsBlocked(val.transform.position, out var distance))
				{
					return true;
				}
				((Character)__instance).Message((MessageType)2, $"Too close to a boss altar ({distance:0}m of {SkylaConfig.BossAltarExclusionRadius():0}m).", 0, (Sprite)null, false);
				__result = false;
				return false;
			}
		}

		private static readonly List<OfferingBowl> s_altars = new List<OfferingBowl>();

		internal static void Register(OfferingBowl bowl)
		{
			if (!((Object)(object)bowl == (Object)null))
			{
				s_altars.RemoveAll((OfferingBowl a) => (Object)(object)a == (Object)null);
				if (!s_altars.Contains(bowl))
				{
					s_altars.Add(bowl);
				}
			}
		}

		internal static bool IsBlocked(Vector3 position, out float distance)
		{
			//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)
			distance = float.MaxValue;
			float num = SkylaConfig.BossAltarExclusionRadius();
			if (num <= 0f)
			{
				return false;
			}
			bool result = false;
			for (int num2 = s_altars.Count - 1; num2 >= 0; num2--)
			{
				OfferingBowl val = s_altars[num2];
				if ((Object)(object)val == (Object)null)
				{
					s_altars.RemoveAt(num2);
				}
				else if (!((Object)(object)val.m_bossPrefab == (Object)null))
				{
					float num3 = Vector3.Distance(((Component)val).transform.position, position);
					if (!(num3 > num))
					{
						result = true;
						if (num3 < distance)
						{
							distance = num3;
						}
					}
				}
			}
			return result;
		}

		internal static bool IsSkyla(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			if ((Object)(object)go.GetComponent<Skyla>() != (Object)null)
			{
				return true;
			}
			return ((Object)go).name.StartsWith(Skyla.s_prefabName, StringComparison.Ordinal);
		}
	}
	public class Chime : MonoBehaviour
	{
		private static AudioSource s_master;

		private static readonly HashSet<AudioSource> s_sources = new HashSet<AudioSource>();

		private static readonly object s_lock = new object();

		private AudioSource m_source;

		public static void AddChime(GameObject prefab)
		{
			if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponentInChildren<Chime>() != (Object)null))
			{
				GameObject val = prefab;
				Transform val2 = prefab.transform.Find("attach");
				if ((Object)(object)val2 != (Object)null)
				{
					val = ((Component)val2).gameObject;
				}
				val.AddComponent<Chime>();
			}
		}

		private void Awake()
		{
			m_source = ((Component)this).GetComponentInChildren<AudioSource>();
			if ((Object)(object)m_source == (Object)null)
			{
				Debug.LogWarning((object)("[Chime] No AudioSource found on '" + ((Object)((Component)this).gameObject).name + "'. Chime will not be registered."));
				return;
			}
			lock (s_lock)
			{
				s_sources.Add(m_source);
				if ((Object)(object)s_master == (Object)null)
				{
					s_master = m_source;
				}
				else if ((Object)(object)s_master != (Object)(object)m_source)
				{
					m_source.timeSamples = s_master.timeSamples;
				}
			}
			ZSFX componentInChildren = ((Component)this).GetComponentInChildren<ZSFX>();
			if (componentInChildren != null)
			{
				componentInChildren.Play();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)m_source == (Object)null)
			{
				return;
			}
			lock (s_lock)
			{
				s_sources.Remove(m_source);
				s_master = null;
				using HashSet<AudioSource>.Enumerator enumerator = s_sources.GetEnumerator();
				if (enumerator.MoveNext())
				{
					s_master = enumerator.Current;
				}
			}
		}
	}
	public static class ChimeEffects
	{
		[HarmonyPatch(typeof(Character), "UseStamina")]
		public static class Character_UseStamina_Patch
		{
			public static void Prefix(Character __instance, ref float stamina)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				if (!(stamina <= 0f) && !((Object)(object)__instance == (Object)null) && __instance is Player && Skyla.ChimeApplies(((Component)__instance).transform.position, Skyla.ChimeType.CHIME_VIGOUR))
				{
					stamina *= 0.75f;
				}
			}
		}

		[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
		{
			typeof(int),
			typeof(bool),
			typeof(int),
			typeof(float),
			typeof(short)
		})]
		public static class SEMan_AddStatusEffect_Patch
		{
			public static bool Prefix(SEMan __instance, int nameHash, ref StatusEffect __result)
			{
				if (nameHash != s_coldHash && nameHash != s_freezingHash)
				{
					return true;
				}
				if (!PlayerCoveredBy(__instance, Skyla.ChimeType.CHIME_WARMTH))
				{
					return true;
				}
				__result = null;
				return false;
			}
		}

		[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
		{
			typeof(StatusEffect),
			typeof(bool),
			typeof(int),
			typeof(float),
			typeof(short)
		})]
		public static class SEMan_AddStatusEffectObj_Patch
		{
			public static bool Prefix(SEMan __instance, StatusEffect statusEffect, ref StatusEffect __result)
			{
				if ((Object)(object)statusEffect == (Object)null)
				{
					return true;
				}
				int num = statusEffect.NameHash();
				if (num != s_coldHash && num != s_freezingHash)
				{
					return true;
				}
				if (!PlayerCoveredBy(__instance, Skyla.ChimeType.CHIME_WARMTH))
				{
					return true;
				}
				__result = null;
				return false;
			}
		}

		[HarmonyPatch(typeof(Fireplace), "UpdateFireplace")]
		public static class Fireplace_UpdateFireplace_Patch
		{
			public static void Prefix(Fireplace __instance)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				int instanceID = ((Object)__instance).GetInstanceID();
				bool flag = s_emberFires.Contains(instanceID);
				if (Skyla.ChimeApplies(((Component)__instance).transform.position, Skyla.ChimeType.CHIME_EMBERS))
				{
					if (!__instance.m_infiniteFuel)
					{
						__instance.m_infiniteFuel = true;
						s_emberFires.Add(instanceID);
					}
				}
				else if (flag)
				{
					__instance.m_infiniteFuel = false;
					s_emberFires.Remove(instanceID);
				}
			}
		}

		public const float VigourStaminaMultiplier = 0.75f;

		private static readonly int s_coldHash = StringExtensionMethods.GetStableHashCode("Cold");

		private static readonly int s_freezingHash = StringExtensionMethods.GetStableHashCode("Freezing");

		private static readonly FieldInfo s_semanCharacter = AccessTools.Field(typeof(SEMan), "m_character");

		private static readonly HashSet<int> s_emberFires = new HashSet<int>();

		private static Character OwnerOf(SEMan seman)
		{
			if (seman == null || s_semanCharacter == null)
			{
				return null;
			}
			object? value = s_semanCharacter.GetValue(seman);
			return (Character)((value is Character) ? value : null);
		}

		private static bool PlayerCoveredBy(SEMan seman, Skyla.ChimeType chime)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			Character val = OwnerOf(seman);
			if ((Object)(object)val == (Object)null || !(val is Player))
			{
				return false;
			}
			return Skyla.ChimeApplies(((Component)val).transform.position, chime);
		}
	}
	public static class ChimeTrader
	{
		private sealed class Offer
		{
			public Skyla.ChimeType Chime;

			public string GlobalKey;

			public string TrophyPrefab;

			public string Label;

			public bool Weather;
		}

		[HarmonyPatch(typeof(Trader), "Start")]
		public class Trader_Start_Patch
		{
			public static void Postfix(Trader __instance)
			{
				try
				{
					StockHaldor(__instance);
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[Skyla] Haldor stock (Start) failed: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(Trader), "Interact")]
		public class Trader_Interact_Patch
		{
			public static void Prefix(Trader __instance)
			{
				try
				{
					StockHaldor(__instance);
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[Skyla] Haldor stock (Interact) failed: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(StoreGui), "Show")]
		public class StoreGui_Show_Patch
		{
			public static void Prefix(Trader trader)
			{
				try
				{
					StockHaldor(trader);
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[Skyla] Haldor stock (Show) failed: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(StoreGui), "FillList")]
		public class StoreGui_FillList_Patch
		{
			private static readonly FieldInfo f_trader = AccessTools.Field(typeof(StoreGui), "m_trader");

			public static void Prefix(StoreGui __instance)
			{
				try
				{
					object? obj = f_trader?.GetValue(__instance);
					StockHaldor((Trader)((obj is Trader) ? obj : null));
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[Skyla] Haldor stock (FillList) failed: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(StoreGui), "CanAfford")]
		public class StoreGui_CanAfford_Patch
		{
			public static void Postfix(TradeItem item, ref bool __result)
			{
				CanAffordTrophy(item, ref __result);
			}
		}

		[HarmonyPatch(typeof(StoreGui), "BuySelectedItem")]
		public class StoreGui_BuySelectedItem_Patch
		{
			public static bool Prefix(StoreGui __instance)
			{
				string blockMessage;
				bool num = TryBeginBuy(__instance, out blockMessage);
				if (!num && !string.IsNullOrEmpty(blockMessage) && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, blockMessage, 0, (Sprite)null, false);
				}
				return num;
			}

			public static void Postfix()
			{
				FinishBuy();
			}
		}

		[HarmonyPatch(typeof(StoreGui), "UpdateBuyButton")]
		public class StoreGui_UpdateBuyButton_Patch
		{
			public static void Postfix(StoreGui __instance)
			{
				RestrictBuyButton(__instance);
			}
		}

		private static readonly Offer[] s_offers = new Offer[13]
		{
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_FARMING,
				GlobalKey = "defeated_gdking",
				TrophyPrefab = "TrophyTheElder",
				Label = "Chime of Fertility",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_COMFORT,
				GlobalKey = "defeated_bonemass",
				TrophyPrefab = "TrophyBonemass",
				Label = "Chime of Comfort",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_COOKING,
				GlobalKey = "defeated_goblinking",
				TrophyPrefab = "TrophyGoblinKing",
				Label = "Chime of the Hearth",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_INDUSTRY,
				GlobalKey = "defeated_queen",
				TrophyPrefab = "TrophySeekerQueen",
				Label = "Chime of Industry",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_VIGOUR,
				GlobalKey = "defeated_eikthyr",
				TrophyPrefab = "TrophyEikthyr",
				Label = "Chime of Vigour",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_WARMTH,
				GlobalKey = "defeated_dragon",
				TrophyPrefab = "TrophyDragonQueen",
				Label = "Chime of Warmth",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_EMBERS,
				GlobalKey = "defeated_fader",
				TrophyPrefab = "TrophyFader",
				Label = "Chime of Embers",
				Weather = false
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_CLEAR,
				GlobalKey = "defeated_eikthyr",
				TrophyPrefab = "TrophyNeck",
				Label = "Balmy Chime",
				Weather = true
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_SNOW,
				GlobalKey = "defeated_dragon",
				TrophyPrefab = "TrophyWolf",
				Label = "Snow Chime",
				Weather = true
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_SNOWSTORM,
				GlobalKey = "defeated_dragon",
				TrophyPrefab = "TrophyHatchling",
				Label = "Blizzard Chime",
				Weather = true
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_STORM,
				GlobalKey = "defeated_goblinking",
				TrophyPrefab = "TrophyDeathsquito",
				Label = "Storm Chime",
				Weather = true
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_MISTLANDS_STORM,
				GlobalKey = "defeated_queen",
				TrophyPrefab = "TrophyGjall",
				Label = "Tempest Chime",
				Weather = true
			},
			new Offer
			{
				Chime = Skyla.ChimeType.CHIME_ASHRAIN,
				GlobalKey = "defeated_fader",
				TrophyPrefab = "TrophyAsksvin",
				Label = "Chime of Ashes",
				Weather = true
			}
		};

		private static readonly Dictionary<TradeItem, string> s_trophyByTrade = new Dictionary<TradeItem, string>();

		private static readonly Dictionary<TradeItem, int> s_priceByTrade = new Dictionary<TradeItem, int>();

		private static string s_pendingTrophyPrefab;

		private static string s_pendingChimeSharedName;

		private static int s_pendingChimeCountBefore;

		private static int s_pendingPrice;

		private static bool s_pendingBuy;

		private static bool Enabled => SkylaConfig.ChimeTraderEnabled();

		private static int PriceFor(Offer offer)
		{
			if (!offer.Weather)
			{
				return SkylaConfig.ChimeTraderUtilityPrice();
			}
			return SkylaConfig.ChimeTraderWeatherPrice();
		}

		private static string TrophyKind(Offer offer)
		{
			if (!offer.Weather)
			{
				return "boss trophy";
			}
			return "mob trophy";
		}

		private static bool IsExcludedMerchant(Trader trader)
		{
			if ((Object)(object)trader == (Object)null)
			{
				return true;
			}
			string text = trader.m_name + " " + ((Object)((Component)trader).gameObject).name;
			if (text.IndexOf("Hildir", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("BogWitch", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return text.IndexOf("Blidh", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static ItemDrop FindItemDrop(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName) || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			if (!((Object)(object)itemPrefab == (Object)null))
			{
				return itemPrefab.GetComponent<ItemDrop>();
			}
			return null;
		}

		private static bool TryGetChimeDrop(Skyla.ChimeType chime, out ItemDrop drop)
		{
			drop = null;
			if (!PerkConfig.s_chimePrefabMap.TryGetValue(chime, out var value) || (Object)(object)value == (Object)null)
			{
				if ((Object)(object)ObjectDB.instance != (Object)null)
				{
					Assets.RegisterIntoObjectDB(ObjectDB.instance);
				}
				if (!PerkConfig.s_chimePrefabMap.TryGetValue(chime, out value) || (Object)(object)value == (Object)null)
				{
					return false;
				}
			}
			drop = value.GetComponent<ItemDrop>();
			return (Object)(object)drop != (Object)null;
		}

		private static bool HasGlobalKey(string key)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(key))
			{
				return true;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (instance.GetGlobalKey(key))
			{
				return true;
			}
			if (Enum.TryParse<GlobalKeys>(key, ignoreCase: true, out GlobalKeys result) && instance.GetGlobalKey(result))
			{
				return true;
			}
			return false;
		}

		public static void StockHaldor(Trader trader)
		{
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: 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_0245: 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_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Expected O, but got Unknown
			if (!Enabled)
			{
				Debug.Log((object)"[Skyla] Haldor chime sales disabled in config.");
			}
			else
			{
				if ((Object)(object)trader == (Object)null || IsExcludedMerchant(trader))
				{
					return;
				}
				Assets.EnsureBalmyInCurrentObjectDB();
				string text = ((Object)((Component)trader).gameObject).name ?? "?";
				string text2 = trader.m_name ?? "";
				if (trader.m_items == null)
				{
					trader.m_items = new List<TradeItem>();
				}
				trader.m_items.RemoveAll((TradeItem ti) => ti != null && s_trophyByTrade.ContainsKey(ti));
				trader.m_items.RemoveAll(delegate(TradeItem ti)
				{
					if ((Object)(object)ti?.m_prefab == (Object)null)
					{
						return false;
					}
					Offer[] array3 = s_offers;
					for (int i = 0; i < array3.Length; i++)
					{
						if (TryGetChimeDrop(array3[i].Chime, out var drop2) && (Object)(object)drop2 == (Object)(object)ti.m_prefab)
						{
							return true;
						}
					}
					return false;
				});
				List<TradeItem> list = new List<TradeItem>();
				foreach (KeyValuePair<TradeItem, string> item in s_trophyByTrade)
				{
					if (trader.m_items.Contains(item.Key))
					{
						list.Add(item.Key);
					}
				}
				foreach (TradeItem item2 in list)
				{
					s_trophyByTrade.Remove(item2);
					s_priceByTrade.Remove(item2);
				}
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				Offer[] array = s_offers;
				foreach (Offer offer in array)
				{
					if (!TryGetChimeDrop(offer.Chime, out var drop))
					{
						num2++;
						Debug.LogWarning((object)$"[Skyla] Haldor: chime prefab missing for {offer.Chime} ({offer.Label}).");
						continue;
					}
					if ((Object)(object)FindItemDrop(offer.TrophyPrefab) == (Object)null)
					{
						Debug.LogWarning((object)("[Skyla] Haldor: trophy '" + offer.TrophyPrefab + "' not in ObjectDB — skipping " + offer.Label + "."));
						continue;
					}
					if (!HasGlobalKey(offer.GlobalKey))
					{
						num4++;
						continue;
					}
					int num6 = PriceFor(offer);
					TradeItem val = new TradeItem
					{
						m_prefab = drop,
						m_stack = 1,
						m_price = num6,
						m_requiredGlobalKey = "",
						m_name = offer.Label,
						m_tooltip = $"{num6} coins + {offer.TrophyPrefab} ({TrophyKind(offer)})"
					};
					trader.m_items.Add(val);
					s_trophyByTrade[val] = offer.TrophyPrefab;
					s_priceByTrade[val] = num6;
					num++;
					num3++;
				}
				List<string> list2 = new List<string>();
				string[] array2 = new string[7] { "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" };
				foreach (string text3 in array2)
				{
					list2.Add(text3.Replace("defeated_", "") + "=" + (HasGlobalKey(text3) ? "yes" : "no"));
				}
				List<string> list3 = new List<string>();
				foreach (TradeItem item3 in trader.m_items)
				{
					if (s_trophyByTrade.TryGetValue(item3, out var value))
					{
						string text4 = (((Object)(object)item3.m_prefab != (Object)null) ? ((Object)item3.m_prefab).name : "<null>");
						list3.Add(item3.m_name + "[" + text4 + "]<-" + value);
					}
				}
				string text5 = $"Haldor ('{text}' / '{text2}'): stocked {num} chime(s), {num4} still locked, missingPrefab={num2}. " + "Bosses: " + string.Join(" ", list2.ToArray()) + "\n" + string.Format("  rows ({0}): {1}", list3.Count, string.Join(" | ", list3.ToArray()));
				if (Mod.Log != null)
				{
					Mod.Log.LogInfo((object)text5);
				}
				else
				{
					Debug.Log((object)("[Skyla] " + text5));
				}
			}
		}

		private static bool TryGetOffer(TradeItem item, out Offer offer)
		{
			offer = null;
			if ((Object)(object)item?.m_prefab == (Object)null)
			{
				return false;
			}
			Offer[] array = s_offers;
			foreach (Offer offer2 in array)
			{
				if (TryGetChimeDrop(offer2.Chime, out var drop) && (Object)(object)drop == (Object)(object)item.m_prefab)
				{
					offer = offer2;
					return true;
				}
			}
			return false;
		}

		private static bool TryGetRequiredTrophy(TradeItem item, out string trophyPrefab)
		{
			trophyPrefab = null;
			if (item == null)
			{
				return false;
			}
			if (s_trophyByTrade.TryGetValue(item, out trophyPrefab) && !string.IsNullOrEmpty(trophyPrefab))
			{
				return true;
			}
			if (!TryGetOffer(item, out var offer))
			{
				return false;
			}
			trophyPrefab = offer.TrophyPrefab;
			return true;
		}

		private static int PriceForTrade(TradeItem item)
		{
			if (item != null && s_priceByTrade.TryGetValue(item, out var value))
			{
				return value;
			}
			if (TryGetOffer(item, out var offer))
			{
				return PriceFor(offer);
			}
			return SkylaConfig.ChimeTraderUtilityPrice();
		}

		private static ItemData FindTrophyInInventory(Inventory inv, string trophyPrefab)
		{
			if (inv == null || string.IsNullOrEmpty(trophyPrefab))
			{
				return null;
			}
			ItemData item = inv.GetItem(trophyPrefab, -1, true);
			if (item != null)
			{
				return item;
			}
			ItemDrop val = FindItemDrop(trophyPrefab);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			string text = val.m_itemData?.m_shared?.m_name;
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			return inv.GetItem(text, -1, false);
		}

		private static bool PlayerHasTrophy(string trophyPrefab)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (FindTrophyInInventory(inventory, trophyPrefab) != null)
			{
				return true;
			}
			string text = FindItemDrop(trophyPrefab)?.m_itemData?.m_shared?.m_name;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem != null)
				{
					string text2 = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null);
					if (!string.IsNullOrEmpty(text2) && text2.Equals(trophyPrefab, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
					if (!string.IsNullOrEmpty(text) && allItem.m_shared != null && allItem.m_shared.m_name == text)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryBeginBuy(StoreGui gui, out string blockMessage)
		{
			blockMessage = null;
			s_pendingBuy = false;
			s_pendingTrophyPrefab = null;
			s_pendingChimeSharedName = null;
			s_pendingChimeCountBefore = 0;
			s_pendingPrice = 0;
			if (!Enabled)
			{
				return true;
			}
			Assets.EnsureBalmyInCurrentObjectDB();
			object? obj = AccessTools.Field(typeof(StoreGui), "m_selectedItem")?.GetValue(gui);
			TradeItem val = (TradeItem)((obj is TradeItem) ? obj : null);
			if (!TryGetRequiredTrophy(val, out var trophyPrefab))
			{
				return true;
			}
			int num = PriceForTrade(val);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			if (!PlayerHasTrophy(trophyPrefab))
			{
				blockMessage = $"Haldor wants {trophyPrefab} as well as {num} coins.";
				return false;
			}
			if ((Object)(object)val.m_prefab != (Object)null)
			{
				string name = ((Object)val.m_prefab).name;
				ObjectDB instance = ObjectDB.instance;
				GameObject val2 = ((instance != null) ? instance.GetItemPrefab(name) : null);
				if (!((Object)(object)val2 != (Object)null))
				{
					blockMessage = "Haldor can't find " + name + " in the item database.";
					Debug.LogError((object)("[Skyla] Buy blocked — ObjectDB missing '" + name + "'."));
					return false;
				}
				ItemDrop component = val2.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null)
				{
					val.m_prefab = component;
				}
			}
			string text = val.m_prefab?.m_itemData?.m_shared?.m_name;
			s_pendingBuy = true;
			s_pendingTrophyPrefab = trophyPrefab;
			s_pendingChimeSharedName = text;
			s_pendingPrice = num;
			s_pendingChimeCountBefore = ((!string.IsNullOrEmpty(text)) ? ((Humanoid)localPlayer).GetInventory().CountItems(text, -1, false) : 0);
			return true;
		}

		private static void FinishBuy()
		{
			if (!s_pendingBuy)
			{
				return;
			}
			s_pendingBuy = false;
			string text = s_pendingTrophyPrefab;
			string text2 = s_pendingChimeSharedName;
			int num = s_pendingChimeCountBefore;
			int num2 = s_pendingPrice;
			s_pendingTrophyPrefab = null;
			s_pendingChimeSharedName = null;
			s_pendingPrice = 0;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || string.IsNullOrEmpty(text))
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (!string.IsNullOrEmpty(text2) && inventory.CountItems(text2, -1, false) <= num)
			{
				Debug.LogWarning((object)"[Skyla] Buy finished but chime was not added — trophy not consumed.");
				return;
			}
			ItemData val = FindTrophyInInventory(inventory, text);
			if (val != null)
			{
				inventory.RemoveItem(val, 1);
			}
			else
			{
				string text3 = FindItemDrop(text)?.m_itemData?.m_shared?.m_name;
				if (!string.IsNullOrEmpty(text3))
				{
					inventory.RemoveItem(text3, 1, -1, false);
				}
				else
				{
					inventory.RemoveItem(text, 1, -1, true);
				}
			}
			((Character)localPlayer).Message((MessageType)2, $"Traded {text} + {num2} coins.", 0, (Sprite)null, false);
		}

		private static void RestrictBuyButton(StoreGui gui)
		{
			if (!Enabled)
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(StoreGui), "m_selectedItem");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(StoreGui), "m_buyButton");
			object? obj = fieldInfo?.GetValue(gui);
			if (!TryGetRequiredTrophy((TradeItem)((obj is TradeItem) ? obj : null), out var trophyPrefab) || PlayerHasTrophy(trophyPrefab))
			{
				return;
			}
			try
			{
				object? obj2 = fieldInfo2?.GetValue(gui);
				Button val = (Button)((obj2 is Button) ? obj2 : null);
				if ((Object)(object)val != (Object)null)
				{
					((Selectable)val).interactable = false;
				}
			}
			catch
			{
			}
		}

		private static void CanAffordTrophy(TradeItem item, ref bool result)
		{
			if (result && Enabled && TryGetRequiredTrophy(item, out var trophyPrefab) && !PlayerHasTrophy(trophyPrefab))
			{
				result = false;
			}
		}
	}
	internal class ContainerPatch
	{
		[HarmonyPatch(typeof(Container), "Interact")]
		public static class Container_Interact_Patch
		{
			public static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt)
			{
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || (Object)(object)character == (Object)null || !((Character)character).IsPlayer())
				{
					return false;
				}
				Vagon componentInParent = ((Component)__instance).gameObject.GetComponentInParent<Vagon>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					return Skyla.CanUseWagon(componentInParent, (Character)(object)character);
				}
				Ship componentInParent2 = ((Component)__instance).gameObject.GetComponentInParent<Ship>();
				if ((Object)(object)componentInParent2 != (Object)null)
				{
					return Skyla.CanUseShip(componentInParent2, (Character)(object)character);
				}
				if (!((Object)(object)((Component)__instance).gameObject.GetComponent<TombStone>() != (Object)null))
				{
					return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_CONTAINER);
				}
				return true;
			}
		}
	}
	[HarmonyPatch]
	internal static class CookingStationPatch
	{
		[HarmonyPatch(typeof(CookingStation), "UpdateFuel")]
		[HarmonyPrefix]
		private static void UpdateFuelPrefix(ref float dt, CookingStation __instance)
		{
			if (Applies(__instance))
			{
				dt *= 0.5f;
			}
		}

		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		[HarmonyPrefix]
		private static bool UpdateCookingPrefix(CookingStation __instance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return ZNetScene.instance.IsAreaReady(((Component)__instance).transform.position);
			}
			return false;
		}

		[HarmonyPatch(typeof(CookingStation), "GetSlot")]
		[HarmonyPostfix]
		private static void GetSlotPostfix(ref string itemName, ref float cookedTime, ref int status, CookingStation __instance)
		{
			if (!Applies(__instance))
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(CookingStation), "GetItemConversion", (Type[])null, (Type[])null);
			if (methodInfo == null || string.IsNullOrEmpty(itemName))
			{
				return;
			}
			object obj = methodInfo.Invoke(__instance, new object[1] { itemName });
			if (obj != null)
			{
				float num = (float)AccessTools.Field(obj.GetType(), "m_cookTime").GetValue(obj) * 1.1f;
				if (!((double)cookedTime <= (double)num))
				{
					cookedTime = num;
				}
			}
		}

		[HarmonyPatch(typeof(CookingStation), "SetSlot")]
		[HarmonyPrefix]
		private static void SetSlotPrefix(int slot, ref string itemName, ref float cookedTime, ref int status, CookingStation __instance)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if (!Applies(__instance))
			{
				return;
			}
			ZNetView val = (ZNetView)AccessTools.Field(typeof(CookingStation), "m_nview").GetValue(__instance);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				float num = val.GetZDO().GetFloat("slot" + slot, 0f);
				if (status == 0)
				{
					float num2 = cookedTime - num;
					cookedTime = num + num2 * 1.25f;
				}
			}
		}

		private static bool Applies(CookingStation cs)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Skyla.ChimeApplies(((Component)cs).transform.position, Skyla.ChimeType.CHIME_COOKING);
		}
	}
	internal class DestructiblePatch
	{
		[HarmonyPatch(typeof(Destructible), "RPC_Damage")]
		public static class Destructible_Damage_Patch
		{
			public static bool Prefix(Destructible __instance, long sender, ref HitData hit)
			{
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || hit == null)
				{
					return false;
				}
				if ((Object)(object)((Component)__instance).GetComponent<RandomFlyingBird>() != (Object)null)
				{
					return true;
				}
				if ((Object)(object)hit.GetAttacker() != (Object)null && hit.GetAttacker().IsPlayer())
				{
					return Skyla.CheckAccess(hit.GetAttacker(), ((Component)__instance).transform.position, Skyla.ActionType.ACTION_DAMAGE);
				}
				float num = 1f - Skyla.FindMaxSkylaPower(((Component)__instance).transform.position);
				if ((double)num <= 0.0)
				{
					return false;
				}
				hit.ApplyModifier(num);
				return true;
			}
		}
	}
	internal class DoorPatch
	{
		[HarmonyPatch(typeof(Door), "Interact")]
		public static class Door_Interact_Patch
		{
			public static bool Prefix(Door __instance, Humanoid character, bool hold, bool alt)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_DOOR);
				}
				return false;
			}
		}
	}
	internal class EnvManPatch
	{
		[HarmonyPatch(typeof(EnvMan), "GetEnvironmentOverride")]
		public static class EnvMan_GetEnvironmentOverride_Patch
		{
			public static void Postfix(EnvMan __instance, ref string __result)
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				if (__result == null && !((Object)(object)Player.m_localPlayer == (Object)null))
				{
					switch (Skyla.FindWeatherMode(((Component)Player.m_localPlayer).transform.position))
					{
					case PerkConfig.WeatherMode.WEATHER_SNOW:
						__result = (EnvMan.IsDay() ? "Snow" : "Twilight_Snow");
						break;
					case PerkConfig.WeatherMode.WEATHER_STORM:
						__result = "ThunderStorm";
						break;
					case PerkConfig.WeatherMode.WEATHER_SNOWSTORM:
						__result = (EnvMan.IsDay() ? "SnowStorm" : "Twilight_SnowStorm");
						break;
					case PerkConfig.WeatherMode.WEATHER_MISTLANDS_STORM:
						__result = "Mistlands_thunder";
						break;
					case PerkConfig.WeatherMode.WEATHER_ASHRAIN:
						__result = "Ashrain";
						break;
					case PerkConfig.WeatherMode.WEATHER_CLEAR:
						__result = "Clear";
						break;
					}
				}
			}
		}
	}
	internal class FermenterPatch
	{
		[HarmonyPatch(typeof(Fermenter), "Interact")]
		public static class Fermenter_Interact_Patch
		{
			public static bool Prefix(Fermenter __instance, Humanoid user, bool hold, bool alt)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_FERMENTER);
				}
				return false;
			}
		}
	}
	internal class FireplacePatch
	{
		[HarmonyPatch(typeof(Fireplace), "UpdateFireplace")]
		public static class Fireplace_UpdateFireplace_Patch
		{
			public static bool Prefix(Fireplace __instance, ref float __state)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsOwner())
				{
					__state = component.GetZDO().GetFloat("fuel", 0f);
				}
				return true;
			}

			public static void Postfix(Fireplace __instance, float __state)
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)__instance == (Object)null))
				{
					ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
					if (!((Object)(object)component == (Object)null) && component.IsOwner())
					{
						float num = component.GetZDO().GetFloat("fuel", 0f);
						float num2 = Skyla.FindMaxSkylaPower(((Component)__instance).transform.position);
						float num3 = __state - num;
						float num4 = (((double)num2 > 0.9900000095367432) ? __instance.m_maxFuel : Math.Min(__instance.m_maxFuel, num + num3 * num2));
						component.GetZDO().Set("fuel", num4);
					}
				}
			}
		}
	}
	internal class ItemStandPatch
	{
		[HarmonyPatch(typeof(ItemStand), "Interact")]
		public static class ItemStand_Interact_Patch
		{
			public static bool Prefix(ItemStand __instance, Humanoid user, bool hold, bool alt)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_ITEMSTAND);
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(ItemStand), "UseItem")]
		public static class ItemStand_UseItem_Patch
		{
			public static bool Prefix(ItemStand __instance, Humanoid user, ItemData item)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_ITEMSTAND);
				}
				return false;
			}
		}
	}
	public class LocalManager
	{
		private static ISet<ZDOID> s_localPlayerSkylaSet = new HashSet<ZDOID>();

		private static float s_localPlayerSkylaAreaLimit = 0f;

		private static bool s_hasReceivedInfo = false;

		public static void RegisterRPC()
		{
			ZRoutedRpc.instance.Register<float, ZPackage>("ReceiveServerSkylaData", (Action<long, float, ZPackage>)RPC_ReceiveServerSkylaData);
		}

		private static void OutputLocalState()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			Debug.Log((object)"==================================");
			Debug.Log((object)"Dumping out local Skyla info:");
			float num = 0f;
			foreach (ZDOID item in s_localPlayerSkylaSet)
			{
				float num2 = ZDOMan.instance.GetZDO(item).GetFloat("SkylaRadius", 0f);
				Debug.Log((object)$"ZDOID {item}, Radius: {num2}");
				num += (float)Math.PI * num2 * num2;
			}
			Debug.Log((object)$"Total area used: {num}");
			Debug.Log((object)"==================================");
		}

		private static ISet<ZDOID> Decode(ZPackage zp)
		{
			//IL_0012: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			ISet<ZDOID> set = new HashSet<ZDOID>();
			int num = zp.ReadInt();
			for (int i = 0; i < num; i++)
			{
				ZDOID item = zp.ReadZDOID();
				set.Add(item);
			}
			return set;
		}

		private static float GetLocalPlayerAreaLimit()
		{
			return s_localPlayerSkylaAreaLimit;
		}

		private static void RPC_ReceiveServerSkylaData(long sender, float maxWardedArea, ZPackage zp)
		{
			if (!float.IsNaN(maxWardedArea))
			{
				s_localPlayerSkylaAreaLimit = maxWardedArea;
			}
			s_localPlayerSkylaSet = Decode(zp);
			s_hasReceivedInfo = true;
		}

		private static float GetUsedArea()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			foreach (ZDOID item in s_localPlayerSkylaSet)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item);
				float num2 = ((zDO != null) ? zDO.GetFloat("SkylaRadius", 0f) : 0f);
				num += (float)Math.PI * num2 * num2;
			}
			return num;
		}

		public static float GetRemainingArea()
		{
			return Math.Max(GetLocalPlayerAreaLimit() - GetUsedArea(), 0f);
		}

		private static float DistanceToNearestBlockingSkyla(Skyla skyla)
		{
			//IL_002e: 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)
			float val = 9999f;
			foreach (Skyla s_localSkyla in Skyla.s_localSkylaList)
			{
				if (s_localSkyla.GetOwner() != skyla.GetOwner())
				{
					float val2 = Vector3.Distance(((Component)s_localSkyla).transform.position, ((Component)skyla).transform.position) - s_localSkyla.GetRadius();
					val = Math.Min(val, val2);
				}
			}
			return Math.Max(val, 0f);
		}

		private static float DistanceToNearestNoBuildZone(Skyla skyla)
		{
			//IL_0034: 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)
			float val = 9999f;
			Location[] array = Object.FindObjectsOfType<Location>();
			foreach (Location val2 in array)
			{
				if (val2.m_noBuild && (double)val2.m_exteriorRadius > 0.0)
				{
					float val3 = Vector3.Distance(((Component)val2).transform.position, ((Component)skyla).transform.position) - val2.m_exteriorRadius;
					val = Math.Min(val, val3);
				}
			}
			return Math.Max(val, 0f);
		}

		public static float GetMaxRadiusForSkyla(Skyla skyla)
		{
			double num = GetRemainingArea();
			float radius = skyla.GetRadius();
			double num2 = 3.1415927410125732 * (double)radius * (double)radius;
			float num3 = (float)(num + num2);
			return Math.Min(DistanceToNearestBlockingSkyla(skyla), Math.Min(SkylaConfig.MaxSkylaRadius(), Math.Min(DistanceToNearestNoBuildZone(skyla), (float)Math.Sqrt((double)num3 / 3.1415927410125732))));
		}

		private static void Local_RegisterSkyla(ZDO skylaZDO)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Player.m_localPlayer == (Object)null) && skylaZDO.GetLong("creator", 0L) == Player.m_localPlayer.GetPlayerID())
			{
				s_localPlayerSkylaSet.Add(skylaZDO.m_uid);
			}
		}

		private static void Local_UnregisterSkyla(ZDO skylaZDO)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Player.m_localPlayer == (Object)null) && skylaZDO.GetLong("creator", 0L) == Player.m_localPlayer.GetPlayerID())
			{
				s_localPlayerSkylaSet.Remove(skylaZDO.m_uid);
			}
		}

		public static void RemoveSkyla(ZDO skylaZDO)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Local_UnregisterSkyla(skylaZDO);
			ZRoutedRpc.instance.InvokeRoutedRPC("UnregisterSkyla", new object[1] { skylaZDO.m_uid });
		}

		public static void AddSkyla(ZDO skylaZDO)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Local_RegisterSkyla(skylaZDO);
			ZRoutedRpc.instance.InvokeRoutedRPC("RegisterSkyla", new object[1] { skylaZDO.m_uid });
		}

		public static void RequestInfo(long playerID)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC("RequestInfo", new object[1] { playerID });
		}
	}
	internal class MineRockPatch
	{
		[HarmonyPatch(typeof(MineRock), "RPC_Hit")]
		public static class MineRock_Hit_Patch
		{
			public static bool Prefix(MineRock __instance, long sender, ref HitData hit)
			{
				//IL_0050: 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 ((Object)(object)__instance == (Object)null || hit == null)
				{
					return false;
				}
				if ((Object)(object)hit.GetAttacker() != (Object)null && hit.GetAttacker().IsPlayer())
				{
					return Skyla.CheckAccess(hit.GetAttacker(), ((Component)__instance).transform.position, Skyla.ActionType.ACTION_DAMAGE);
				}
				float num = 1f - Skyla.FindMaxSkylaPower(((Component)__instance).transform.position);
				if ((double)num <= 0.0)
				{
					return false;
				}
				hit.ApplyModifier(num);
				return true;
			}
		}

		[HarmonyPatch(typeof(MineRock5), "RPC_Damage")]
		public static class MineRock5_Damage_Patch
		{
			public static bool Prefix(MineRock5 __instance, long sender, ref HitData hit)
			{
				//IL_0050: 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 ((Object)(object)__instance == (Object)null || hit == null)
				{
					return false;
				}
				if ((Object)(object)hit.GetAttacker() != (Object)null && hit.GetAttacker().IsPlayer())
				{
					return Skyla.CheckAccess(hit.GetAttacker(), ((Component)__instance).transform.position, Skyla.ActionType.ACTION_DAMAGE);
				}
				float num = 1f - Skyla.FindMaxSkylaPower(((Component)__instance).transform.position);
				if ((double)num <= 0.0)
				{
					return false;
				}
				hit.ApplyModifier(num);
				return true;
			}
		}
	}
	[BepInPlugin("Tali.Skyla", "Skyla", "0.8.0")]
	public class Mod : BaseUnityPlugin
	{
		public const string ModGuid = "Tali.Skyla";

		private const string AuthorName = "Tali";

		private const string ModName = "Skyla";

		private const string ModVer = "0.8.0";

		private readonly ConfigSync configSync = new ConfigSync("Skyla")
		{
			DisplayName = "Skyla",
			CurrentVersion = "0.8.0",
			MinimumRequiredVersion = "0.8.0",
			ModRequired = true
		};

		private Harmony _harmony;

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			SkylaConfig.SetupConfig(this);
			configSync.IsLocked = true;
			SetupWatcher();
			_harmony = new Harmony("Tali.Skyla");
			_harmony.PatchAll();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.Trader_Start_Patch)).Patch();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.Trader_Interact_Patch)).Patch();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_Show_Patch)).Patch();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_FillList_Patch)).Patch();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_CanAfford_Patch)).Patch();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_BuySelectedItem_Patch)).Patch();
			_harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_UpdateBuyButton_Patch)).Patch();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ChimeTrader Harmony hooks registered.");
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (ZNet.instance.IsServer() && File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
		}

		public ConfigEntry<T> SyncedConfig<T>(string group, string name, T defaultVal, string desc)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, defaultVal, new ConfigDescription(desc, (AcceptableValueBase)null, Array.Empty<object>()));
			configSync.AddConfigEntry<T>(val).SynchronizedConfig = true;
			return val;
		}
	}
	internal class ParticleMist_Patch
	{
	}
	public class PerkConfig
	{
		public enum WeatherMode
		{
			WEATHER_NONE,
			WEATHER_SNOW,
			WEATHER_STORM,
			WEATHER_SNOWSTORM,
			WEATHER_MISTLANDS_STORM,
			WEATHER_ASHRAIN,
			WEATHER_CLEAR,
			WEATHER_MAX
		}

		public class Farming
		{
			public const float c_harvestIncreaseProbability = 0.5f;

			public const int c_harvestIncrease = 1;

			public const float c_growTimeFactor = 0.8f;
		}

		public class Cooking
		{
			public const float c_fuelBurnRateFactor = 0.5f;

			public const float c_cookingTimeFactor = 0.8f;
		}

		public class Comfort
		{
			public const int c_comfortBoost = 3;
		}

		public class Industry
		{
			public const float c_fuelBurnRateFactor = 0.5f;

			public const float c_bakeRateFactor = 1.2f;
		}

		public static Dictionary<string, Skyla.ChimeType> s_chimeMap = new Dictionary<string, Skyla.ChimeType>
		{
			{
				"Chime of Fertility",
				Skyla.ChimeType.CHIME_FARMING
			},
			{
				"Chime of the Hearth",
				Skyla.ChimeType.CHIME_COOKING
			},
			{
				"Chime of Comfort",
				Skyla.ChimeType.CHIME_COMFORT
			},
			{
				"Chime of Industry",
				Skyla.ChimeType.CHIME_INDUSTRY
			},
			{
				"Snow Chime",
				Skyla.ChimeType.CHIME_SNOW
			},
			{
				"Blizzard Chime",
				Skyla.ChimeType.CHIME_SNOWSTORM
			},
			{
				"Chime of Ashes",
				Skyla.ChimeType.CHIME_ASHRAIN
			},
			{
				"Storm Chime",
				Skyla.ChimeType.CHIME_STORM
			},
			{
				"Tempest Chime",
				Skyla.ChimeType.CHIME_MISTLANDS_STORM
			},
			{
				"Balmy Chime",
				Skyla.ChimeType.CHIME_CLEAR
			}
		};

		public static Dictionary<Skyla.ChimeType, GameObject> s_chimePrefabMap = new Dictionary<Skyla.ChimeType, GameObject>();

		public static Dictionary<Skyla.ChimeType, string> s_powerNameMap = new Dictionary<Skyla.ChimeType, string>
		{
			{
				Skyla.ChimeType.CHIME_FARMING,
				"Fertility"
			},
			{
				Skyla.ChimeType.CHIME_COOKING,
				"Hearth"
			},
			{
				Skyla.ChimeType.CHIME_COMFORT,
				"Comfort"
			},
			{
				Skyla.ChimeType.CHIME_INDUSTRY,
				"Industry"
			}
		};

		public static Dictionary<WeatherMode, string> s_weatherNameMap = new Dictionary<WeatherMode, string>
		{
			{
				WeatherMode.WEATHER_NONE,
				"<none>"
			},
			{
				WeatherMode.WEATHER_CLEAR,
				"Clear"
			},
			{
				WeatherMode.WEATHER_SNOW,
				"Snow"
			},
			{
				WeatherMode.WEATHER_STORM,
				"Storm"
			},
			{
				WeatherMode.WEATHER_SNOWSTORM,
				"Blizzard"
			},
			{
				WeatherMode.WEATHER_MISTLANDS_STORM,
				"Tempest"
			},
			{
				WeatherMode.WEATHER_ASHRAIN,
				"Ashrain"
			}
		};

		public static string GetChimeDisplayName(Skyla.ChimeType chime)
		{
			return chime switch
			{
				Skyla.ChimeType.CHIME_FARMING => "Fertility", 
				Skyla.ChimeType.CHIME_COOKING => "Hearth", 
				Skyla.ChimeType.CHIME_COMFORT => "Comfort", 
				Skyla.ChimeType.CHIME_INDUSTRY => "Industry", 
				Skyla.ChimeType.CHIME_VIGOUR => "Vigour", 
				Skyla.ChimeType.CHIME_WARMTH => "Warmth", 
				Skyla.ChimeType.CHIME_EMBERS => "Embers", 
				Skyla.ChimeType.CHIME_CLEAR => "Balmy", 
				Skyla.ChimeType.CHIME_SNOW => "Snow", 
				Skyla.ChimeType.CHIME_SNOWSTORM => "Blizzard", 
				Skyla.ChimeType.CHIME_STORM => "Storm", 
				Skyla.ChimeType.CHIME_MISTLANDS_STORM => "Tempest", 
				Skyla.ChimeType.CHIME_ASHRAIN => "Ashes", 
				_ => chime.ToString(), 
			};
		}

		public static string GetChimeEffect(Skyla.ChimeType chime)
		{
			return chime switch
			{
				Skyla.ChimeType.CHIME_FARMING => "Plants grow ~20% faster, with a chance of bonus harvest.", 
				Skyla.ChimeType.CHIME_COOKING => "Cooking is faster and cook stations burn half as much fuel.", 
				Skyla.ChimeType.CHIME_COMFORT => $"+{3} comfort while resting in range.", 
				Skyla.ChimeType.CHIME_INDUSTRY => "Smelters and kilns run faster and use half the fuel.", 
				Skyla.ChimeType.CHIME_VIGOUR => $"Everything you do in range costs ~{25}% less stamina.", 
				Skyla.ChimeType.CHIME_WARMTH => "Cold and Freezing cannot take hold inside the Skýla range.", 
				Skyla.ChimeType.CHIME_EMBERS => "Fires and torches in range never burn through their fuel.", 
				Skyla.ChimeType.CHIME_CLEAR => "Forces clear skies inside the Skýla range.", 
				Skyla.ChimeType.CHIME_SNOW => "Forces snow weather inside the Skýla range.", 
				Skyla.ChimeType.CHIME_SNOWSTORM => "Forces a blizzard inside the Skýla range.", 
				Skyla.ChimeType.CHIME_STORM => "Forces storm weather inside the Skýla range.", 
				Skyla.ChimeType.CHIME_MISTLANDS_STORM => "Forces the Mistlands tempest inside the Skýla range.", 
				Skyla.ChimeType.CHIME_ASHRAIN => "Forces ashrain weather inside the Skýla range.", 
				_ => "", 
			};
		}

		public static string GetWeatherEffect(WeatherMode mode)
		{
			return mode switch
			{
				WeatherMode.WEATHER_NONE => "No forced weather. The sky follows the normal biome.", 
				WeatherMode.WEATHER_CLEAR => GetChimeEffect(Skyla.ChimeType.CHIME_CLEAR), 
				WeatherMode.WEATHER_SNOW => GetChimeEffect(Skyla.ChimeType.CHIME_SNOW), 
				WeatherMode.WEATHER_STORM => GetChimeEffect(Skyla.ChimeType.CHIME_STORM), 
				WeatherMode.WEATHER_SNOWSTORM => GetChimeEffect(Skyla.ChimeType.CHIME_SNOWSTORM), 
				WeatherMode.WEATHER_MISTLANDS_STORM => GetChimeEffect(Skyla.ChimeType.CHIME_MISTLANDS_STORM), 
				WeatherMode.WEATHER_ASHRAIN => GetChimeEffect(Skyla.ChimeType.CHIME_ASHRAIN), 
				_ => "", 
			};
		}
	}
	[HarmonyPatch(typeof(PickableItem), "Interact")]
	public static class PickableItem_Interact_Patch
	{
		public static bool Prefix(PickableItem __instance, Humanoid character, bool repeat, bool alt)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetBool("ProtectedPickable", false))
			{
				return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_PICKABLE);
			}
			return true;
		}
	}
	internal class PickablePatch
	{
		[HarmonyPatch(typeof(Pickable), "Interact")]
		public static class Pickable_Interact_Patch
		{
			public static bool Prefix(Pickable __instance, Humanoid character, bool repeat, bool alt)
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return false;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					return true;
				}
				__instance.m_amount += component.GetZDO().GetInt("HarvestAmountOverride", __instance.m_amount);
				if (component.GetZDO().GetBool("ProtectedPickable", false))
				{
					return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_PICKABLE);
				}
				return true;
			}
		}
	}
	internal class PiecePatch
	{
		[HarmonyPatch(typeof(Piece), "DropResources")]
		public static class Piece_DropResources_Patch
		{
			public static void Postfix(Piece __instance)
			{
				Skyla component = ((Component)__instance).GetComponent<Skyla>();
				if (!((Object)(object)component == (Object)null))
				{
					component.DropResources();
				}
			}
		}

		[HarmonyPatch(typeof(Piece), "SetCreator")]
		public static class Piece_SetCreator_Patch
		{
			public static void Postfix(Piece __instance, long uid)
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					Skyla component2 = ((Component)__instance).gameObject.GetComponent<Skyla>();
					if (!((Object)(object)component2 == (Object)null))
					{
						component2.OnPlaced(uid);
					}
				}
			}
		}
	}
	internal class PlantPatch
	{
		[HarmonyPatch(typeof(Plant), "Grow")]
		public static class Plant_Grow_Patch
		{
			public static void Postfix(Plant __instance, ref GameObject __result)
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || (Object)(object)__result == (Object)null)
				{
					return;
				}
				ZNetView component = __result.GetComponent<ZNetView>();
				if (!((Object)(object)__result.GetComponent<Pickable>() == (Object)null) && !((Object)(object)component == (Object)null))
				{
					component.GetZDO().Set("ProtectedPickable", true);
					if (Skyla.ChimeApplies(((Component)__instance).gameObject.transform.position, Skyla.ChimeType.CHIME_FARMING) && !((double)Random.value >= 0.5))
					{
						component.GetZDO().Set("HarvestAmountOverride", 1);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Plant), "GetGrowTime")]
		public static class Plant_GetGrowTime_Patch
		{
			public static void Postfix(Plant __instance, ref float __result)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				if (Skyla.ChimeApplies(((Component)__instance).gameObject.transform.position, Skyla.ChimeType.CHIME_FARMING))
				{
					__result *= 0.8f;
				}
			}
		}
	}
	public class PlayerPatch
	{
		[HarmonyPatch(typeof(Player), "OnSpawned")]
		public static class Player_OnSpawned_Patch
		{
			public static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					LocalManager.RequestInfo(Player.m_localPlayer.GetPlayerID());
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnRespawn")]
		public static class Player_OnRespawn_Patch
		{
			public static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					LocalManager.RequestInfo(Player.m_localPlayer.GetPlayerID());
				}
			}
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		public static class Player_CheckCanRemovePiece_Patch
		{
			public static bool Prefix(Player __instance, Piece piece)
			{
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return false;
				}
				Vagon component = ((Component)piece).gameObject.GetComponent<Vagon>();
				if ((Object)(object)component != (Object)null)
				{
					return Skyla.CanUseWagon(component, (Character)(object)__instance);
				}
				Ship component2 = ((Component)piece).gameObject.GetComponent<Ship>();
				if ((Object)(object)component2 != (Object)null)
				{
					return Skyla.CanUseShip(component2, (Character)(object)__instance);
				}
				Skyla component3 = ((Component)piece).gameObject.GetComponent<Skyla>();
				if ((Object)(object)component3 != (Object)null)
				{
					return component3.IsPermitted((Character)(object)__instance, Skyla.ActionType.ACTION_REMOVE_SKYLA);
				}
				return Skyla.CheckAccess((Character)(object)__instance, ((Component)piece).transform.position, Skyla.ActionType.ACTION_BUILD);
			}
		}

		[HarmonyPatch(typeof(Player), "AutoPickup")]
		public static class Player_AutoPickup_Patch
		{
			public static bool Prefix(Player __instance, float dt)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)__instance, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_AUTO_PICKUP);
				}
				return false;
			}
		}
	}
	public class ServerManager
	{
		private static bool s_initialized = false;

		private static Dictionary<long, HashSet<ZDO>> s_playerSkylaMap = new Dictionary<long, HashSet<ZDO>>();

		private static Dictionary<string, float> s_playerMaxTotalArea = new Dictionary<string, float>();

		private static string s_vipPlayerFileName = "skyla_area_overrides.txt";

		public static void Initialize()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			List<ZDO> list = new List<ZDO>();
			if (!ZNet.instance.IsServer() || s_initialized)
			{
				return;
			}
			int num = 0;
			while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(Skyla.s_prefabName, list, ref num))
			{
			}
			foreach (ZDO item in list)
			{
				long playerID = item.GetLong("creator", 0L);
				if (float.IsNaN(item.GetFloat("SkylaRadius", 0f)))
				{
					Debug.Log((object)$"Skyla ServerManager :: Fixing NaN Skyla at {item.GetPosition()}");
					item.Set("SkylaRadius", 0f);
				}
				ZDO ward = item;
				RegisterSkyla(playerID, ward);
			}
			Debug.Log((object)string.Format("SkylaManager::Initialize - found {0} {1} ZDOs", list.Count, "Skýla"));
			LoadSpecialPlayerList();
			s_initialized = true;
		}

		public static void LoadSpecialPlayerList()
		{
			Debug.Log((object)"SkylaManager :: Loading Player Override List");
			string path = Path.Combine(Paths.ConfigPath, s_vipPlayerFileName);
			Dictionary<string, float> dictionary = new Dictionary<string, float>();
			if (!File.Exists(path))
			{
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(path);
				foreach (string text in array)
				{
					if (text.StartsWith("//"))
					{
						continue;
					}
					string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					if (array2.Length == 2)
					{
						try
						{
							string key = array2[0];
							float val = float.Parse(array2[1]);
							dictionary.Add(key, Math.Max(0f, val));
						}
						catch
						{
						}
					}
				}
			}
			catch
			{
				return;
			}
			s_playerMaxTotalArea = dictionary;
		}

		public static void RegisterRPC()
		{
			ZRoutedRpc.instance.Register<ZDOID>("RegisterSkyla", (Action<long, ZDOID>)RPC_RegisterSkyla);
			ZRoutedRpc.instance.Register<ZDOID>("UnregisterSkyla", (Action<long, ZDOID>)RPC_UnregisterSkyla);
			ZRoutedRpc.instance.Register<long>("RequestInfo", (Action<long, long>)RPC_RequestInfo);
		}

		private static float GetMaxAreaForPlayer(string steamID)
		{
			if (s_playerMaxTotalArea.ContainsKey(steamID))
			{
				return s_playerMaxTotalArea[steamID];
			}
			return SkylaConfig.TotalAreaLimit();
		}

		public static float GetMaxRadiusForSkylaZdo(ZDO ward)
		{
			if (ward == null)
			{
				return SkylaConfig.MaxSkylaRadius();
			}
			long playerID = ward.GetLong("creator", 0L);
			float num = ward.GetFloat("SkylaRadius", 0f);
			float usedArea = GetUsedArea(playerID);
			float num2 = Mathf.Max(0f, usedArea - (float)Math.PI * num * num);
			float num3 = (float)Math.Sqrt((double)Mathf.Max(0f, SkylaConfig.TotalAreaLimit() - num2) / 3.1415927410125732);
			return Mathf.Min(SkylaConfig.MaxSkylaRadius(), num3);
		}

		private static string GetSteamIDForPeer(long sender)
		{
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			string text = "<unknown>";
			if (peer != null)
			{
				text = peer.m_socket.GetHostName();
				Debug.Log((object)("SkylaManager :: Finding SteamID for player " + peer.m_playerName + " :: got " + text));
			}
			if (!text.StartsWith("Steam_"))
			{
				return text;
			}
			return text.Substring(6);
		}

		private static void RPC_RequestInfo(long sender, long playerID)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			long num = SkylaNet.ResolvePlayerId(sender);
			if (num != 0L)
			{
				playerID = num;
			}
			if (s_playerSkylaMap.ContainsKey(playerID))
			{
				_ = s_playerSkylaMap[playerID].Count;
			}
			Initialize();
			LoadSpecialPlayerList();
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "ReceiveServerSkylaData", new object[2]
			{
				GetMaxAreaForPlayer(GetSteamIDForPeer(sender)),
				EncodeWards(playerID)
			});
			if (!s_playerSkylaMap.ContainsKey(playerID))
			{
				return;
			}
			foreach (ZDO item in s_playerSkylaMap[playerID])
			{
				ZDOMan.instance.ForceSendZDO(sender, item.m_uid);
			}
		}

		private static ZPackage EncodeWards(long playerID)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			if (s_playerSkylaMap.ContainsKey(playerID))
			{
				Debug.Log((object)string.Format("SkylaManager :: Encoding data of {0} {1} for playerID {2}", s_playerSkylaMap[playerID].Count, "Skýla", playerID));
				val.Write(s_playerSkylaMap[playerID].Count);
				foreach (ZDO item in s_playerSkylaMap[playerID])
				{
					val.Write(item.m_uid);
				}
			}
			else
			{
				val.Write(0);
			}
			return val;
		}

		private static float GetUsedArea(long playerID)
		{
			float num = 0f;
			if (s_playerSkylaMap.ContainsKey(playerID))
			{
				foreach (ZDO item in s_playerSkylaMap[playerID])
				{
					float num2 = item.GetFloat("SkylaRadius", 0f);
					num += (float)Math.PI * num2 * num2;
				}
			}
			return num;
		}

		private static float GetRemainingAreaBudget(long playerID)
		{
			return SkylaConfig.TotalAreaLimit() - GetUsedArea(playerID);
		}

		private static void RegisterSkyla(long playerID, ZDO ward)
		{
			if (!s_playerSkylaMap.ContainsKey(playerID))
			{
				s_playerSkylaMap.Add(playerID, new HashSet<ZDO>());
			}
			s_playerSkylaMap[playerID].Add(ward);
		}

		private static void RPC_RegisterSkyla(long sender, ZDOID ward)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(ward);
			if (zDO != null)
			{
				long num = zDO.GetLong("creator", 0L);
				long num2 = SkylaNet.ResolvePlayerId(sender);
				if (num2 == 0L || num == 0L || num2 == num)
				{
					RegisterSkyla(num, zDO);
				}
			}
		}

		private static void UnregisterSkyla(long playerID, ZDO ward)
		{
			if (s_playerSkylaMap.ContainsKey(playerID))
			{
				s_playerSkylaMap[playerID].Remove(ward);
			}
		}

		private static void RPC_UnregisterSkyla(long sender, ZDOID ward)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(ward);
			if (zDO != null)
			{
				long num = zDO.GetLong("creator", 0L);
				long num2 = SkylaNet.ResolvePlayerId(sender);
				if (num2 == 0L || num == 0L || num2 == num)
				{
					UnregisterSkyla(num, zDO);
				}
			}
		}
	}
	internal class SE_Rested_Patch
	{
		[HarmonyPatch(typeof(SE_Rested), "CalculateComfortLevel", new Type[]
		{
			typeof(bool),
			typeof(Vector3)
		})]
		public static class FE_Resteed_CalculateComfortLevel_Patch
		{
			public static void Postfix(bool inShelter, Vector3 position, ref int __result)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				if (Skyla.ChimeApplies(position, Skyla.ChimeType.CHIME_COMFORT))
				{
					__result += 3;
				}
			}
		}
	}
	internal class ShipControlsPatch
	{
		[HarmonyPatch(typeof(ShipControlls), "Interact")]
		public static class ShipControlls_Interact_Patch
		{
			public static bool Prefix(ShipControlls __instance, Humanoid character, bool repeat, bool alt)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return false;
				}
				if (!IsCreator(__instance.m_ship, (Player)(object)((character is Player) ? character : null)))
				{
					return Skyla.CanUseShip(__instance.m_ship, (Character)(object)character);
				}
				return true;
			}
		}

		private static bool IsCreator(Ship v, Player p)
		{
			if ((Object)(object)v != (Object)null && (Object)(object)p != (Object)null)
			{
				return ((Component)v).gameObject.GetComponent<Piece>().GetCreator() == p.GetPlayerID();
			}
			return false;
		}
	}
	internal class SignPatch
	{
		[HarmonyPatch(typeof(Sign), "Interact")]
		public static class Sign_Interact_Patch
		{
			public static bool Prefix(Sign __instance, Humanoid character, bool hold, bool alt)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)null)
				{
					return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_SIGN);
				}
				return false;
			}
		}
	}
	public class Skyla : MonoBehaviour, Hoverable, Interactable
	{
		public enum ActionType
		{
			ACTION_NONE,
			ACTION_CONTROL_SKYLA,
			ACTION_REMOVE_SKYLA,
			ACTION_DAMAGE,
			ACTION_BUILD,
			ACTION_TERRAIN_MODIFICATION,
			ACTION_USE_PORTAL,
			ACTION_USE_CONTAINER,
			ACTION_USE_DOOR,
			ACTION_USE_SIGN,
			ACTION_USE_ITEMSTAND,
			ACTION_USE_FERMENTER,
			ACTION_USE_BEEHIVE,
			ACTION_PICKUP_FACTORY_OUTPUT,
			ACTION_AUTO_PICKUP,
			ACTION_PICKABLE,
			ACTION_USE_SHIP,
			ACTION_USE_WAGON,
			PROTECTION_WEATHER,
			PROTECTION_MIST
		}

		public enum ChimeType
		{
			CHIME_FARMING = 0,
			CHIME_COOKING = 1,
			CHIME_STABILITY = 2,
			CHIME_COMFORT = 4,
			CHIME_INDUSTRY = 5,
			CHIME_VIGOUR = 3,
			CHIME_WARMTH = 6,
			CHIME_EMBERS = 7,
			CHIME_STORM = 10,
			CHIME_SNOW = 11,
			CHIME_SNOWSTORM = 12,
			CHIME_MISTLANDS_STORM = 13,
			CHIME_ASHRAIN = 14,
			CHIME_CLEAR = 15
		}

		[HarmonyPatch(typeof(ZDOMan), "Load")]
		public class ZDOMan_Load_Patch
		{
			public static void Postfix(ZDOMan __instance)
			{
				ServerManager.Initialize();
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		public class ZNetScene_Awake_Patch
		{
			public static void Postfix(ZNetScene __instance)
			{
				GameObject prefab = __instance.GetPrefab(s_prefabName);
				if ((Object)(object)prefab != (Object)null)
				{
					s_skylaPrefab = prefab;
					if ((Object)(object)prefab.GetComponent<Skyla>() == (Object)null)
					{
						prefab.AddComponent<Skyla>();
					}
				}
				AddToHammer(s_skylaPrefab);
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		public static class ZNetAwakePatch
		{
			public static void Postfix(ZNet __instance)
			{
				ServerManager.RegisterRPC();
				LocalManager.RegisterRPC();
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Destroy")]
		private static class ZNetScene_Destroy_Patch
		{
			private static bool Prefix(ZNetScene __instance, GameObject go)
			{
				Skyla component = go.GetComponent<Skyla>();
				if ((Object)(object)component != (Object)null)
				{
					LocalManager.RemoveSkyla(component.m_nview.GetZDO());
				}
				return true;
			}
		}

		private static GameObject s_skylaPrefab;

		private static float s_defaultSkylaRadius = 15f;

		private static Skyla s_lastHovered;

		private static float s_lastHoveredTime;

		private const float c_fullLightIntensity = 3f;

		private const float c_fullRuneIntensity = 4.8f;

		private const float c_halfHeight = 50f;

		private const int c_pulseTimeSecs = 4;

		public static ISet<Skyla> s_localSkylaList = new HashSet<Skyla>();

		public static string s_prefabName = "RunicSkyla";

		public const string c_skylaName = "Runic Skýla";

		public const string c_skylaShortName = "Skýla";

		public const string c_permittedName = "Vinir";

		private const string c_zdoSkylaPower = "SkylaPower";

		private const string c_zdoIsActive = "IsActive";

		public const string c_zdoSkylaRadius = "SkylaRadius";

		public const string c_zdoPieceCreator = "creator";

		public const string c_zdoProtectedItemDrop = "ProtectedItem";

		public const string c_zdoProtectedPickable = "ProtectedPickable";

		public const string c_zdoHarvestBonus = "HarvestAmountOverride";

		public const string c_zdoChimeBitvector = "ChimesData";

		public const string c_zdoWeatherMode = "WeatherMode";

		private static Dictionary<ActionType, string> s_zdoAccessMap = new Dictionary<ActionType, string>
		{
			{
				ActionType.ACTION_USE_CONTAINER,
				"public_use_container"
			},
			{
				ActionType.ACTION_USE_DOOR,
				"public_use_door"
			},
			{
				ActionType.ACTION_USE_SIGN,
				"public_use_sign"
			},
			{
				ActionType.ACTION_USE_ITEMSTAND,
				"public_use_itemstand"
			},
			{
				ActionType.ACTION_USE_BEEHIVE,
				"public_use_beehive"
			},
			{
				ActionType.ACTION_USE_FERMENTER,
				"public_use_fermenter"
			},
			{
				ActionType.ACTION_PICKUP_FACTORY_OUTPUT,
				"public_pickup_factory"
			},
			{
				ActionType.ACTION_PICKABLE,
				"public_pickable"
			},
			{
				ActionType.ACTION_USE_SHIP,
				"public_use_ship"
			},
			{
				ActionType.ACTION_USE_WAGON,
				"public_use_wagon"
			},
			{
				ActionType.PROTECTION_WEATHER,
				"weather_protection"
			},
			{
				ActionType.PROTECTION_MIST,
				"mist_protection"
			}
		};

		public static Dictionary<ChimeType, PerkConfig.WeatherMode> s_weatherChimeMap = new Dictionary<ChimeType, PerkConfig.WeatherMode>
		{
			{
				ChimeType.CHIME_STORM,
				PerkConfig.WeatherMode.WEATHER_STORM
			},
			{
				ChimeType.CHIME_SNOW,
				PerkConfig.WeatherMode.WEATHER_SNOW
			},
			{
				ChimeType.CHIME_SNOWSTORM,
				PerkConfig.WeatherMode.WEATHER_SNOWSTORM
			},
			{
				ChimeType.CHIME_MISTLANDS_STORM,
				PerkConfig.WeatherMode.WEATHER_MISTLANDS_STORM
			},
			{
				ChimeType.CHIME_ASHRAIN,
				PerkConfig.WeatherMode.WEATHER_ASHRAIN
			},
			{
				ChimeType.CHIME_CLEAR,
				PerkConfig.WeatherMode.WEATHER_CLEAR
			}
		};

		private MeshRenderer m_model;

		private ZNetView m_nview;

		private Light m_lightSource;

		private Piece m_piece;

		private CircleProjector m_circleProjector;

		private DateTime m_awakeTime;

		public const int ActiveUtilityNone = -1;

		private const int ActiveUtilityUnset = -999;

		public float GetSkylaPower()
		{
			if (m_nview.IsValid() && IsActive())
			{
				return m_nview.GetZDO().GetFloat("SkylaPower", 0f);
			}
			return 0f;
		}

		public float GetRadius()
		{
			if (m_nview.IsValid())
			{
				return m_nview.GetZDO().GetFloat("SkylaRadius", 0f);
			}
			return 0f;
		}

		public void SetRadius(float radius)
		{
			if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid())
			{
				radius = ClampRadius(radius);
				if (m_nview.IsOwner())
				{
					SetRadiusLocal(radius);
					return;
				}
				m_nview.InvokeRPC("SetRadius", new object[1] { radius });
			}
		}

		private void SetRadiusLocal(float radius)
		{
			m_nview.GetZDO().Set("SkylaRadius", radius);
		}

		private float ClampRadius(float radius)
		{
			float num = SkylaConfig.MaxSkylaRadius();
			num = ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()) ? Mathf.Min(num, LocalManager.GetMaxRadiusForSkyla(this)) : Mathf.Min(num, ServerManager.GetMaxRadiusForSkylaZdo(m_nview.GetZDO())));
			return Mathf.Clamp(radius, 0f, Mathf.Max(0f, num));
		}

		private double GetDeltaTime()
		{
			DateTime time = ZNet.instance.GetTime();
			DateTime dateTime = new DateTime(m_nview.GetZDO().GetLong("SkylaTime", time.Ticks));
			double totalSeconds = (time - dateTime).TotalSeconds;
			m_nview.GetZDO().Set("SkylaTime", time.Ticks);
			return totalSeconds;
		}

		private void Awake()
		{
			m_awakeTime = DateTime.Now;
			m_piece = ((Component)this).GetComponent<Piece>();
			m_lightSource = ((Component)this).GetComponent<Light>();
			m_circleProjector = ((Component)this).GetComponentInChildren<CircleProjector>();
			if ((Object)(object)m_circleProjector != (Object)null)
			{
				((Component)m_circleProjector).gameObject.SetActive(false);
			}
			m_nview = ((Component)this).GetComponent<ZNetView>();
			if (!m_nview.IsValid() || m_nview.GetZDO() == null)
			{
				return;
			}
			s_localSkylaList.Add(this);
			((MonoBehaviour)this).InvokeRepeating("UpdateState", 0f, 1f);
			if (string.IsNullOrEmpty(m_nview.GetZDO().GetString("CreatorName", "")) && m_nview.IsOwner())
			{
				Player player = Player.GetPlayer(m_piece.GetCreator());
				if ((Object)(object)player != (Object)null)
				{
					m_nview.GetZDO().Set("CreatorName", player.GetPlayerName());
				}
			}
			m_nview.Register("ToggleEnabled", (Action<long>)RPC_ToggleEnabled);
			m_nview.Register<long>("TogglePermitted", (Action<long, long>)RPC_TogglePermitted);
			m_nview.Register<int>("AddChime", (Action<long, int>)RPC_AddChime);
			m_nview.Register<float>("SetRadius", (Action<long, float>)RPC_SetRadius);
			m_nview.Register<int, bool>("SetPublicSetting", (Action<long, int, bool>)RPC_SetPublicSetting);
			m_nview.Register<int>("SetWeatherMode", (Action<long, int>)RPC_SetWeatherMode);
			m_nview.Register<int>("SetActiveUtilityChime", (Action<long, int>)RPC_SetActiveUtilityChime);
			m_nview.Register<long>("RequestSetup", (Action<long, long>)RPC_RequestSetup);
			m_nview.Register<bool>("RequestSetupResponse", (Action<long, bool>)RPC_RequestSetupResponse);
			LocalManager.AddSkyla(m_nview.GetZDO());
			if (m_nview.IsOwner() && !m_nview.GetZDO().GetBool("SkylaRadiusInit", false))
			{
				if ((double)m_nview.GetZDO().GetFloat("SkylaRadius", 0f) <= 0.0)
				{
					float maxRadiusForSkyla = LocalManager.GetMaxRadiusForSkyla(this);
					float num = Mathf.Min(s_defaultSkylaRadius, maxRadiusForSkyla);
					m_nview.GetZDO().Set("SkylaRadius", Mathf.Max(0f, num));
				}
				m_nview.GetZDO().Set("SkylaRadiusInit", true);
			}
			if (!m_nview.IsOwner() || m_nview.GetZDO().GetBool("SkylaDefaultsInit", false))
			{
				return;
			}
			foreach (KeyValuePair<ActionType, string> item in s_zdoAccessMap)
			{
				m_nview.GetZDO().Set(item.Value, true);
			}
			m_nview.GetZDO().Set("WeatherMode", 0);
			m_nview.GetZDO().Set("SkylaDefaultsInit", true);
		}

		private void OnDestroy()
		{
			s_localSkylaList.Remove(this);
		}

		private void UpdateState()
		{
			if (m_nview.IsValid() && m_nview.IsOwner())
			{
				float num = Mathf.Clamp((float)GetDeltaTime(), 0f, 5f);
				if (IsActive())
				{
					float num2 = Mathf.Min(1f, GetSkylaPower() + num / (float)SkylaConfig.PowerUpTimeSecs());
					m_nview.GetZDO().Set("SkylaPower", num2);
				}
			}
		}

		private void Update()
		{
			UpdateVFX();
			UpdateMarker();
		}

		private void UpdateVFX()
		{
			//IL_0029: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)m_model == (Object)null)
			{
				m_model = ((Component)this).GetComponentInChildren<MeshRenderer>();
			}
			if (!((Object)(object)m_model == (Object)null))
			{
				Color val = Color.white * 4.8f;
				val.a = 1f;
				Color val2 = val;
				float num = (float)(DateTime.Now - m_awakeTime).TotalSeconds;
				float skylaPower = GetSkylaPower();
				float num2 = 0f;
				if (IsActive())
				{
					num2 = (((double)skylaPower < 1.0) ? ((float)(Math.Cos((double)num / 4.0 * Math.PI * 2.0) * 0.5 + 0.5) * skylaPower) : 1f);
				}
				((Renderer)m_model).material.SetColor("_EmissionColor", Color.Lerp(Color.black, val2, num2));
				if ((Object)(object)m_lightSource != (Object)null)
				{
					m_lightSource.intensity = 3f * num2;
				}
			}
		}

		private void UpdateMarker()
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)m_circleProjector == (Object)null))
			{
				float radius = GetRadius();
				bool active = ((Character)Player.m_localPlayer).InPlaceMode() && m_nview.IsValid() && (double)radius > 0.0;
				m_circleProjector.m_radius = radius;
				((Component)m_circleProjector).gameObject.SetActive(active);
			}
		}

		public bool IsActive()
		{
			if (m_nview.IsValid())
			{
				return m_nview.GetZDO().GetBool("IsActive", false);
			}
			return false;
		}

		public void SetActive(bool active)
		{
			if (!m_nview.IsValid())
			{
				return;
			}
			bool flag = m_nview.GetZDO().GetBool("IsActive", false);
			m_nview.GetZDO().Set("IsActive", active);
			if (!(!active || flag))
			{
				if (!m_nview.GetZDO().GetBool("SkylaEverCharged", false) || !SkylaConfig.PersistChargeOnToggle())
				{
					m_nview.GetZDO().Set("SkylaPower", 0f);
				}
				m_nview.GetZDO().Set("SkylaEverCharged", true);
				long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().Ticks : DateTime.Now.Ticks);
				m_nview.GetZDO().Set("SkylaTime", num);
			}
		}

		internal static Skyla GetRecentlyHovered(float maxAgeSeconds = 2.5f)
		{
			if ((Object)(object)s_lastHovered == (Object)null)
			{
				return null;
			}
			if (!((double)Time.time - (double)s_lastHoveredTime > (double)maxAgeSeconds))
			{
				return s_lastHovered;
			}
			return null;
		}

		private List<KeyValuePair<long, string>> GetPermittedPlayers()
		{
			List<KeyValuePair<long, string>> list = new List<KeyValuePair<long, string>>();
			if (!m_nview.IsValid())
			{
				return list;
			}
			int num = m_nview.GetZDO().GetInt("permitted", 0);
			for (int i = 0; i < num; i++)
			{
				long num2 = m_nview.GetZDO().GetLong("pu_id" + i, 0L);
				string value = m_nview.GetZDO().GetString("pu_name" + i, "");
				if (num2 != 0L)
				{
					list.Add(new KeyValuePair<long, string>(num2, value));
				}
			}
			return list;
		}

		private void SetPermittedPlayers(List<KeyValuePair<long, string>> users)
		{
			if (m_nview.IsValid())
			{
				m_nview.GetZDO().Set("permitted", users.Count);
				for (int i = 0; i < users.Count; i++)
				{
					ZDO zDO = m_nview.GetZDO();
					string text = "pu_id" + i;
					long key = users[i].Key;
					zDO.Set(text, key);
					ZDO zDO2 = m_nview.GetZDO();
					string text2 = "pu_name" + i;
					string value = users[i].Value;
					zDO2.Set(text2, value);
				}
			}
		}

		private bool IsPermitted(long playerID)
		{
			if (m_piece.GetCreator() == playerID)
			{
				return true;
			}
			foreach (KeyValuePair<long, string> permittedPlayer in GetPermittedPlayers())
			{
				if (permittedPlayer.Key == playerID)
				{
					return true;
				}
			}
			return false;
		}

		private void AddPermitted(long playerID, string playerName)
		{
			List<KeyValuePair<long, string>> permittedPlayers = GetPermittedPlayers();
			if (!permittedPlayers.Exists((KeyValuePair<long, string> x) => x.Key == playerID))
			{
				permittedPlayers.Add(new KeyValuePair<long, string>(playerID, playerName));
				SetPermittedPlayers(permittedPlayers);
			}
		}

		private void RemovePermitted(long playerID)
		{
			List<KeyValuePair<long, string>> permittedPlayers = GetPermittedPlayers();
			if (permittedPlayers.RemoveAll((KeyValuePair<long, string> x) => x.Key == playerID) > 0)
			{
				SetPermittedPlayers(permittedPlayers);
			}
		}

		public string GetHoverName()
		{
			return "Skýla";
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public string GetHoverText()
		{
			if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid())
			{
				return "";
			}
			s_lastHovered = this;
			s_lastHoveredTime = Time.time;
			string text = (IsActive() ? "Deactivate" : "Activate");
			string text2 = "Power: Inactive";
			if (IsActive())
			{
				float num = Mathf.Clamp01(GetSkylaPower());
				TimeSpan timeSpan = TimeSpan.FromSeconds(Math.Max(0.0, (1.0 - (double)num) * (double)SkylaConfig.PowerUpTimeSecs()));
				string arg = ((timeSpan.TotalHours >= 1.0) ? $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m" : $"{timeSpan.Minutes}m {timeSpan.Seconds}s");
				text2 = $"Power: {(float)((double)num * 100.0):0}% (full in {arg})";
			}
			return "Runic Skýla\n" + text2 + "\n[<color=yellow>E</color>] " + text + "\n[<color=yellow>Shift+E</color>] Configure\n[<color=yellow>Ctrl+E</color>] Vinir (nearest)";
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (!hold)
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null)
				{
					long playerID = val.GetPlayerID();
					if (ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true))
					{
						if (!IsOwner(playerID))
						{
							((Character)user).Message((MessageType)2, "Only the Skýla creator can manage Vinir.", 0, (Sprite)null, false);
							return true;
						}
						Player val2 = FindNearestOtherPlayer(val, 12f);
						if ((Object)(object)val2 == (Object)null)
						{
							((Character)user).Message((MessageType)2, "No nearby player to grant Vinir.", 0, (Sprite)null, false);
							return true;
						}
						bool flag = IsPermitted(val2.GetPlayerID()) && !IsOwner(val2.GetPlayerID());
						RequestTogglePermitted(val2.GetPlayerID());
						((Character)user).Message((MessageType)2, flag ? (val2.GetPlayerName() + " is no longer Vinir.") : (val2.GetPlayerName() + " is now Vinir."), 0, (Sprite)null, false);
						return true;
					}
					if (alt || ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true))
					{
						if (!IsPermitted(playerID))
						{
							((Character)user).Message((MessageType)2, "You are not permitted.", 0, (Sprite)null, false);
							return true;
						}
						GUIManager.Show(val, this);
						return true;
					}
					if