Decompiled source of WolfPack v1.1.4

WolfPack.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Networking;
using neobotics.ModSdk;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WolfPack")]
[assembly: AssemblyConfiguration("Deploy")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+430b6f314e49bff2524a1bec8a0874cf112343db")]
[assembly: AssemblyProduct("WolfPack")]
[assembly: AssemblyTitle("WolfPack")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
public sealed class ConfigurationManagerAttributes
{
	public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);

	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public CustomHotkeyDrawerFunc CustomHotkeyDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;

	public Func<object, string> ObjToStr;

	public Func<string, object> StrToObj;
}
namespace neobotics.ModSdk
{
	public class AudioHelper : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <Co_LoadAudio>d__8 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string filePath;

			public string[] audioFiles;

			public AudioHelper <>4__this;

			private UnityWebRequest <URL>5__2;

			private int <f>5__3;

			private string <clipUri>5__4;

			private string <clipName>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Co_LoadAudio>d__8(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<URL>5__2 = null;
				<clipUri>5__4 = null;
				<clipName>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				AudioHelper audioHelper = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<URL>5__2 = null;
					Logging.GetLogger().Debug("Co_LoadAudio loading files from " + filePath);
					<f>5__3 = 0;
					break;
				case 1:
					<>1__state = -1;
					if (<URL>5__2 != null)
					{
						try
						{
							AudioClip content = DownloadHandlerAudioClip.GetContent(<URL>5__2);
							audioHelper.audioClips.Add(<clipName>5__5.ToLower(), content);
						}
						catch (Exception ex)
						{
							Logging.GetLogger().Warning("Failed to load clip " + <clipUri>5__4 + ": " + ex.Message);
						}
					}
					else
					{
						Logging.GetLogger().Warning("Failed to get URL for " + <clipUri>5__4);
					}
					<clipUri>5__4 = null;
					<clipName>5__5 = null;
					<f>5__3++;
					break;
				}
				if (<f>5__3 < audioFiles.Length)
				{
					<clipUri>5__4 = new Uri(audioFiles[<f>5__3]).AbsoluteUri;
					<clipName>5__5 = audioFiles[<f>5__3].Substring(filePath.Length + 1);
					Logging.GetLogger().Debug("Loading audio clip " + <clipName>5__5);
					try
					{
						<URL>5__2 = UnityWebRequestMultimedia.GetAudioClip(<clipUri>5__4, (AudioType)0);
					}
					catch (Exception ex2)
					{
						Logging.GetLogger().Warning("Can't find audio resource: " + ex2.Message);
					}
					<>2__current = <URL>5__2.SendWebRequest();
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();

		public void Awake()
		{
			Logging.GetLogger().Debug("AudioHelper.Awake");
			LoadAudioResources();
			ZRoutedRpc.instance.Register<Vector3, string>("NeoPlayClip", (Action<long, Vector3, string>)RPC_NeoPlayClip);
		}

		public void RPC_NeoPlayClip(long sender, Vector3 sourcePoint, string clipName)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Logging.GetLogger().Debug("AudioHelper.RPC_NeoPlayClip");
			if (ZNet.instance.IsDedicated())
			{
				return;
			}
			try
			{
				NeoPlayClip(sourcePoint, clipName);
			}
			catch (Exception e)
			{
				Logging.GetLogger().Error(e, stackTrace: false);
			}
		}

		public void Play(Vector3 sourcePoint, string clipName)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Logging.GetLogger().Debug("AudioHelper.Play");
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NeoPlayClip", new object[2] { sourcePoint, clipName });
		}

		public void NeoPlayClip(Vector3 sourcePoint, string clipName)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			NeoPlayClip(sourcePoint, position, clipName);
		}

		public void NeoPlayClip(Vector3 sourcePoint, Vector3 targetPoint, string clipName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Logging.GetLogger().Debug("AudioHelper.NeoPlayClip");
			Vector3 val = sourcePoint - targetPoint;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			float num = (Vector3.Distance(sourcePoint, targetPoint) + 1f) / 10f;
			if (audioClips.TryGetValue(clipName.ToLower(), out var value))
			{
				AudioSource.PlayClipAtPoint(value, targetPoint + normalized * num, 1f);
			}
			else
			{
				Logging.GetLogger().Warning("Couldn't find audio clip for " + clipName);
			}
		}

		public float GetClipDuration(string clipName)
		{
			if (!audioClips.TryGetValue(clipName.ToLower(), out var value))
			{
				return -1f;
			}
			return value.length;
		}

		private void LoadAudioResources()
		{
			FileInfo fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
			string[] array = new string[0];
			Dictionary<string, AudioType> obj = new Dictionary<string, AudioType>
			{
				{
					"*.wav",
					(AudioType)20
				},
				{
					"*.mp3",
					(AudioType)13
				}
			};
			string directoryName = fileInfo.DirectoryName;
			audioClips.Clear();
			Logging.GetLogger().Debug("LoadAudioResources");
			foreach (string key in obj.Keys)
			{
				array = CollectionExtensions.AddRangeToArray<string>(array, Directory.GetFiles(fileInfo.DirectoryName, key, SearchOption.TopDirectoryOnly));
			}
			((MonoBehaviour)this).StartCoroutine(Co_LoadAudio(directoryName, array));
		}

		[IteratorStateMachine(typeof(<Co_LoadAudio>d__8))]
		private IEnumerator Co_LoadAudio(string filePath, string[] audioFiles)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Co_LoadAudio>d__8(0)
			{
				<>4__this = this,
				filePath = filePath,
				audioFiles = audioFiles
			};
		}
	}
	internal class CircularList<T>
	{
		private List<T> circle;

		private int index;

		public int Index => index;

		public CircularList(List<T> source, T startingElement)
		{
			circle = new List<T>(source);
			index = circle.FindIndex((T x) => x.Equals(startingElement));
		}

		public T Next()
		{
			index = ((index < circle.Count - 1) ? (index + 1) : 0);
			return circle[index];
		}

		public T Previous()
		{
			index = ((index > 0) ? (index - 1) : (circle.Count - 1));
			return circle[index];
		}
	}
	public class ConfigMock
	{
		public bool Value { get; set; }
	}
	public class CrossPlatformRandom : Random
	{
		private const int LCG_MULTIPLIER = 134775813;

		private const int LCG_INCREMENT = 1;

		private int _seed;

		public float value => (float)NextDouble();

		public CrossPlatformRandom()
		{
			Random random = new Random();
			_seed = random.Next();
		}

		public CrossPlatformRandom(int seed)
		{
			_seed = seed;
		}

		public float Range(int min, int max)
		{
			return Next(min, max);
		}

		public float Range(float min, float max)
		{
			return Mathf.Lerp(min, max, (float)NextDouble());
		}

		private int GetNext()
		{
			_seed = _seed * 134775813 + 1;
			return _seed;
		}

		public override int Next()
		{
			return Next(int.MaxValue);
		}

		public override int Next(int maxValue)
		{
			if (maxValue < 0)
			{
				throw new ArgumentOutOfRangeException("maxValue is less than zero.");
			}
			return (int)((long)(uint)GetNext() * (long)(uint)maxValue >>> 32);
		}

		public override int Next(int minValue, int maxValue)
		{
			if (minValue > maxValue)
			{
				throw new ArgumentOutOfRangeException("minValue is greater than maxValue.");
			}
			return minValue + Next(maxValue - minValue);
		}

		public override double NextDouble()
		{
			return Sample();
		}

		protected override double Sample()
		{
			return (double)Next() / 2147483647.0;
		}
	}
	internal class CustomDataWrapper
	{
		private Dictionary<string, string> playerData;

		private Dictionary<string, string> Data { get; set; }

		public CustomDataWrapper(Dictionary<string, string> sourceData, string keyPrefix)
		{
			CustomDataWrapper customDataWrapper = this;
			playerData = sourceData;
			Data = new Dictionary<string, string>();
			sourceData.Keys.ToList().ForEach(delegate(string key)
			{
				if (key.StartsWith(keyPrefix))
				{
					customDataWrapper.Data.Add(key, sourceData[key]);
				}
			});
		}

		public void Add(string key, string value)
		{
			Data.Add(key, value);
			playerData.Add(key, value);
		}

		public bool Remove(string key)
		{
			return Data.Remove(key) & playerData.Remove(key);
		}

		public void Set(string key, string value)
		{
			if (Data.ContainsKey(key))
			{
				Data[key] = value;
			}
			else
			{
				Data.Add(key, value);
			}
			if (playerData.ContainsKey(key))
			{
				playerData[key] = value;
			}
			else
			{
				playerData.Add(key, value);
			}
		}

		public string Get(string key)
		{
			if (Data.ContainsKey(key))
			{
				return Data[key];
			}
			return null;
		}

		public bool ContainsKey(string key)
		{
			return Data.ContainsKey(key);
		}

		public void PreSaveSync()
		{
			foreach (KeyValuePair<string, string> datum in Data)
			{
				if (!playerData.ContainsKey(datum.Key))
				{
					playerData.Add(datum.Key, datum.Value);
				}
			}
		}
	}
	internal class DebugUtils
	{
		public static void ObjectInspector(object o)
		{
			if (o == null)
			{
				Debug.Log((object)"Object is null");
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			Type type = o.GetType();
			Debug.Log((object)(o.ToString() + " Type " + type.Name));
			PropertyInfo[] properties = type.GetProperties(bindingAttr);
			foreach (PropertyInfo propertyInfo in properties)
			{
				Debug.Log((object)$"{type.Name}.{propertyInfo.Name} = {propertyInfo.GetValue(o)}");
			}
			FieldInfo[] fields = type.GetFields(bindingAttr);
			foreach (FieldInfo field in fields)
			{
				FieldPrinter(o, type, field);
			}
		}

		public static void MethodInspector(object o)
		{
			if (o == null)
			{
				Debug.Log((object)"Object is null");
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			Type type = o.GetType();
			Debug.Log((object)(o.ToString() + " Type " + type.Name));
			MethodInfo[] methods = type.GetMethods(bindingAttr);
			foreach (MethodInfo methodInfo in methods)
			{
				methodInfo.GetParameters();
				string arg = string.Join(", ", (from x in methodInfo.GetParameters()
					select x.ParameterType?.ToString() + " " + x.Name).ToArray());
				Debug.Log((object)$"{methodInfo.ReturnType} {methodInfo.Name} ({arg})");
			}
		}

		private static void ItemDataInspector(ItemData item)
		{
			ObjectInspector(item);
			ObjectInspector(item.m_shared);
		}

		private static void FieldPrinter(object o, Type t, FieldInfo field)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			try
			{
				if (field.FieldType == typeof(ItemData))
				{
					ItemData val = (ItemData)field.GetValue(o);
					if (val != null)
					{
						ItemDataInspector(val);
					}
					else
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
					}
				}
				else if (field.FieldType == typeof(Transform))
				{
					Transform val2 = (Transform)field.GetValue(o);
					if ((Object)(object)val2 != (Object)null)
					{
						Debug.Log((object)("\tTransform.parent = " + ((Object)val2.parent).name));
					}
					else
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
					}
				}
				else if (field.FieldType == typeof(EffectList))
				{
					EffectList val3 = (EffectList)field.GetValue(o);
					if (val3 != null)
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}:");
						EffectData[] effectPrefabs = val3.m_effectPrefabs;
						foreach (EffectData val4 in effectPrefabs)
						{
							Debug.Log((object)("\tEffectData.m_prefab = " + ((Object)val4.m_prefab).name));
						}
					}
					else
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
					}
				}
				else
				{
					Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}");
				}
			}
			catch (Exception)
			{
				Debug.Log((object)("Exception accessing " + t?.Name + "." + field?.Name));
			}
		}

		public static void GameObjectInspector(GameObject go)
		{
			Debug.Log((object)("\n\nInspecting GameObject " + ((Object)go).name));
			ObjectInspector(go);
			Component[] componentsInChildren = go.GetComponentsInChildren<Component>();
			foreach (Component val in componentsInChildren)
			{
				try
				{
					string obj = ((val != null) ? ((Object)val).name : null);
					object obj2;
					if (val == null)
					{
						obj2 = null;
					}
					else
					{
						Transform transform = val.transform;
						if (transform == null)
						{
							obj2 = null;
						}
						else
						{
							Transform parent = transform.parent;
							obj2 = ((parent != null) ? ((Object)parent).name : null);
						}
					}
					Debug.Log((object)("\n\nInspecting Component " + obj + " with parent " + (string?)obj2));
					ObjectInspector(val);
				}
				catch (Exception)
				{
				}
			}
		}

		public static void PrintList<T>(List<T> l)
		{
			foreach (T item in l)
			{
				Debug.Log((object)item.ToString());
			}
		}

		public static void ComponentInspector(Component c)
		{
			Debug.Log((object)("\n\nInspecting Component " + ((Object)c).name));
			ObjectInspector(c);
		}

		public static void EffectsInspector(EffectList e)
		{
			EffectData[] effectPrefabs = e.m_effectPrefabs;
			Debug.Log((object)$"Effect list has effects {e.HasEffects()} count {effectPrefabs.Length}");
			EffectData[] array = effectPrefabs;
			foreach (EffectData val in array)
			{
				Debug.Log((object)$"Effect Data {val} prefab name {((Object)val.m_prefab).name} prefab GameObject name {((Object)val.m_prefab.gameObject).name}");
			}
		}

		public static void PrintInventory()
		{
			foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems())
			{
				Debug.Log((object)allItem.m_shared.m_name);
			}
		}

		public static void PrintAllObjects()
		{
			ZNetScene.instance.m_prefabs.ForEach(delegate(GameObject x)
			{
				Debug.Log((object)("GameObject " + ((Object)x).name));
			});
		}

		public static void PrintAllCharacters()
		{
			Character.GetAllCharacters().ForEach(delegate(Character x)
			{
				Debug.Log((object)("Character " + ((Object)x).name));
			});
		}

		public static void PrintAllLayers()
		{
			string[] array = (from index in Enumerable.Range(0, 31)
				select LayerMask.LayerToName(index) into l
				where !string.IsNullOrEmpty(l)
				select l).ToArray();
			foreach (string text in array)
			{
				Debug.Log((object)("Layer " + text + " " + Convert.ToString(LayerMask.NameToLayer(text), 2).PadLeft(32, '0')));
			}
		}
	}
	public class DelegatedConfigEntry<T> : DelegatedConfigEntryBase
	{
		private ConfigEntry<T> _entry;

		private EventHandler rootHandler;

		private Action<object, EventArgs> clientDelegate;

		private Logging Log;

		public ConfigEntry<T> ConfigEntry
		{
			get
			{
				return _entry;
			}
			set
			{
				_entry = value;
				if (_entry != null && rootHandler != null)
				{
					_entry.SettingChanged += rootHandler;
				}
				Name = ((ConfigEntryBase)_entry).Definition.Key;
				Section = ((ConfigEntryBase)_entry).Definition.Section;
				ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue();
				Log.Trace("Set " + Section + " " + Name + " to serialized value " + ServerValue);
			}
		}

		public T Value
		{
			get
			{
				return _entry.Value;
			}
			set
			{
				_entry.Value = value;
			}
		}

		public DelegatedConfigEntry(bool useServerDelegate = false)
			: this((Action<object, EventArgs>)null, useServerDelegate)
		{
		}

		public DelegatedConfigEntry(Action<object, EventArgs> delegateHandler, bool useServerDelegate = false)
		{
			Log = Logging.GetLogger();
			Log.Trace("DelegatedConfigEntry");
			if (delegateHandler != null)
			{
				clientDelegate = delegateHandler;
			}
			if (useServerDelegate)
			{
				Log.Trace("Configuring server delegate");
				rootHandler = delegate(object s, EventArgs e)
				{
					ServerDelegate(s, e);
				};
				ServerConfiguration.ServerDelegatedEntries.Add(this);
			}
			else if (clientDelegate != null)
			{
				rootHandler = delegate(object s, EventArgs e)
				{
					clientDelegate(s, e);
				};
			}
		}

		private void ServerDelegate(object sender, EventArgs args)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			Logging.GetLogger().Trace("ServerDelegate");
			_entry.SettingChanged -= rootHandler;
			ZNet instance = ZNet.instance;
			bool? flag = ((instance != null) ? new bool?(instance.IsServer()) : null);
			if (flag.HasValue)
			{
				if (flag == false && ServerConfiguration.Instance.ReceivedServerValues)
				{
					if (ServerValue != null)
					{
						((ConfigEntryBase)_entry).SetSerializedValue(ServerValue);
						Log.Debug("Setting " + Name + " to server value " + ServerValue);
					}
				}
				else if (flag.GetValueOrDefault())
				{
					ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue();
					ServerConfiguration.Instance.SendConfigToAllClients(sender, (SettingChangedEventArgs)args);
				}
			}
			if (clientDelegate != null)
			{
				clientDelegate(sender, args);
			}
			_entry.SettingChanged += rootHandler;
		}

		public void EnableHandler(bool setActive)
		{
			if (setActive)
			{
				_entry.SettingChanged += rootHandler;
			}
			else
			{
				_entry.SettingChanged -= rootHandler;
			}
		}

		public bool IsKeyPressed()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigEntry is ConfigEntry<KeyboardShortcut> val)
			{
				KeyboardShortcut value = val.Value;
				foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
				{
					if (!Input.GetKey(modifier))
					{
						return false;
					}
				}
				if (!Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
				{
					return false;
				}
				return true;
			}
			Log.Error("Keyboard read attempted on non-KeyboardShortcut config.");
			return false;
		}

		public bool IsKeyDown()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigEntry is ConfigEntry<KeyboardShortcut> val)
			{
				KeyboardShortcut value = val.Value;
				foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
				{
					if (!Input.GetKey(modifier))
					{
						return false;
					}
				}
				if (!Input.GetKey(((KeyboardShortcut)(ref value)).MainKey))
				{
					return false;
				}
				return true;
			}
			Log.Error("Keyboard read attempted on non-KeyboardShortcut config.");
			return false;
		}

		public bool IsKeyReleased()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigEntry is ConfigEntry<KeyboardShortcut> val)
			{
				KeyboardShortcut value = val.Value;
				foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
				{
					if (!Input.GetKeyUp(modifier))
					{
						return false;
					}
				}
				if (!Input.GetKeyUp(((KeyboardShortcut)(ref value)).MainKey))
				{
					return false;
				}
				return true;
			}
			Log.Error("Keyboard read attempted on non-KeyboardShortcut config.");
			return false;
		}
	}
	public class DelegatedConfigEntryBase
	{
		public string Name;

		public string Section;

		public string ServerValue;
	}
	internal class HarmonyHelper
	{
		public enum PatchType
		{
			Prefix,
			Postfix,
			Transpiler,
			Finalizer
		}

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

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

		public static void GetDetectionSet(Dictionary<string, string> harmonyIds)
		{
			Logging logger = Logging.GetLogger();
			foreach (KeyValuePair<string, string> harmonyId in harmonyIds)
			{
				if (Harmony.HasAnyPatches(harmonyId.Key))
				{
					logger.Debug("Detected " + harmonyId.Value + " from Harmony");
					if (!detectionSet.ContainsKey(harmonyId.Key))
					{
						detectionSet.Add(harmonyId.Key, harmonyId.Value);
					}
				}
				else if (Chainloader.PluginInfos.ContainsKey(harmonyId.Key))
				{
					logger.Debug("Detected " + harmonyId.Value + " from BepInEx");
					if (!detectionSet.ContainsKey(harmonyId.Key))
					{
						detectionSet.Add(harmonyId.Key, harmonyId.Value);
					}
				}
			}
		}

		public static void AddToUnpatch(string key)
		{
			if (detectionSet.ContainsKey(key))
			{
				unpatchMods.Add(key, detectionSet[key]);
			}
		}

		public static void UnpatchMods(Harmony harmony)
		{
			Logging logger = Logging.GetLogger();
			foreach (KeyValuePair<string, string> unpatchMod in unpatchMods)
			{
				logger.Warning("Not compatible with " + unpatchMod.Value);
				Harmony.UnpatchID(unpatchMod.Key);
				detectionSet.Remove(unpatchMod.Key);
				logger.Warning("Disabled " + unpatchMod.Value);
			}
		}

		public static bool IsModDetected(string key)
		{
			return detectionSet.ContainsKey(key);
		}

		public static bool IsModNameDetected(string value)
		{
			return detectionSet.ContainsValue(value);
		}

		public static bool TryGetDetectedModName(string key, out string mod)
		{
			return detectionSet.TryGetValue(key, out mod);
		}

		public static bool TryGetDetectedModKey(string value, out string key)
		{
			key = null;
			foreach (string key2 in detectionSet.Keys)
			{
				if (detectionSet[key2] == value)
				{
					key = key2;
					return true;
				}
			}
			return false;
		}

		public static string AddAnonymousPatch(string baseMethodName, PatchType patchType, string modName, string patchMethodName = null)
		{
			string text = null;
			int num = 0;
			Logging logger = Logging.GetLogger();
			foreach (MethodBase item in Harmony.GetAllPatchedMethods().ToList())
			{
				MethodBaseExtensions.HasMethodBody(item);
				Patches patchInfo = Harmony.GetPatchInfo(item);
				ReadOnlyCollection<Patch> readOnlyCollection = patchInfo.Prefixes;
				switch (patchType)
				{
				case PatchType.Postfix:
					readOnlyCollection = patchInfo.Postfixes;
					break;
				case PatchType.Prefix:
					readOnlyCollection = patchInfo.Prefixes;
					break;
				case PatchType.Transpiler:
					readOnlyCollection = patchInfo.Transpilers;
					break;
				case PatchType.Finalizer:
					readOnlyCollection = patchInfo.Finalizers;
					break;
				}
				foreach (Patch item2 in readOnlyCollection)
				{
					if (!item2.owner.StartsWith("harmony-auto") || !(item.Name == baseMethodName))
					{
						continue;
					}
					if (patchMethodName != null)
					{
						if (item2.PatchMethod.Name == patchMethodName)
						{
							num++;
							text = item2.owner;
						}
					}
					else
					{
						num++;
						text = item2.owner;
					}
				}
				if (num == 1)
				{
					detectionSet.Add(text, modName);
					logger.Info($"Added unique anonymous {baseMethodName} {patchType}: {text} as {modName}");
				}
				else if (num > 1)
				{
					text = null;
					logger.Warning($"Found multiple anonymous {baseMethodName} {patchType} entries. Can't identify correct patch to remove or modify.");
				}
			}
			if (num == 0)
			{
				logger.Info("No patch found for " + modName);
			}
			return text;
		}
	}
	public class ImageHelper
	{
		private string resources;

		private bool isEmbedded;

		private Logging logger;

		public ImageHelper(string resourceLocation, bool embedded)
		{
			resources = resourceLocation;
			logger = Logging.GetLogger();
			isEmbedded = embedded;
		}

		public Sprite LoadSprite(string name, int width, int height, bool linear = false, float pixelsPerUnit = 100f)
		{
			logger.Debug("Reading image and creating sprite " + name);
			if (TryLoadImage(name, width, height, linear, out var image))
			{
				return LoadSprite(image, pixelsPerUnit);
			}
			return null;
		}

		public Sprite LoadSprite(Texture2D texture, float pixelsPerUnit = 100f)
		{
			return LoadSprite(texture, ((Object)texture).name, ((Texture)texture).width, ((Texture)texture).height, pixelsPerUnit);
		}

		public Sprite LoadSprite(Texture2D texture, string name, float width, float height, float pixelsPerUnit = 100f)
		{
			//IL_0044: 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)texture == (Object)null)
			{
				return null;
			}
			if (Utility.IsNullOrWhiteSpace(name))
			{
				name = ((Object)texture).name;
			}
			logger.Debug("Creating sprite " + name + " from existing texture");
			Sprite obj = Sprite.Create(texture, new Rect(0f, 0f, width, height), Vector2.zero, pixelsPerUnit);
			if ((Object)(object)obj == (Object)null)
			{
				throw new ApplicationException("Can't create sprite " + name);
			}
			((Object)obj).name = name;
			return obj;
		}

		public bool TryLoadImage(string name, int width, int height, bool linear, out Texture2D image)
		{
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			image = null;
			logger.Debug("Loading " + name + " from " + resources);
			Stream stream = null;
			if (isEmbedded)
			{
				stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resources + "." + name);
			}
			else
			{
				char directorySeparatorChar = Path.DirectorySeparatorChar;
				string text = (Utility.IsNullOrWhiteSpace(resources) ? "/" : resources);
				if (!text.EndsWith("/"))
				{
					text += directorySeparatorChar;
				}
				string text2 = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + text + name;
				text2 = text2.Replace('\\', directorySeparatorChar).Replace('/', directorySeparatorChar);
				try
				{
					logger.Debug("Reading file " + text2);
					stream = new FileStream(text2, FileMode.Open, FileAccess.Read);
				}
				catch (Exception ex)
				{
					logger.Warning("Error loading external resource. Using embedded resource: " + ex.Message);
					stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resources + "." + name);
				}
			}
			if (stream == null)
			{
				throw new FileNotFoundException("Can't find " + name + " in " + resources);
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, (int)stream.Length);
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, true, linear);
			logger.Debug("Loading image " + name);
			if (ImageConversion.LoadImage(val, array, false))
			{
				image = val;
				return true;
			}
			throw new FileLoadException("Can't load " + name);
		}
	}
	public class SpriteLoaderFromFile : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <LoadSpriteFromFile>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public SpriteLoaderFromFile <>4__this;

			private UnityWebRequest <uwr>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadSpriteFromFile>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<uwr>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Invalid comparison between Unknown and I4
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					int num = <>1__state;
					SpriteLoaderFromFile spriteLoaderFromFile = <>4__this;
					switch (num)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<uwr>5__2 = UnityWebRequestTexture.GetTexture("file://" + spriteLoaderFromFile.filePath);
						<>1__state = -3;
						<>2__current = <uwr>5__2.SendWebRequest();
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -3;
						if ((int)<uwr>5__2.result != 1)
						{
							Debug.LogError((object)("Error loading sprite: " + <uwr>5__2.error));
						}
						else
						{
							Texture2D content = DownloadHandlerTexture.GetContent(<uwr>5__2);
							Sprite sprite = Sprite.Create(content, new Rect(0f, 0f, (float)((Texture)content).width, (float)((Texture)content).height), new Vector2(0.5f, 0.5f));
							((Component)spriteLoaderFromFile).GetComponent<SpriteRenderer>().sprite = sprite;
						}
						<>m__Finally1();
						<uwr>5__2 = null;
						return false;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<uwr>5__2 != null)
				{
					((IDisposable)<uwr>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public string filePath;

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(LoadSpriteFromFile());
		}

		[IteratorStateMachine(typeof(<LoadSpriteFromFile>d__2))]
		private IEnumerator LoadSpriteFromFile()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadSpriteFromFile>d__2(0)
			{
				<>4__this = this
			};
		}
	}
	internal class InputCycler
	{
		private static InputCycler _instance;

		private bool useMouseWheel;

		private DelegatedConfigEntry<KeyboardShortcut> keyAdvance;

		private DelegatedConfigEntry<KeyboardShortcut> keyReferse;

		public static InputCycler Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new InputCycler();
				}
				return _instance;
			}
		}

		private InputCycler()
		{
		}

		public void Init(bool useMouseWheel, DelegatedConfigEntry<KeyboardShortcut> keyAdvance, DelegatedConfigEntry<KeyboardShortcut> keyReverse = null)
		{
			this.useMouseWheel = useMouseWheel;
			this.keyAdvance = keyAdvance;
			keyReferse = keyReverse;
		}
	}
	public class IterativeStopwatch : Stopwatch
	{
		private double startMillis;

		private Logging Log = Logging.GetLogger();

		public long Iterations { get; private set; }

		public double IterationMicroseconds { get; private set; }

		public double TotalElapsedMicroseconds { get; private set; }

		public double IterationMilliseconds { get; private set; }

		public double TotalElapsedMilliseconds { get; private set; }

		public double AverageMicroseconds { get; private set; }

		public double AverageMilliseconds { get; private set; }

		public IterativeStopwatch()
		{
			Iterations = 0L;
		}

		public new void Start()
		{
			startMillis = base.Elapsed.TotalMilliseconds;
			base.Start();
		}

		public new void Stop()
		{
			if (base.IsRunning)
			{
				base.Stop();
				Iterations++;
				IterationMilliseconds = base.Elapsed.TotalMilliseconds - startMillis;
				IterationMicroseconds = IterationMilliseconds * 1000.0;
				TotalElapsedMilliseconds = base.Elapsed.TotalMilliseconds;
				TotalElapsedMicroseconds = base.Elapsed.TotalMilliseconds * 1000.0;
				AverageMilliseconds = TotalElapsedMilliseconds / (double)Iterations;
				AverageMicroseconds = TotalElapsedMicroseconds / (double)Iterations;
			}
		}

		public new void Reset()
		{
			startMillis = 0.0;
			Iterations = 0L;
			base.Reset();
		}

		public new void Restart()
		{
			startMillis = 0.0;
			Iterations = 0L;
			base.Restart();
		}
	}
	public static class JsonHelper
	{
		[Serializable]
		private class JsonWrapper<T>
		{
			public T[] Items;
		}

		public static T[] FromJson<T>(string json)
		{
			return JsonUtility.FromJson<JsonWrapper<T>>(json).Items;
		}

		public static string ToJson<T>(T[] array)
		{
			return JsonUtility.ToJson((object)new JsonWrapper<T>
			{
				Items = array
			});
		}

		public static string ToJson<T>(T[] array, bool prettyPrint)
		{
			return JsonUtility.ToJson((object)new JsonWrapper<T>
			{
				Items = array
			}, prettyPrint);
		}
	}
	public class Logging
	{
		public enum LogLevels
		{
			Critical,
			Error,
			Warning,
			Info,
			Debug,
			Trace
		}

		private static Logging _logger;

		public LogLevels LogLevel { get; set; }

		public string ModName { get; set; }

		private Logging(LogLevels level, string name)
		{
			LogLevel = level;
			ModName = name;
		}

		public static Logging GetLogger(LogLevels level, string name)
		{
			if (_logger == null)
			{
				_logger = new Logging(level, name);
			}
			return _logger;
		}

		public static Logging GetLogger()
		{
			if (_logger == null)
			{
				throw new NullReferenceException("Logger not initialized");
			}
			return _logger;
		}

		public void Trace(string msg)
		{
			if (LogLevel >= LogLevels.Trace)
			{
				Debug.Log((object)Message(msg));
			}
		}

		public void Debug(string msg)
		{
			if (LogLevel >= LogLevels.Debug)
			{
				Debug.Log((object)Message(msg));
			}
		}

		public void Info(string msg)
		{
			if (LogLevel >= LogLevels.Info)
			{
				Debug.Log((object)Message(msg));
			}
		}

		public void Warning(string msg)
		{
			if (LogLevel >= LogLevels.Warning)
			{
				Debug.LogWarning((object)Message(msg));
			}
		}

		public void Error(string msg)
		{
			if (LogLevel >= LogLevels.Error)
			{
				Debug.LogWarning((object)Message(msg));
			}
		}

		public void Error(Exception e)
		{
			Error(e, stackTrace: false);
		}

		public void Error(Exception e, bool stackTrace)
		{
			if (LogLevel >= LogLevels.Error)
			{
				Warning(Message(e.Message));
				if (stackTrace)
				{
					Warning(e.StackTrace);
				}
			}
		}

		public void Critical(Exception e)
		{
			if (LogLevel >= LogLevels.Critical)
			{
				Debug(Message(e.Message));
				Error(e.StackTrace);
			}
		}

		private string Message(string msg)
		{
			return ModName + ": " + msg;
		}
	}
	public class ServerConfiguration
	{
		[HarmonyPatch(typeof(ZNet), "StopAll")]
		private static class ZNet_Shutdown_Patch
		{
			[HarmonyPrefix]
			private static void ZNet_StopAll_Prefix(ZNet __instance)
			{
				if (_instance != null)
				{
					Log.Debug("ZNet_StopAll_Patch_Prefix");
					_instance.ReceivedServerValues = false;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class ZNet_OnNewConnection_Patch
		{
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				Log.Debug("ZNet OnNewConnection postfix");
				if (!__instance.IsServer())
				{
					try
					{
						peer.m_rpc.Register<ZPackage>("ClientConfigReceiver." + GetPluginGuid(), (Action<ZRpc, ZPackage>)Instance.RPC_ClientConfigReceiver);
						Log.Debug("Player registered RPC_ClientConfigReceiver");
						return;
					}
					catch (Exception)
					{
						Log.Warning("Failed to register RPC");
						return;
					}
				}
				try
				{
					Instance.SendConfigToClient(peer);
				}
				catch (Exception)
				{
					Log.Warning("Error sending server configuration to client");
				}
			}
		}

		[CompilerGenerated]
		private sealed class <Co_BroadcastConfig>d__21 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ZPackage zpkg;

			private List<ZNetPeer>.Enumerator <>7__wrap1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Co_BroadcastConfig>d__21(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = default(List<ZNetPeer>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
					{
						<>1__state = -1;
						Log.Debug("Co_BroadcastConfig");
						List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
						<>7__wrap1 = connectedPeers.GetEnumerator();
						<>1__state = -3;
						break;
					}
					case 1:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap1.MoveNext())
					{
						ZNetPeer current = <>7__wrap1.Current;
						if (current != ZNet.instance.GetServerPeer())
						{
							current.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { zpkg });
							Log.Trace("Invoked ClientConfigReceiver on peer");
						}
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap1 = default(List<ZNetPeer>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap1).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public static List<DelegatedConfigEntryBase> ServerDelegatedEntries = new List<DelegatedConfigEntryBase>();

		private static ConfigFile LocalConfig;

		private static BaseUnityPlugin Mod;

		private static string ConfigFileName;

		private static ServerConfiguration _instance;

		private static Logging Log;

		public bool IsSetup;

		public bool ReceivedServerValues;

		public FileSystemWatcher ConfigWatcher;

		private const string NOT_CONFIGURED = "ServerConfiguration not initialized. Setup first.";

		public static ServerConfiguration Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new ServerConfiguration();
				}
				return _instance;
			}
		}

		private ServerConfiguration()
		{
		}

		public void Setup(ConfigFile config, BaseUnityPlugin modInstance)
		{
			LocalConfig = config;
			Log = Logging.GetLogger();
			Log.Trace("ServerConfiguration Setup");
			Mod = modInstance;
			ConfigFileName = Path.GetFileName(LocalConfig.ConfigFilePath);
			IsSetup = true;
		}

		public void CreateConfigWatcher()
		{
			ConfigWatcher = Utils.CreateFileWatcher(LocalConfig.ConfigFilePath, LoadConfig);
		}

		private void LoadConfig(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(LocalConfig.ConfigFilePath))
			{
				return;
			}
			try
			{
				Log.Debug($"Loading configuration {e.ChangeType}");
				LocalConfig.Reload();
			}
			catch
			{
				Log.Error("Error loading configuration file " + ConfigFileName);
			}
		}

		public static string GetPluginGuid()
		{
			return Mod.Info.Metadata.GUID;
		}

		public void RPC_ClientConfigReceiver(ZRpc zrpc, ZPackage package)
		{
			if (!Instance.IsSetup)
			{
				Log.Error("ServerConfiguration not initialized. Setup first.");
				return;
			}
			Log.Debug("ClientConfigReceiver");
			string section;
			string name;
			while (package.GetPos() < package.Size())
			{
				section = package.ReadString();
				name = package.ReadString();
				string text = package.ReadString();
				Log.Trace("Reading " + section + " " + name + " value " + text + " from ZPackage");
				DelegatedConfigEntryBase delegatedConfigEntryBase = ServerDelegatedEntries.Find((DelegatedConfigEntryBase e) => e.Name == name && e.Section == section);
				if (delegatedConfigEntryBase != null)
				{
					Log.Trace("Found DCEB on client and setting to server value " + text);
					delegatedConfigEntryBase.ServerValue = text;
				}
				ConfigEntryBase val = LocalConfig[section, name];
				if (val != null)
				{
					Log.Trace("Found local CEB and setting underlying config value " + text);
					val.SetSerializedValue(text);
				}
			}
			ReceivedServerValues = true;
		}

		internal void WriteConfigEntries(ZPackage zpkg)
		{
			foreach (DelegatedConfigEntryBase serverDelegatedEntry in ServerDelegatedEntries)
			{
				Log.Trace("Writing " + serverDelegatedEntry.Section + " " + serverDelegatedEntry.Name + " value " + serverDelegatedEntry.ServerValue + " to ZPackage");
				zpkg.Write(serverDelegatedEntry.Section);
				zpkg.Write(serverDelegatedEntry.Name);
				zpkg.Write(serverDelegatedEntry.ServerValue);
			}
		}

		internal void SendConfigToClient(ZNetPeer peer)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (!Instance.IsSetup)
			{
				Log.Error("ServerConfiguration not initialized. Setup first.");
				return;
			}
			Log.Debug("SendConfigToClient");
			ZPackage val = new ZPackage();
			WriteConfigEntries(val);
			peer.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { val });
			Log.Trace("Invoked ClientConfigReceiver on peer");
		}

		public void SendConfigToAllClients(object o, SettingChangedEventArgs e)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			if (!IsSetup)
			{
				Log.Error("ServerConfiguration not initialized. Setup first.");
			}
			else if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZNet.instance.GetPeerConnections() > 0)
			{
				Log.Debug("SendConfigToAllClients");
				ZPackage zpkg = new ZPackage();
				WriteConfigEntries(zpkg);
				((MonoBehaviour)Mod).StartCoroutine(_instance.Co_BroadcastConfig(zpkg));
			}
		}

		[IteratorStateMachine(typeof(<Co_BroadcastConfig>d__21))]
		private IEnumerator Co_BroadcastConfig(ZPackage zpkg)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Co_BroadcastConfig>d__21(0)
			{
				zpkg = zpkg
			};
		}
	}
	public class Utils
	{
		public static TEnum Guardrails<TEnum>(string value, TEnum enumDefault) where TEnum : struct
		{
			if (Enum.TryParse<TEnum>(value, ignoreCase: true, out var result))
			{
				return result;
			}
			return enumDefault;
		}

		public static int Guardrails(int value, int lbound, int ubound)
		{
			if (value < lbound)
			{
				return lbound;
			}
			if (value > ubound)
			{
				return ubound;
			}
			return value;
		}

		public static string Truncate(string value, int maxChars)
		{
			if (value == null)
			{
				return null;
			}
			if (value.Length <= maxChars)
			{
				return value;
			}
			return value.Substring(0, maxChars);
		}

		public static void GetCharactersInRangeXZ(Vector3 point, float radius, List<Character> characters)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			float num = radius * radius;
			foreach (Character s_character in Character.s_characters)
			{
				if (DistanceSqrXZ(((Component)s_character).transform.position, point) < num)
				{
					characters.Add(s_character);
				}
			}
		}

		public static float DistanceSqr(Vector3 v0, Vector3 v1)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			float num = v1.x - v0.x;
			float num2 = v1.y - v0.y;
			float num3 = v1.z - v0.z;
			return num * num + num2 * num2 + num3 * num3;
		}

		public static float DistanceSqrXZ(Vector3 v0, Vector3 v1)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = v1.x - v0.x;
			float num2 = v1.z - v0.z;
			return num * num + num2 * num2;
		}

		public static float DistanceXZ(Vector3 v0, Vector3 v1)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = v1.x - v0.x;
			float num2 = v1.z - v0.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		public static float Guardrails(float value, float lbound, float ubound)
		{
			if (value < lbound)
			{
				return lbound;
			}
			if (value > ubound)
			{
				return ubound;
			}
			return value;
		}

		public static string UnClonifiedName(string name)
		{
			if (name == null)
			{
				return null;
			}
			int num = name.IndexOf("(Clone)");
			if (num < 1)
			{
				return name;
			}
			return name.Substring(0, num);
		}

		public static void SetTranslator(int id, string idText)
		{
			typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(Localization.instance, new object[2]
			{
				"skill_" + id,
				idText
			});
		}

		public static string GetTranslated(int id)
		{
			Logging.GetLogger().Debug(string.Format("Got translation for id {0} to {1}", id, Localization.instance.Localize("skill_" + id)));
			return Localization.instance.Localize("$skill_" + id);
		}

		public static string GetAssemblyPathedFile(string fileName)
		{
			return new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName.Replace('\\', '/') + "/" + fileName;
		}

		public static Sprite GetPrefabIcon(string prefabName)
		{
			Sprite result = null;
			GameObject prefab = GetPrefab(prefabName);
			ItemDrop val = default(ItemDrop);
			if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent<ItemDrop>(ref val))
			{
				result = val.m_itemData.GetIcon();
			}
			return result;
		}

		public static Player GetPlayerByZDOID(ZDOID zid)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				ZDOID zDOID = ((Character)allPlayer).GetZDOID();
				if (((ZDOID)(ref zDOID)).Equals(zid))
				{
					return allPlayer;
				}
			}
			return null;
		}

		public static Character GetCharacterByZDOID(string cid)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				ZDOID zDOID = allCharacter.GetZDOID();
				if (((object)(ZDOID)(ref zDOID)).ToString().Equals(cid))
				{
					return allCharacter;
				}
			}
			return null;
		}

		public static Character GetCharacterByZDOID(ZDOID cid)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				ZDOID zDOID = allCharacter.GetZDOID();
				if (((ZDOID)(ref zDOID)).Equals(cid))
				{
					return allCharacter;
				}
			}
			return null;
		}

		public static ZNetPeer GetPeerByRPC(ZRpc rpc)
		{
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.m_rpc == rpc)
				{
					return peer;
				}
			}
			return null;
		}

		public static List<GameObject> GetGameObjectsOfType(Type t)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			List<GameObject> list = new List<GameObject>();
			Object[] array = Object.FindObjectsByType(t, (FindObjectsSortMode)0);
			foreach (Object val in array)
			{
				list.Add(((Component)val).gameObject);
			}
			return list;
		}

		public static GameObject GetClosestGameObjectOfType(Type t, Vector3 point, float radius)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return GetGameObjectsOfTypeInRangeByDistance(t, point, radius)?[0];
		}

		public static List<GameObject> GetGameObjectsOfTypeInRangeByDistance(Type t, Vector3 point, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<GameObject, float>> list = new List<KeyValuePair<GameObject, float>>();
			List<GameObject> gameObjectsOfTypeInRange = GetGameObjectsOfTypeInRange(t, point, radius);
			if (gameObjectsOfTypeInRange.Count > 0)
			{
				foreach (GameObject item in gameObjectsOfTypeInRange)
				{
					list.Add(new KeyValuePair<GameObject, float>(item, Vector3.Distance(item.transform.position, point)));
				}
				list.Sort((KeyValuePair<GameObject, float> pair1, KeyValuePair<GameObject, float> pair2) => pair1.Value.CompareTo(pair2.Value));
				return list.ConvertAll((KeyValuePair<GameObject, float> x) => x.Key);
			}
			return null;
		}

		public static List<GameObject> GetGameObjectsOfTypeInRange(Type t, Vector3 point, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return (from x in GetGameObjectsOfType(t)
				where Vector3.Distance(x.transform.position, point) < radius
				select x).ToList();
		}

		public static float GetPointDepth(Vector3 p)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return ZoneSystem.instance.m_waterLevel - GetSolidHeight(p);
		}

		public static List<string> GetDelimitedStringAsList(string delimitedString, char delimiter)
		{
			List<string> list = new List<string>();
			string[] array = delimitedString.Split(new char[1] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				list.Add(text.Trim());
			}
			return list;
		}

		public static float GetSolidHeight(Vector3 p)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			int solidRayMask = ZoneSystem.instance.m_solidRayMask;
			float result = 0f;
			p.y += 1000f;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(p, Vector3.down, ref val, 2000f, solidRayMask) && !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody))
			{
				result = ((RaycastHit)(ref val)).point.y;
			}
			return result;
		}

		public static Transform FindChild(Transform aParent, string aName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			foreach (Transform item in aParent)
			{
				Transform val = item;
				if (((Object)val).name == aName)
				{
					return val;
				}
				Transform val2 = FindChild(val, aName);
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return null;
		}

		public static Transform FindParent(Transform go)
		{
			while ((Object)(object)go.parent != (Object)null)
			{
				go = go.parent;
			}
			return go;
		}

		public static GameObject GetPrefab(int prefabHash)
		{
			return GetPrefabByHash(prefabHash);
		}

		public static GameObject GetPrefabByHash(int prefabHash)
		{
			GameObject val = ObjectDB.instance.GetItemPrefab(prefabHash);
			Logging logger = Logging.GetLogger();
			if ((Object)(object)val != (Object)null)
			{
				logger.Debug("Found prefab in ObjectDB");
			}
			else
			{
				ZNetScene instance = ZNetScene.instance;
				val = ((instance != null) ? instance.GetPrefab(prefabHash) : null);
				if ((Object)(object)val != (Object)null)
				{
					logger.Debug("Found prefab in Scene");
				}
			}
			return val;
		}

		public static GameObject GetPrefab(string prefabName)
		{
			GameObject val = ObjectDB.instance.GetItemPrefab(prefabName);
			Logging logger = Logging.GetLogger();
			if ((Object)(object)val != (Object)null)
			{
				logger.Debug("Found " + prefabName + " in ObjectDB");
			}
			else
			{
				ZNetScene instance = ZNetScene.instance;
				val = ((instance != null) ? instance.GetPrefab(prefabName) : null);
				if ((Object)(object)val != (Object)null)
				{
					logger.Debug("Found " + prefabName + " in Scene");
				}
			}
			return val;
		}

		public static string SerializeFromDictionary<K, V>(string delimp, string delimc, IDictionary<K, V> dict)
		{
			if (dict == null)
			{
				return null;
			}
			IEnumerable<string> values = dict.Select(delegate(KeyValuePair<K, V> kvp)
			{
				KeyValuePair<K, V> keyValuePair = kvp;
				string? obj = keyValuePair.Key?.ToString();
				string text = delimc;
				keyValuePair = kvp;
				return obj + text + keyValuePair.Value;
			});
			return string.Join(delimp, values);
		}

		public static void DeserializeToDictionary<K, V>(string serializedString, string delimp, string delimc, ref IDictionary<K, V> dict)
		{
			if (dict == null)
			{
				return;
			}
			dict.Clear();
			string[] separator = new string[1] { delimp };
			string[] separator2 = new string[1] { delimc };
			string[] array = serializedString.Split(separator, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(separator2, StringSplitOptions.RemoveEmptyEntries);
				if (array2.Length == 2)
				{
					dict.Add(TypedValue<K>(array2[0]), TypedValue<V>(array2[1]));
				}
			}
		}

		public static FileSystemWatcher CreateFileWatcher(string fullPath, FileSystemEventHandler handler)
		{
			string fileName = Path.GetFileName(fullPath);
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(fullPath.Substring(0, fullPath.Length - fileName.Length), fileName);
			fileSystemWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
			fileSystemWatcher.Changed += handler;
			fileSystemWatcher.Created += handler;
			fileSystemWatcher.IncludeSubdirectories = false;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
			return fileSystemWatcher;
		}

		public static T TypedValue<T>(object a)
		{
			return (T)Convert.ChangeType(a, typeof(T));
		}

		public static float TimeAdjustedRamp(float maxValue, float duration, float elapsedTime, float pctFromStartRise, float pctFromEndFall)
		{
			float num = elapsedTime / duration;
			if (num <= pctFromStartRise)
			{
				return maxValue * (num / pctFromStartRise);
			}
			if (num >= 1f - pctFromEndFall)
			{
				return maxValue * ((1f - num) / pctFromEndFall);
			}
			return maxValue;
		}

		public static bool CopyComponentToGameObject(Component original, ref GameObject destination)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			Logging logger = Logging.GetLogger();
			Type type = ((object)original).GetType();
			logger.Debug($"Original Type is {type}");
			GameObject obj = destination;
			logger.Debug("Destination GameObject " + ((obj != null) ? ((Object)obj).name : null));
			Component val = destination.GetComponent(type);
			if ((Object)(object)val == (Object)null)
			{
				val = destination.AddComponent(type);
			}
			if ((Object)(object)val == (Object)null)
			{
				logger.Debug("Destination component is null");
				return false;
			}
			Component val2 = (Component)Activator.CreateInstance(type);
			if ((Object)(object)val2 == (Object)null)
			{
				logger.Debug("Destination component is null");
				return false;
			}
			if ((Object)(object)val2 == (Object)null)
			{
				logger.Debug("Boxed component is null");
				return false;
			}
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				fieldInfo.SetValue(val2, fieldInfo.GetValue(original));
			}
			val = val2;
			return true;
		}

		public static bool CopyObject(object original, object target)
		{
			Logging logger = Logging.GetLogger();
			Type type = original.GetType();
			Type type2 = target.GetType();
			if (type == null)
			{
				logger.Warning("Copy Object: Source object is null");
				Activator.CreateInstance(type);
				return false;
			}
			if (type2 == null)
			{
				logger.Warning("Copy Object: Destination object is null");
				return false;
			}
			if (type2 != type)
			{
				logger.Warning("Copy Object: Source and destination components are different types");
				return false;
			}
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				fieldInfo.SetValue(target, fieldInfo.GetValue(original));
			}
			return true;
		}
	}
}
namespace neobotics.ValheimMods
{
	internal class Cfg
	{
		public static DelegatedConfigEntry<Logging.LogLevels> debugLevel = null;

		public static DelegatedConfigEntry<KeyboardShortcut> packBehaviorKey = null;

		public static DelegatedConfigEntry<KeyboardShortcut> characterSelectorKey = null;

		public static DelegatedConfigEntry<KeyboardShortcut> packStayKey = null;

		public static DelegatedConfigEntry<KeyboardShortcut> packAttackKey = null;

		public static DelegatedConfigEntry<string> trainableCreatures = null;

		public static DelegatedConfigEntry<int> detectionRange = null;

		public static DelegatedConfigEntry<int> maxTames = null;

		public static DelegatedConfigEntry<bool> restrictPetting = null;

		public static DelegatedConfigEntry<int> packAttackRange = null;

		public static ConfigEntry<bool> disableTameNameFiltering = null;

		public static ConfigEntry<bool> twoKeyAction = null;

		public static ConfigEntry<string> wolfCallSound = null;

		public static ConfigEntry<bool> useSound = null;

		public static ConfigEntry<int> minimumCreatureLevel = null;

		public static ConfigEntry<int> scrollDelay = null;

		public static ConfigEntry<bool> useMouseWheel = null;

		public static ConfigEntry<bool> logCreatures = null;

		public static ConfigEntry<string> notifications = null;

		public static ConfigEntry<int> strictObedience = null;

		public static ConfigEntry<string> lastCalledCreature = null;

		public static ConfigEntry<int> followRadius = null;

		private static KeyCode[] keyModifiers = (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 };

		private static KeyboardShortcut packAttackKeyDefault = new KeyboardShortcut((KeyCode)106, keyModifiers);

		private static KeyboardShortcut packBehaviorKeyDefault = new KeyboardShortcut((KeyCode)116, keyModifiers);

		private static KeyboardShortcut characterSelectorKeyDefault = new KeyboardShortcut((KeyCode)117, keyModifiers);

		private static KeyboardShortcut packStayKeyDefault = new KeyboardShortcut((KeyCode)121, keyModifiers);

		public static void BepInExConfig(BaseUnityPlugin _instance)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Expected O, but got Unknown
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Expected O, but got Unknown
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Expected O, but got Unknown
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Expected O, but got Unknown
			ServerConfiguration.Instance.Setup(_instance.Config, _instance);
			debugLevel = new DelegatedConfigEntry<Logging.LogLevels>(ChangeLogging);
			debugLevel.ConfigEntry = _instance.Config.Bind<Logging.LogLevels>("Utility", "LogLevel", Logging.LogLevels.Info, "Controls the level of information contained in the log");
			WolfPack.Log.LogLevel = debugLevel.Value;
			detectionRange = new DelegatedConfigEntry<int>(useServerDelegate: true);
			detectionRange.ConfigEntry = _instance.Config.Bind<int>("General", "DetectionRange", 50, new ConfigDescription("Tame creatures beyond this distance will not be affected. Min 1; Max 150.@", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 150), Array.Empty<object>()));
			maxTames = new DelegatedConfigEntry<int>(useServerDelegate: true);
			maxTames.ConfigEntry = _instance.Config.Bind<int>("General", "MaxTames", 10, new ConfigDescription("Maximum number of tame creatures that can be summoned at one time. Min 1; Max 50.@", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			restrictPetting = new DelegatedConfigEntry<bool>(useServerDelegate: true);
			restrictPetting.ConfigEntry = _instance.Config.Bind<bool>("General", "RestrictPetting", true, "If enabled, prevents petting other player's tames from re-setting to Stay.@");
			trainableCreatures = new DelegatedConfigEntry<string>(WolfPack.ChangeTrainables, useServerDelegate: true);
			trainableCreatures.ConfigEntry = _instance.Config.Bind<string>("General", "TrainableCreatures", "wolf", "List of creatures that will be called to Follow or Stay, separated by commas, e.g., wolf,boar,lox. Accepts an asterisk (*) as the first and/or last character in a parital name to match every creature who's name starts* with, *ends with or *contains* that text.@");
			followRadius = _instance.Config.Bind<int>("General", "FollowRadius", 10, new ConfigDescription("The radius in which following creatures will randomly distribute around the player to prevent 'bunching'", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 30), Array.Empty<object>()));
			packAttackRange = new DelegatedConfigEntry<int>(useServerDelegate: true);
			packAttackRange.ConfigEntry = _instance.Config.Bind<int>("General", "TamesAttackRange", 100, new ConfigDescription("The maximum distance at which enemies can be targeted by hovering and tames will attack. Set to 0 to disable targeting.@", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 150), Array.Empty<object>()));
			lastCalledCreature = _instance.Config.Bind<string>("Hidden", "LastCalledCreature", "", new ConfigDescription("The last creature type selected from the TrainableCreatures list", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			packBehaviorKey = new DelegatedConfigEntry<KeyboardShortcut>();
			packBehaviorKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "PackBehaviorShortcut", packBehaviorKeyDefault, "Keyboard shortcut toggles pack to Follow or Stay. If UseTwoKeys is set to true, only calls creatures to Follow.");
			packStayKey = new DelegatedConfigEntry<KeyboardShortcut>();
			packStayKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "AlternateStayShortcut", packStayKeyDefault, "Keyboard shortcut to cause pack to Stay. Only used if UseTwoKeys is set to True");
			characterSelectorKey = new DelegatedConfigEntry<KeyboardShortcut>();
			characterSelectorKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "CreatureSelectorShortcut", characterSelectorKeyDefault, "Keyboard shortcut to rotate through TrainableCreatures list. If UseMouseWheel is set to True, hold this key down and use the mouse wheel to change creatures. If UseMouseWheel is set to False, press this key to cycle between creatures");
			packAttackKey = new DelegatedConfigEntry<KeyboardShortcut>();
			packAttackKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "TamesAttackShortcut", packAttackKeyDefault, "Keyboard shortcut to send tames to attack target being hovered over.");
			disableTameNameFiltering = _instance.Config.Bind<bool>("Utility", "DisableNameFiltering", true, "TEMPORARY fix for [PlatformUserID \"\" failed to parse!] spammed error in current Valheim release. CAVEAT bypasses content filtering for tame names.");
			twoKeyAction = _instance.Config.Bind<bool>("General", "UseTwoKeys", false, "True or False to use separate keys for Follow and Stay. If set to True, will use the shortcut defined in AlternateStayShortcut to cause pack to Stay");
			minimumCreatureLevel = _instance.Config.Bind<int>("General", "MinimumCreatureLevel", 0, new ConfigDescription("Lowest level (in 'stars') of creature affected, e.g., 0 = no stars, 1 = 1 star, 2 = 2 stars. NOTE: applied to all creatures. Min 0; Max 2", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2), Array.Empty<object>()));
			useMouseWheel = _instance.Config.Bind<bool>("General", "UseMouseWheel", true, "Set to True or False to use mouse wheel to switch between called creatures. When set to True, hold the CreatureSelectorShortcut while spinning the mouse wheel.");
			notifications = _instance.Config.Bind<string>("General", "Notifications", "Center", new ConfigDescription("Area where creature selection notifications appear. Can be 'TopLeft' or 'Center'. Default is Center", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Center", "TopLeft" }), Array.Empty<object>()));
			strictObedience = _instance.Config.Bind<int>("General", "StrictObedience", 10, new ConfigDescription("Max distance 'Stayed' creatures will stray. Set to 0 for NO wandering. Default is 10. Min 0; Max 20", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
			scrollDelay = _instance.Config.Bind<int>("Utility", "MouseWheelLatency", 3, new ConfigDescription("Controls how sensitive the mouse wheel is when selecting creatures. Increase if too sensitive, decrease if too sluggish. Min 0; Max 10", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>()));
			logCreatures = _instance.Config.Bind<bool>("Utility", "LogCreatureNames", false, "If set to True, will write all located creature names to the logger. Intended for temporary use to identify creature names to add to the TrainableCreatureList.");
			disableTameNameFiltering = _instance.Config.Bind<bool>("Utility", "DisableNameFiltering", false, "TEMPORARY fix for [PlatformUserID \"\" failed to parse!] spammed error in current Valheim release. CAVEAT bypasses content filtering for creature names.");
			useSound = _instance.Config.Bind<bool>("Audio", "UseSound", true, "True or False to enable wolf follow sound effect");
			wolfCallSound = _instance.Config.Bind<string>("Audio", "PackCallSound", "Whistle.wav", "Audio file played when creatures are called to Follow. [Choose Whistle.wav, Horn1.wav, or Horn2.wav]");
			ServerConfiguration.Instance.CreateConfigWatcher();
		}

		public static void ChangeLogging(object s, EventArgs e)
		{
			SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null);
			WolfPack.Log.Debug($"ChangeLog {val.ChangedSetting.Definition.Key} to {val.ChangedSetting.BoxedValue}");
			WolfPack.Log.LogLevel = debugLevel.Value;
		}
	}
	internal class CreatureMatcher
	{
		private string mPrefix = "$enemy_";

		private string pSuffix = "(clone)";

		private static CreatureMatcher _instance;

		public int MatchType { get; private set; }

		public string Matching { get; private set; }

		public string Name { get; private set; }

		public string HoverName { get; private set; }

		public string PrefixName { get; private set; }

		public static CreatureMatcher Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new CreatureMatcher();
				}
				return _instance;
			}
		}

		private CreatureMatcher()
		{
		}

		public void Config(string matchName)
		{
			MatchType = 1;
			Matching = matchName;
			if (matchName.Equals("*"))
			{
				MatchType = 3;
			}
			else if (matchName.StartsWith("*") && matchName.EndsWith("*") && matchName.Length > 2)
			{
				Matching = matchName.Substring(1).Substring(0, matchName.Length - 2);
				MatchType = 5;
			}
			else if (matchName.StartsWith("*") && matchName.Length > 1)
			{
				Matching = matchName.Substring(1);
				MatchType = 2;
			}
			else if (matchName.EndsWith("*") && matchName.Length > 1)
			{
				Matching = matchName.Substring(0, matchName.Length - 1);
				MatchType = 4;
			}
		}

		public bool Match(Character aCharacter)
		{
			Name = aCharacter.m_name.ToLower();
			HoverName = aCharacter.GetHoverName().ToLower();
			PrefixName = ((Object)((Component)aCharacter).gameObject).name.ToLower();
			if (Name.StartsWith(mPrefix))
			{
				Name = Name.Substring(mPrefix.Length);
			}
			if (PrefixName.EndsWith(pSuffix))
			{
				PrefixName = PrefixName.Substring(0, PrefixName.Length - pSuffix.Length);
			}
			List<string> list = new List<string> { Name, HoverName, PrefixName };
			bool flag = false;
			return MatchType switch
			{
				1 => list.Exists((string n) => n.Equals(Matching)), 
				2 => list.Exists((string n) => n.EndsWith(Matching)), 
				3 => true, 
				4 => list.Exists((string n) => n.StartsWith(Matching)), 
				5 => list.Exists((string n) => n.Contains(Matching)), 
				_ => false, 
			};
		}
	}
	internal class DebugUtils
	{
		public static void ObjectInspector(object o)
		{
			if (o == null)
			{
				Debug.Log((object)"Object is null");
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			Type type = o.GetType();
			Debug.Log((object)(o.ToString() + " Type " + type.Name));
			PropertyInfo[] properties = type.GetProperties(bindingAttr);
			foreach (PropertyInfo propertyInfo in properties)
			{
				Debug.Log((object)$"{type.Name}.{propertyInfo.Name} = {propertyInfo.GetValue(o)}");
			}
			FieldInfo[] fields = type.GetFields(bindingAttr);
			foreach (FieldInfo field in fields)
			{
				FieldPrinter(o, type, field);
			}
		}

		public static void MethodInspector(object o)
		{
			if (o == null)
			{
				Debug.Log((object)"Object is null");
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			Type type = o.GetType();
			Debug.Log((object)(o.ToString() + " Type " + type.Name));
			MethodInfo[] methods = type.GetMethods(bindingAttr);
			foreach (MethodInfo methodInfo in methods)
			{
				methodInfo.GetParameters();
				string arg = string.Join(", ", (from x in methodInfo.GetParameters()
					select x.ParameterType?.ToString() + " " + x.Name).ToArray());
				Debug.Log((object)$"{methodInfo.ReturnType} {methodInfo.Name} ({arg})");
			}
		}

		private static void ItemDataInspector(ItemData item)
		{
			ObjectInspector(item);
			ObjectInspector(item.m_shared);
		}

		private static void FieldPrinter(object o, Type t, FieldInfo field)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			try
			{
				if (field.FieldType == typeof(ItemData))
				{
					ItemData val = (ItemData)field.GetValue(o);
					if (val != null)
					{
						ItemDataInspector(val);
					}
					else
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
					}
				}
				else if (field.FieldType == typeof(Transform))
				{
					Transform val2 = (Transform)field.GetValue(o);
					if ((Object)(object)val2 != (Object)null)
					{
						Debug.Log((object)("\tTransform.parent = " + ((Object)val2.parent).name));
					}
					else
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
					}
				}
				else if (field.FieldType == typeof(EffectList))
				{
					EffectList val3 = (EffectList)field.GetValue(o);
					if (val3 != null)
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}:");
						EffectData[] effectPrefabs = val3.m_effectPrefabs;
						foreach (EffectData val4 in effectPrefabs)
						{
							Debug.Log((object)("\tEffectData.m_prefab = " + ((Object)val4.m_prefab).name));
						}
					}
					else
					{
						Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
					}
				}
				else
				{
					Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}");
				}
			}
			catch (Exception)
			{
				Debug.Log((object)("Exception accessing " + t?.Name + "." + field?.Name));
			}
		}

		public static void GameObjectInspector(GameObject go)
		{
			Debug.Log((object)("\n\nInspecting GameObject " + ((Object)go).name));
			ObjectInspector(go);
			Component[] componentsInChildren = go.GetComponentsInChildren<Component>();
			foreach (Component val in componentsInChildren)
			{
				string obj = ((val != null) ? ((Object)val).name : null);
				object obj2;
				if (val == null)
				{
					obj2 = null;
				}
				else
				{
					Transform transform = val.transform;
					if (transform == null)
					{
						obj2 = null;
					}
					else
					{
						Transform parent = transform.parent;
						obj2 = ((parent != null) ? ((Object)parent).name : null);
					}
				}
				Debug.Log((object)("\n\nInspecting Component " + obj + " with parent " + (string?)obj2));
				ObjectInspector(val);
			}
		}

		public static void ComponentInspector(Component c)
		{
			Debug.Log((object)("\n\nInspecting Component " + ((Object)c).name));
			ObjectInspector(c);
		}

		public static void EffectsInspector(EffectList e)
		{
			EffectData[] effectPrefabs = e.m_effectPrefabs;
			Debug.Log((object)$"Effect list has effects {e.HasEffects()} count {effectPrefabs.Length}");
			EffectData[] array = effectPrefabs;
			foreach (EffectData val in array)
			{
				Debug.Log((object)$"Effect Data {val} prefab name {((Object)val.m_prefab).name} prefab GameObject name {((Object)val.m_prefab.gameObject).name}");
			}
		}

		public static void PrintInventory()
		{
			foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems())
			{
				Debug.Log((object)allItem.m_shared.m_name);
			}
		}

		public static void PrintAllObjects()
		{
			ZNetScene.instance.m_prefabs.ForEach(delegate(GameObject x)
			{
				Debug.Log((object)("GameObject " + ((Object)x).name));
			});
		}

		public static void PrintAllCharacters()
		{
			Character.GetAllCharacters().ForEach(delegate(Character x)
			{
				Debug.Log((object)("Character " + ((Object)x).name));
			});
		}
	}
	internal class WolfAudio
	{
		public static void CallOfTheWild(Player sourcePlayer, string clipName)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)sourcePlayer).gameObject.transform.position;
			CallOfTheWild(position, position, clipName);
		}

		public static void CallOfTheWild(Player sourcePlayer, Player targetPlayer, string clipName)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)sourcePlayer).gameObject.transform.position;
			Vector3 position2 = ((Component)targetPlayer).gameObject.transform.position;
			CallOfTheWild(position, position2, clipName);
		}

		public static void CallOfTheWild(Vector3 sourcePoint, Vector3 targetPoint, string clipName)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (Cfg.useSound.Value)
			{
				Logging.GetLogger().Debug("CallOfTheWild\n");
				Vector3 val = sourcePoint - targetPoint;
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				float num = (Vector3.Distance(sourcePoint, targetPoint) + 1f) / 10f;
				if (WolfPack.audioClips.TryGetValue(clipName.ToLower(), out var value))
				{
					AudioSource.PlayClipAtPoint(value, targetPoint + normalized * num, 1f);
				}
			}
		}
	}
	[BepInPlugin("neobotics.valheim_mod.wolfpack", "Wolfpack", "1.1.4")]
	[BepInProcess("valheim.exe")]
	[BepInProcess("valheim_server.exe")]
	public class WolfPack : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Tameable), "GetText")]
		private static class Tameable_GetText_Patch
		{
			[HarmonyPrefix]
			private static bool Tameable_GetText_Prefix(Tameable __instance, out string __result)
			{
				__result = "";
				if (!Cfg.disableTameNameFiltering.Value)
				{
					return true;
				}
				ZNetView nview = __instance.m_nview;
				if (!nview.IsValid())
				{
					return false;
				}
				__result = nview.GetZDO().GetString(ZDOVars.s_tamedName, "");
				return false;
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "UpdateTarget")]
		private static class MonsterAI_UpdateTarget_Patch
		{
			[HarmonyPrefix]
			private static void MonsterAI_UpdateTarget_Prefix(MonsterAI __instance, Humanoid humanoid, float dt, out float __state)
			{
				__state = __instance.m_alertRange;
				if (!((Object)(object)s_targetGameObject == (Object)null) && (Object)(object)__instance.m_follow == (Object)(object)((Component)Player.m_localPlayer).gameObject)
				{
					__instance.m_alertRange = 100f;
				}
			}

			[HarmonyPostfix]
			private static void MonsterAI_UpdateTarget_Postfix(MonsterAI __instance, Humanoid humanoid, float dt, ref float __state)
			{
				__instance.m_alertRange = __state;
			}
		}

		[HarmonyPatch(typeof(Tameable), "Command")]
		private static class Tameable_Command_Patch
		{
			[HarmonyPrefix]
			private static bool Tameable_Command_Prefix(Tameable __instance, Humanoid user, bool message)
			{
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				Log.Debug("Tameable_Command_Patch_Prefix");
				Player localPlayer = Player.m_localPlayer;
				ZNetView nview = __instance.m_nview;
				ZDO val = ((nview != null) ? nview.GetZDO() : null);
				if (val == null)
				{
					return true;
				}
				string @string = val.GetString(ZDOVars.s_follow, "");
				Log.Debug($"Current player: {localPlayer.GetPlayerID()} wolf owned by: {val.GetOwner()} wolf following {@string}");
				if (string.IsNullOrEmpty(@string))
				{
					List<Character> list = new List<Character>();
					Character.GetCharactersInRange(((Component)localPlayer).transform.position, (float)Cfg.detectionRange.Value, list);
					int playerTamesCount = GetPlayerTamesCount((Humanoid)(object)localPlayer, list);
					Log.Debug($"Number following {playerTamesCount}");
					if (playerTamesCount >= Cfg.maxTames.Value)
					{
						Log.Debug("Tame follow count at max. Skipping.");
						return false;
					}
					return true;
				}
				if (@string != localPlayer.GetPlayerName() && Cfg.restrictPetting.Value)
				{
					Log.Debug("It's not my tame. Can't Stay");
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(BaseAI), "Follow")]
		private static class BaseAI_Follow_Patch
		{
			[HarmonyPrefix]
			private static bool BaseAI_Follow_Prefix(BaseAI __instance, GameObject go, float dt)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				Player val = default(Player);
				if (__instance.m_character.m_tamed && go.TryGetComponent<Player>(ref val))
				{
					Log.Trace("Tame following player");
					float num = Vector3.Distance(go.transform.position, ((Component)__instance.m_character).transform.position);
					bool flag = num > 10f;
					if (num < 3f)
					{
						__instance.StopMoving();
					}
					else
					{
						Vector2 val2 = Random.insideUnitCircle * (float)Cfg.followRadius.Value;
						Vector3 val3 = default(Vector3);
						((Vector3)(ref val3))..ctor(val2.x + go.transform.position.x, go.transform.position.y, val2.y + go.transform.position.z);
						__instance.MoveTo(dt, val3, 0f, flag);
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static class Camera_Update_Patch
		{
			private static bool keyWasDown;

			private static float zoomSensitivity;

			private static void Prefix(GameCamera __instance, float dt, ref float ___m_zoomSens)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if (Cfg.useMouseWheel.Value)
				{
					KeyboardShortcut value = Cfg.characterSelectorKey.Value;
					if (((KeyboardShortcut)(ref value)).IsPressed())
					{
						if (!keyWasDown)
						{
							zoomSensitivity = ___m_zoomSens;
							___m_zoomSens = 0f;
							keyWasDown = true;
						}
						return;
					}
				}
				if (keyWasDown)
				{
					___m_zoomSens = zoomSensitivity;
					keyWasDown = false;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private class PatchOnNewConnection_Patch
		{
			private static void Postfix(ZNetPeer peer, ZNet __instance)
			{
				if (Log.LogLevel >= Logging.LogLevels.Debug)
				{
					Log.Debug("OnNewConnection_Patch");
				}
				if (__instance.IsServer() && serverIsRegistered)
				{
					return;
				}
				try
				{
					ZRoutedRpc.instance.Register<ZDOID, string>("WolfCall", (Action<long, ZDOID, string>)RPC_WolfCall);
					if (__instance.IsServer())
					{
						serverIsRegistered = true;
					}
				}
				catch (Exception)
				{
					Log.Warning("Attempt to re-register RPCs");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		public class Player_Update_Patch
		{
			private static void Prefix(Player __instance)
			{
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_024b: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)__instance == (Object)(object)Player.m_localPlayer))
				{
					return;
				}
				if (Cfg.packAttackRange.Value > 0 && Cfg.packAttackKey.IsKeyPressed())
				{
					Log.Debug("Pack attack key pressed");
					AttackHoverTarget(__instance);
					return;
				}
				if (!Cfg.useMouseWheel.Value)
				{
					if (Cfg.characterSelectorKey.IsKeyPressed())
					{
						Log.Debug("WolfPack selector key pressed");
						if (trainables.Count > 0)
						{
							currentCreatureIndex = ++currentCreatureIndex % trainables.Count;
							NotifyCreatureChange(__instance);
						}
					}
				}
				else if (Cfg.characterSelectorKey.IsKeyDown())
				{
					float y = Input.mouseScrollDelta.y;
					Log.Debug($"Character selector key pressed with mouse wheel enabled: mouse scroll delta:{y}");
					if (y != 0f)
					{
						if (y > 0f && lastMouseWheelDelta <= 0f)
						{
							currentCreatureIndex = ((currentCreatureIndex < trainables.Count - 1) ? (++currentCreatureIndex) : 0);
						}
						if (y < 0f && lastMouseWheelDelta >= 0f)
						{
							currentCreatureIndex = ((currentCreatureIndex <= 0) ? (trainables.Count - 1) : (--currentCreatureIndex));
						}
						lastMouseWheelDelta = y;
						frameDelay = Cfg.scrollDelay.Value;
						NotifyCreatureChange(__instance);
					}
					else if (frameDelay > 0)
					{
						frameDelay--;
					}
					else
					{
						lastMouseWheelDelta = 0f;
					}
				}
				bool flag = false;
				if (Cfg.twoKeyAction.Value)
				{
					bool num = Cfg.packBehaviorKey.IsKeyPressed();
					bool flag2 = Cfg.packStayKey.IsKeyPressed();
					if (num)
					{
						Log.Debug("WolfPack 2 key follow pressed");
						packFollow = true;
					}
					else if (flag2)
					{
						Log.Debug("WolfPack 2 key stay pressed");
						packFollow = false;
					}
					flag = num || flag2;
				}
				else
				{
					flag = Cfg.packBehaviorKey.IsKeyPressed();
				}
				if (!flag)
				{
					return;
				}
				Log.Debug("WolfPack pack behavior key pressed");
				try
				{
					if (Log.LogLevel >= Logging.LogLevels.Debug)
					{
						Log.Debug("Player_Update_Patch.Prefix");
						Log.Trace($"Keypress Player ID {__instance.GetPlayerID()} Name {__instance.GetPlayerName()} ZDOID {((Character)__instance).GetZDOID()}");
					}
					Local_CommandWolves(__instance, trainables[currentCreatureIndex], packFollow);
					((Character)__instance).Message((MessageType)2, packFollow ? (creatureMessage + " follow you") : (creatureMessage + " stay"), 0, (Sprite)null);
				}
				catch (Exception e)
				{
					Log.Error(e, stackTrace: false);
				}
				if (!Cfg.twoKeyAction.Value)
				{
					packFollow = !packFollow;
				}
			}
		}

		[CompilerGenerated]
		private sealed class <Co_CommandWolves>d__31 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public List<Character> selectedCreatures;

			public Player aPlayer;

			public bool commandIsFollow;

			private List<Character>.Enumerator <>7__wrap1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Co_CommandWolves>d__31(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = default(List<Character>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						Log.Debug("Co_CommandWolves");
						<>7__wrap1 = selectedCreatures.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap1.MoveNext())
					{
						Character current = <>7__wrap1.Current;
						UpdateWolfAI(aPlayer, current, commandIsFollow);
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap1 = default(List<Character>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap1).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <Co_LoadAudio>d__26 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string filePath;

			public string[] audioFiles;

			private UnityWebRequest <URL>5__2;

			private int <f>5__3;

			private string <clipUri>5__4;

			private string <clipName>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Co_LoadAudio>d__26(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<URL>5__2 = null;
				<clipUri>5__4 = null;
				<clipName>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<URL>5__2 = null;
					Log.Debug("Co_LoadAudio loading files from " + filePath);
					<f>5__3 = 0;
					break;
				case 1:
					<>1__state = -1;
					if (<URL>5__2 != null)
					{
						try
						{
							AudioClip content = DownloadHandlerAudioClip.GetContent(<URL>5__2);
							audioClips.Add(<clipName>5__5.ToLower(), content);
						}
						catch (Exception ex)
						{
							Log.Warning("Failed to load clip " + <clipUri>5__4 + ": " + ex.Message);
						}
					}
					else
					{
						Log.Warning("Failed to get URL for " + <clipUri>5__4);
					}
					<clipUri>5__4 = null;
					<clipName>5__5 = null;
					<f>5__3++;
					break;
				}
				if (<f>5__3 < audioFiles.Length)
				{
					<clipUri>5__4 = new Uri(audioFiles[<f>5__3]).AbsoluteUri;
					<clipName>5__5 = audioFiles[<f>5__3].Substring(filePath.Length + 1);
					Log.Debug("Loading audio clip " + <clipName>5__5);
					try
					{
						<URL>5__2 = UnityWebRequestMultimedia.GetAudioClip(<clipUri>5__4, (AudioType)0);
					}
					catch (Exception ex2)
					{
						Log.Warning("Can't find audio resource: " + ex2.Message);
					}
					<>2__current = <URL>5__2.SendWebRequest();
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public static string Mod = "WolfPack";

		public static Logging Log;

		private readonly Harmony harmony = new Harmony("neobotics.valheim_mod.wolfpack");

		private static WolfPack _modinstance;

		private static volatile bool packFollow = true;

		private static string creatureMessage = null;

		private static int currentCreatureIndex = 0;

		private static List<string> trainables = new List<string>();

		private static float lastMouseWheelDelta = 0f;

		private static int frameDelay = 0;

		private static Random rand = new Random();

		private static List<string> RPCs = new List<string>();

		private static bool serverIsRegistered = false;

		public static GameObject s_targetGameObject = null;

		public const float TARGET_MAX_RANGE = 100f;

		public static Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();

		private static Dictionary<string, MessageType> notifyLocation = new Dictionary<string, MessageType>
		{
			{
				"topleft",
				(MessageType)1
			},
			{
				"center",
				(MessageType)2
			}
		};

		public static WolfPack Instance => _modinstance;

		private void Awake()
		{
			_modinstance = this;
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			ConfigureMod();
			Log.Debug("awake");
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
		}

		private void ConfigureMod()
		{
			Log = Logging.GetLogger(Logging.LogLevels.Info, Mod);
			Cfg.BepInExConfig((BaseUnityPlugin)(object)_modinstance);
			LoadTrainableCreatureList(Cfg.trainableCreatures.Value);
			if (Cfg.useSound.Value)
			{
				LoadAudioResources();
			}
		}

		internal static void ChangeTrainables(object s, EventArgs e)
		{
			SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null);
			Log.Debug($"ChangeInt {val.ChangedSetting.Definition.Key} to {val.ChangedSetting.BoxedValue}");
			_modinstance.LoadTrainableCreatureList(Cfg.trainableCreatures.Value);
		}

		private static bool OkToKey(Player player)
		{
			if (!((Character)player).InPlaceMode() && !Chat.instance.HasFocus() && !Console.IsVisible() && (Object)(object)TextViewer.instance != (Object)null && !TextViewer.instance.IsVisible() && !((Character)player).InCutscene() && !GameCamera.InFreeFly() && !Minimap.IsOpen() && !Menu.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible())
			{
				return !StoreGui.IsVisible();
			}
			return false;
		}

		private static void KeypressEntryPoint()
		{
			_ = Player.m_localPlayer;
			Log.Debug("KeypressEntryPoint");
		}

		private void LoadAudioResources()
		{
			FileInfo fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
			string[] array = new string[0];
			Dictionary<string, AudioType> obj = new Dictionary<string, AudioType>
			{
				{
					"*.wav",
					(AudioType)20
				},
				{
					"*.mp3",
					(AudioType)13
				}
			};
			string directoryName = fileInfo.DirectoryName;
			audioClips.Clear();
			Log.Debug("LoadAudioResources");
			foreach (string key in obj.Keys)
			{
				array = CollectionExtensions.AddRangeToArray<string>(array, Directory.GetFiles(fileInfo.DirectoryName, key, SearchOption.TopDirectoryOnly));
			}
			((MonoBehaviour)this).StartCoroutine(Co_LoadAudio(directoryName, array));
		}

		[IteratorStateMachine(typeof(<Co_LoadAudio>d__26))]
		private IEnumerator Co_LoadAudio(string filePath, string[] audioFiles)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Co_LoadAudio>d__26(0)
			{
				filePath = filePath,
				audioFiles = audioFiles
			};
		}

		private void LoadTrainableCreatureList(string trainable)
		{
			trainables.Clear();
			string[] array = trainable.ToLower().Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			string empty = string.Empty;
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string item = array2[i].Trim();
				trainables.Add(item);
			}
			if (!Utility.IsNullOrWhiteSpace(Cfg.lastCalledCreature.Value) && trainables.Contains(Cfg.lastCalledCreature.Value))
			{
				empty = Cfg.lastCalledCreature.Value;
				currentCreatureIndex = trainables.IndexOf(empty);
			}
			else
			{
				empty = trainables[0];
			}
			creatureMessage = WolfUtils.Pluralizer(empty);
		}

		private static void SetPlayerTamesAttack(Humanoid player, Character target)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if (!IsValidTarget(target, (Character)(object)player))
			{
				return;
			}
			Log.Debug("Valid target found");
			Vector3 val = ((Component)target).transform.position - ((Component)player).transform.position;
			((Character)player).SetLookDir(val, 2f);
			Emote.DoEmote((Emotes)6);
			List<Character> list = new List<Character>();
			Character.GetCharactersInRange(((Component)player).transform.position, (float)Cfg.detectionRange.Value, list);
			MonsterAI val2 = default(MonsterAI);
			foreach (Character i