Decompiled source of CaptainValheim v1.0.0

CaptainValheim.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CaptainValheim")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyProduct("CaptainValheim")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => _items.Length;

	T IReadOnlyList<T>.this[int index] => _items[index];

	int ICollection<T>.Count => _items.Length;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlyArray(T[] items)
	{
		_items = items;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return ((IEnumerable)_items).GetEnumerator();
	}

	void ICollection.CopyTo(Array array, int index)
	{
		((ICollection)_items).CopyTo(array, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return ((IList)_items).Contains(value);
	}

	int IList.IndexOf(object value)
	{
		return ((IList)_items).IndexOf(value);
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return ((IEnumerable<T>)_items).GetEnumerator();
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return ((ICollection<T>)_items).Contains(item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		((ICollection<T>)_items).CopyTo(array, arrayIndex);
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		return ((IList<T>)_items).IndexOf(item);
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
	{
		object IEnumerator.Current => _item;

		T IEnumerator<T>.Current => _item;

		public Enumerator(T item)
		{
			_item = item;
		}

		bool IEnumerator.MoveNext()
		{
			if (!_moveNextCalled)
			{
				return _moveNextCalled = true;
			}
			return false;
		}

		void IEnumerator.Reset()
		{
			_moveNextCalled = false;
		}

		void IDisposable.Dispose()
		{
		}
	}

	int ICollection.Count => 1;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => 1;

	T IReadOnlyList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
	}

	int ICollection<T>.Count => 1;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlySingleElementList(T item)
	{
		_item = item;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		array.SetValue(_item, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return EqualityComparer<T>.Default.Equals(_item, (T)value);
	}

	int IList.IndexOf(object value)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
		{
			return -1;
		}
		return 0;
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return EqualityComparer<T>.Default.Equals(_item, item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		array[arrayIndex] = _item;
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, item))
		{
			return -1;
		}
		return 0;
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class ExtensionMarkerAttribute : Attribute
	{
		private readonly string <Name>k__BackingField;

		public string Name => <Name>k__BackingField;

		public ExtensionMarkerAttribute(string name)
		{
			<Name>k__BackingField = name;
		}
	}
}
namespace CaptainValheim
{
	internal sealed class KeyHintCell
	{
		private readonly List<TMP_Text> _keys = new List<TMP_Text>();

		private readonly List<GameObject> _keyParents = new List<GameObject>();

		private readonly List<TMP_Text> _extraTexts = new List<TMP_Text>();

		private readonly List<TMP_Text> _generatedSeparatorTexts = new List<TMP_Text>();

		private TMP_Text? _label;

		internal GameObject Root { get; }

		private KeyHintCell(GameObject root)
		{
			Root = root;
			RefreshChildren();
		}

		internal static KeyHintCell? CloneFrom(GameObject? template, string name)
		{
			if (!IsUsableTemplate(template) || (Object)(object)template.transform.parent == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(template, template.transform.parent, false);
			((Object)obj).name = name;
			obj.SetActive(false);
			return new KeyHintCell(obj);
		}

		internal static bool IsUsableTemplate(GameObject? template)
		{
			if ((Object)(object)template != (Object)null && (Object)(object)template.transform.parent != (Object)null && !((Object)template).name.StartsWith("CaptainValheim_"))
			{
				return template.GetComponentsInChildren<TMP_Text>(true).Length != 0;
			}
			return false;
		}

		internal static Transform? FindParentWithTemplates(GameObject root, string name)
		{
			Transform val = root.transform.Find(name);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if (!((IEnumerable)val).Cast<Transform>().Any((Transform child) => IsUsableTemplate(((Component)child).gameObject)))
			{
				return null;
			}
			return val;
		}

		internal void Set(string label, IReadOnlyList<string> keys, float preferredTextWidth = 0f, bool hideExtraTexts = false)
		{
			EnsureKeyCount(keys.Count);
			Root.SetActive(true);
			if ((Object)(object)_label != (Object)null)
			{
				SetText(_label, label);
				LayoutElement val = default(LayoutElement);
				if (preferredTextWidth > 0f && ((Component)_label).TryGetComponent<LayoutElement>(ref val))
				{
					val.preferredWidth = preferredTextWidth;
				}
			}
			for (int i = 0; i < _keys.Count; i++)
			{
				bool flag = i < keys.Count;
				if (i < _keyParents.Count && (Object)(object)_keyParents[i] != (Object)null)
				{
					_keyParents[i].SetActive(flag);
				}
				if (flag)
				{
					SetText(_keys[i], keys[i]);
				}
			}
			if (hideExtraTexts)
			{
				foreach (TMP_Text extraText in _extraTexts)
				{
					if ((Object)(object)extraText != (Object)null)
					{
						((Component)extraText).gameObject.SetActive(false);
					}
				}
				return;
			}
			EnsureSeparatorCount(Mathf.Max(0, keys.Count - 1));
			for (int j = 0; j < _generatedSeparatorTexts.Count; j++)
			{
				TMP_Text val2 = _generatedSeparatorTexts[j];
				if (!((Object)(object)val2 == (Object)null))
				{
					bool flag2 = j < keys.Count - 1;
					((Component)val2).gameObject.SetActive(flag2);
					if (flag2)
					{
						SetText(val2, "+");
					}
				}
			}
			foreach (TMP_Text extraText2 in _extraTexts)
			{
				if ((Object)(object)extraText2 != (Object)null)
				{
					((Component)extraText2).gameObject.SetActive(keys.Count > 1);
				}
			}
		}

		internal void SetActive(bool active)
		{
			if ((Object)(object)Root != (Object)null)
			{
				Root.SetActive(active);
			}
		}

		internal void MoveBefore(GameObject? template)
		{
			if (!((Object)(object)template == (Object)null) && !((Object)(object)Root == (Object)null) && !((Object)(object)Root == (Object)(object)template) && !((Object)(object)Root.transform.parent != (Object)(object)template.transform.parent))
			{
				int siblingIndex = Root.transform.GetSiblingIndex();
				int siblingIndex2 = template.transform.GetSiblingIndex();
				int num = ((siblingIndex < siblingIndex2) ? (siblingIndex2 - 1) : siblingIndex2);
				if (siblingIndex != num)
				{
					Root.transform.SetSiblingIndex(Mathf.Max(0, num));
				}
			}
		}

		internal void RebuildParentLayout()
		{
			if ((Object)(object)Root != (Object)null)
			{
				Transform parent = Root.transform.parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if (val != null)
				{
					LayoutRebuilder.ForceRebuildLayoutImmediate(val);
				}
			}
		}

		private void EnsureKeyCount(int count)
		{
			RefreshChildren();
			if (count <= _keys.Count || _keyParents.Count == 0)
			{
				return;
			}
			GameObject val = _keyParents[0];
			Transform parent = val.transform.parent;
			while (_keys.Count < count)
			{
				((Object)Object.Instantiate<GameObject>(val, parent, false)).name = ((_keys.Count == 1) ? "key_bkg (1)" : $"key_bkg ({_keys.Count})");
				RefreshChildren();
				if (_keys.Count == 0)
				{
					break;
				}
			}
		}

		private void EnsureSeparatorCount(int count)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (count <= 0 || _keyParents.Count == 0 || _extraTexts.Count > 0)
			{
				return;
			}
			Transform parent = _keyParents[0].transform.parent;
			TMP_Text val = ResolveSeparatorTemplateText();
			if ((Object)(object)parent == (Object)null || (Object)(object)val == (Object)null)
			{
				return;
			}
			while (_generatedSeparatorTexts.Count < count)
			{
				GameObject val2 = new GameObject($"CaptainValheim_KeyHintSeparator_{_generatedSeparatorTexts.Count}");
				val2.SetActive(false);
				val2.transform.SetParent(parent, false);
				val2.AddComponent<RectTransform>().sizeDelta = new Vector2(18f, 24f);
				TextMeshProUGUI val3 = val2.AddComponent<TextMeshProUGUI>();
				CopyTextStyle(val, (TMP_Text)(object)val3);
				((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
				((Graphic)val3).raycastTarget = false;
				((TMP_Text)val3).text = "+";
				LayoutElement obj = val2.AddComponent<LayoutElement>();
				obj.preferredWidth = 18f;
				obj.minWidth = 12f;
				_generatedSeparatorTexts.Add((TMP_Text)(object)val3);
			}
			for (int i = 0; i < _generatedSeparatorTexts.Count; i++)
			{
				TMP_Text val4 = _generatedSeparatorTexts[i];
				if (!((Object)(object)val4 == (Object)null))
				{
					int num = Mathf.Min(i + 1, _keyParents.Count - 1);
					if (num >= 0 && num < _keyParents.Count && (Object)(object)_keyParents[num] != (Object)null)
					{
						val4.transform.SetSiblingIndex(_keyParents[num].transform.GetSiblingIndex());
					}
				}
			}
		}

		private TMP_Text? ResolveSeparatorTemplateText()
		{
			return GetStyleTemplate(_label) ?? _keys.Select(GetStyleTemplate).FirstOrDefault<TMP_Text>((Func<TMP_Text, bool>)((TMP_Text text) => (Object)(object)text != (Object)null)) ?? GetStyleTemplate(((IEnumerable<TMP_Text>)Root.GetComponentsInChildren<TMP_Text>(true)).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text text) => (Object)(object)text != (Object)null && (Object)(object)text.font != (Object)null))) ?? _label ?? _keys.FirstOrDefault();
		}

		private static TMP_Text? GetStyleTemplate(TMP_Text? text)
		{
			if (!((Object)(object)text != (Object)null) || !((Object)(object)text.font != (Object)null))
			{
				return null;
			}
			return text;
		}

		private static void CopyTextStyle(TMP_Text source, TMP_Text target)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			target.font = source.font;
			target.fontSharedMaterial = source.fontSharedMaterial;
			target.fontSize = source.fontSize;
			target.fontSizeMin = source.fontSizeMin;
			target.fontSizeMax = source.fontSizeMax;
			target.enableAutoSizing = source.enableAutoSizing;
			target.fontStyle = source.fontStyle;
			target.fontWeight = source.fontWeight;
			((Graphic)target).color = ((Graphic)source).color;
			target.characterSpacing = source.characterSpacing;
			target.wordSpacing = source.wordSpacing;
			target.lineSpacing = source.lineSpacing;
			target.paragraphSpacing = source.paragraphSpacing;
			target.textWrappingMode = source.textWrappingMode;
			target.overflowMode = source.overflowMode;
		}

		private void RefreshChildren()
		{
			_keys.Clear();
			_keyParents.Clear();
			_extraTexts.Clear();
			_label = null;
			TMP_Text[] array = (from text in Root.GetComponentsInChildren<TMP_Text>(true)
				where (Object)(object)text != (Object)null
				select text).ToArray();
			TMP_Text[] array2 = array;
			foreach (TMP_Text val in array2)
			{
				Localization instance = Localization.instance;
				if (instance != null)
				{
					instance.RemoveTextFromCache(val);
				}
				TextMeshProUGUI val2 = (TextMeshProUGUI)(object)((val is TextMeshProUGUI) ? val : null);
				if (val2 != null)
				{
					((Graphic)val2).raycastTarget = false;
				}
			}
			_keys.AddRange(array.Where((TMP_Text text) => string.Equals(((Object)text).name, "Key", StringComparison.OrdinalIgnoreCase)));
			if (_keys.Count == 0)
			{
				TMP_Text val3 = ((IEnumerable<TMP_Text>)array).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text text) => LooksLikeKeyBindingText(text.text))) ?? array.OrderBy((TMP_Text text) => text.transform.position.x).LastOrDefault();
				if ((Object)(object)val3 != (Object)null && array.Length > 1)
				{
					_keys.Add(val3);
				}
			}
			_label = ((IEnumerable<TMP_Text>)array).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text text) => string.Equals(((Object)text).name, "Text", StringComparison.OrdinalIgnoreCase) && !_keys.Contains(text))) ?? ((IEnumerable<TMP_Text>)array).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text text) => !_keys.Contains(text) && !LooksLikeKeyBindingText(text.text))) ?? ((IEnumerable<TMP_Text>)array).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text text) => !_keys.Contains(text)));
			foreach (TMP_Text key in _keys)
			{
				_keyParents.Add(((Object)(object)key.transform.parent != (Object)null) ? ((Component)key.transform.parent).gameObject : ((Component)key).gameObject);
			}
			_extraTexts.AddRange(array.Where((TMP_Text text) => (Object)(object)text != (Object)(object)_label && !_keys.Contains(text)));
			SortKeysBySiblingIndex();
		}

		private void SortKeysBySiblingIndex()
		{
			List<int> list = (from i in Enumerable.Range(0, _keys.Count)
				orderby (!((Object)(object)_keyParents[i] != (Object)null)) ? i : _keyParents[i].transform.GetSiblingIndex()
				select i).ToList();
			if (list.Count <= 1)
			{
				return;
			}
			List<TMP_Text> list2 = new List<TMP_Text>();
			List<GameObject> list3 = new List<GameObject>();
			foreach (int item in list)
			{
				list2.Add(_keys[item]);
				list3.Add(_keyParents[item]);
			}
			_keys.Clear();
			_keys.AddRange(list2);
			_keyParents.Clear();
			_keyParents.AddRange(list3);
		}

		private static void SetText(TMP_Text? text, string value)
		{
			if (!((Object)(object)text == (Object)null))
			{
				Localization instance = Localization.instance;
				if (instance != null)
				{
					instance.RemoveTextFromCache(text);
				}
				((Component)text).gameObject.SetActive(true);
				text.text = value;
			}
		}

		private static bool LooksLikeKeyBindingText(string? text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			string text2 = new string(text.Where(char.IsLetterOrDigit).Select(char.ToLowerInvariant).ToArray());
			if (!text2.Contains("mouse") && !text2.Contains("ctrl") && !text2.Contains("shift") && !text2.Contains("alt") && !text2.Contains("button") && !text2.Contains("key") && !text2.Contains("sprite"))
			{
				return text2.Length <= 2;
			}
			return true;
		}
	}
	internal static class ShieldChargeCooldownStatusSystem
	{
		private const string StatusEffectName = "CaptainValheim_Cooldown_shieldCharge";

		private const string DisplayName = "Shield Charge Cooldown";

		private const string Tooltip = "Shield Charge is recharging.";

		private const string FallbackIconPrefabName = "ShieldWood";

		internal static void RegisterStatusEffect(ObjectDB objectDb)
		{
			if (!((Object)(object)objectDb == (Object)null) && !objectDb.m_StatusEffects.Exists((StatusEffect statusEffect) => (Object)(object)statusEffect != (Object)null && ((Object)statusEffect).name == "CaptainValheim_Cooldown_shieldCharge"))
			{
				ShieldChargeCooldownStatusEffect shieldChargeCooldownStatusEffect = ScriptableObject.CreateInstance<ShieldChargeCooldownStatusEffect>();
				shieldChargeCooldownStatusEffect.Initialize("CaptainValheim_Cooldown_shieldCharge", "Shield Charge Cooldown", "Shield Charge is recharging.", ResolveIcon(objectDb, "ShieldWood"));
				objectDb.m_StatusEffects.Add((StatusEffect)(object)shieldChargeCooldownStatusEffect);
			}
		}

		internal static void Apply(Character character, ItemData? shield, float cooldown)
		{
			if ((Object)(object)character == (Object)null || cooldown <= 0f)
			{
				return;
			}
			SEMan sEMan = character.GetSEMan();
			if (sEMan != null)
			{
				int stableHashCode = StringExtensionMethods.GetStableHashCode("CaptainValheim_Cooldown_shieldCharge");
				sEMan.AddStatusEffect(stableHashCode, true, 0, 0f);
				StatusEffect statusEffect = sEMan.GetStatusEffect(stableHashCode);
				if (statusEffect != null)
				{
					statusEffect.m_ttl = cooldown;
					statusEffect.m_icon = ResolveShieldIcon(shield) ?? statusEffect.m_icon;
				}
			}
		}

		private static Sprite? ResolveShieldIcon(ItemData? shield)
		{
			Sprite[] array = shield?.m_shared?.m_icons;
			if (array == null || array.Length <= 0)
			{
				return null;
			}
			return array[0];
		}

		private static Sprite? ResolveIcon(ObjectDB objectDb, string itemPrefabName)
		{
			GameObject itemPrefab = objectDb.GetItemPrefab(itemPrefabName);
			Sprite[] array = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_icons;
			if (array == null || array.Length <= 0)
			{
				return null;
			}
			return array[0];
		}
	}
	internal sealed class ShieldChargeCooldownStatusEffect : StatusEffect
	{
		internal void Initialize(string prefabName, string displayName, string tooltip, Sprite? icon)
		{
			((Object)this).name = prefabName;
			base.m_name = displayName;
			base.m_tooltip = tooltip;
			base.m_icon = icon;
		}
	}
	internal static class ShieldOnlyKeyHintSystem
	{
		private readonly struct ShieldHintState
		{
			internal static readonly ShieldHintState Hidden = new ShieldHintState("", gamepad: false, hasCharge: false, hasPrimaryAttack: false, hasThrow: false);

			private readonly string _weaponPrefabName;

			private readonly bool _gamepad;

			internal readonly bool HasCharge;

			internal readonly bool HasPrimaryAttack;

			internal readonly bool HasThrow;

			internal bool HasRows
			{
				get
				{
					if (!HasCharge && !HasPrimaryAttack)
					{
						return HasThrow;
					}
					return true;
				}
			}

			public ShieldHintState(string weaponPrefabName, bool gamepad, bool hasCharge, bool hasPrimaryAttack, bool hasThrow)
			{
				_weaponPrefabName = weaponPrefabName;
				_gamepad = gamepad;
				HasCharge = hasCharge;
				HasPrimaryAttack = hasPrimaryAttack;
				HasThrow = hasThrow;
			}

			internal bool Equals(ShieldHintState other)
			{
				if (_gamepad == other._gamepad && HasCharge == other.HasCharge && HasPrimaryAttack == other.HasPrimaryAttack && HasThrow == other.HasThrow)
				{
					return string.Equals(_weaponPrefabName, other._weaponPrefabName, StringComparison.Ordinal);
				}
				return false;
			}
		}

		private readonly struct ShieldHintRow
		{
			internal readonly string Label;

			internal readonly IReadOnlyList<string> Keys;

			public ShieldHintRow(string label, IReadOnlyList<string> keys)
			{
				Label = label;
				Keys = keys;
			}
		}

		private static KeyHints? _activeKeyHints;

		private static readonly List<KeyHintCell> HintCells = new List<KeyHintCell>();

		private static readonly List<ShieldHintRow> ReusableRows = new List<ShieldHintRow>();

		private static ShieldHintState _lastHintState = ShieldHintState.Hidden;

		private static bool _hasLastHintState;

		private static bool _showingHints;

		internal static void InitializeKeyHints(KeyHints hints)
		{
			_activeKeyHints = hints;
			DestroyHints();
			_hasLastHintState = false;
			_lastHintState = ShieldHintState.Hidden;
			_showingHints = false;
			UpdateKeyHint(hints, force: true);
		}

		internal static void RefreshKeyHintUi()
		{
			if ((Object)(object)_activeKeyHints != (Object)null)
			{
				UpdateKeyHint(_activeKeyHints);
			}
		}

		internal static void UpdateKeyHint(KeyHints hints, bool force = false)
		{
			if ((Object)(object)hints == (Object)null)
			{
				return;
			}
			_activeKeyHints = hints;
			if (!ShouldAllowCustomCombatHints(hints))
			{
				HideHints();
				if ((Object)(object)hints.m_combatHints != (Object)null)
				{
					hints.m_combatHints.SetActive(false);
				}
				return;
			}
			if (!TryBuildHintState(out var state) || !state.HasRows)
			{
				HideHints();
				RememberHintState(ShieldHintState.Hidden);
				return;
			}
			if (!force && _showingHints && _hasLastHintState && _lastHintState.Equals(state))
			{
				PrepareCombatHintGroup(hints);
				return;
			}
			BuildHintRows(state, ReusableRows);
			EnsureHints(hints, ReusableRows.Count);
			if (HintCells.Count == 0)
			{
				return;
			}
			PrepareCombatHintGroup(hints);
			for (int i = 0; i < HintCells.Count; i++)
			{
				KeyHintCell keyHintCell = HintCells[i];
				if (i >= ReusableRows.Count)
				{
					keyHintCell.SetActive(active: false);
					continue;
				}
				ShieldHintRow shieldHintRow = ReusableRows[i];
				keyHintCell.Set(shieldHintRow.Label, shieldHintRow.Keys, 0f, shieldHintRow.Keys.Count <= 1);
				keyHintCell.RebuildParentLayout();
			}
			RememberHintState(state);
			_showingHints = true;
		}

		private static bool TryBuildHintState(out ShieldHintState state)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			state = ShieldHintState.Hidden;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ShouldShowCombatHints(localPlayer))
			{
				return false;
			}
			ItemData leftItem = ((Humanoid)localPlayer).GetLeftItem();
			if (((Humanoid)localPlayer).GetRightItem() != null || leftItem == null || (int)(leftItem.m_shared?.m_itemType).GetValueOrDefault() != 5 || !SecondaryAttackRuntimeFacade.TryGetDefinition(leftItem, out SecondaryAttackDefinition definition) || !(definition.Behavior is ShieldSpecialSecondaryBehavior shieldSpecialSecondaryBehavior))
			{
				return false;
			}
			state = new ShieldHintState(((Object)(object)leftItem.m_dropPrefab != (Object)null) ? ((Object)leftItem.m_dropPrefab).name : leftItem.m_shared.m_name, ZInput.IsGamepadActive(), shieldSpecialSecondaryBehavior.HasShieldCharge && shieldSpecialSecondaryBehavior.ShieldChargeDistance > 0f, shieldSpecialSecondaryBehavior.HasShieldPrimaryAttack, shieldSpecialSecondaryBehavior.HasShieldThrow);
			return state.HasRows;
		}

		private static void BuildHintRows(ShieldHintState state, List<ShieldHintRow> rows)
		{
			rows.Clear();
			if (state.HasCharge)
			{
				rows.Add(new ShieldHintRow("Charge", new <>z__ReadOnlyArray<string>(new string[2]
				{
					ResolveButtonLabel("Block"),
					ResolveButtonLabel("SecondaryAttack")
				})));
			}
			if (state.HasPrimaryAttack)
			{
				rows.Add(new ShieldHintRow("Attack", new <>z__ReadOnlySingleElementList<string>(ResolveButtonLabel("Attack"))));
			}
			if (state.HasThrow)
			{
				rows.Add(new ShieldHintRow("Throw", new <>z__ReadOnlySingleElementList<string>(ResolveButtonLabel("SecondaryAttack"))));
			}
		}

		private static bool ShouldAllowCustomCombatHints(KeyHints hints)
		{
			if (hints.m_keyHintsEnabled && !InventoryGui.IsVisible() && !Menu.IsVisible() && !Console.IsVisible() && !Game.IsPaused() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()))
			{
				if (!((Object)(object)InventoryGui.instance == (Object)null))
				{
					if (!InventoryGui.instance.IsSkillsPanelOpen && !InventoryGui.instance.IsTrophisPanelOpen)
					{
						return !InventoryGui.instance.IsTextPanelOpen;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private static bool ShouldShowCombatHints(Player? player)
		{
			if ((Object)(object)player != (Object)null && !((Character)player).IsDead() && !Hud.IsPieceSelectionVisible() && !Hud.InRadial() && !InventoryGui.IsVisible() && !Menu.IsVisible() && !Console.IsVisible() && !Game.IsPaused() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()) && ((Object)(object)InventoryGui.instance == (Object)null || (!InventoryGui.instance.IsSkillsPanelOpen && !InventoryGui.instance.IsTrophisPanelOpen && !InventoryGui.instance.IsTextPanelOpen)) && !PlayerCustomizaton.IsBarberGuiVisible())
			{
				return player.GetDoodadController() == null;
			}
			return false;
		}

		private static void PrepareCombatHintGroup(KeyHints hints)
		{
			if ((Object)(object)hints.m_combatHints != (Object)null)
			{
				hints.m_combatHints.SetActive(true);
			}
			SetVanillaCombatHintActive(hints.m_bowDrawGP, active: false);
			SetVanillaCombatHintActive(hints.m_bowDrawKB, active: false);
			SetVanillaCombatHintActive(hints.m_primaryAttackGP, active: false);
			SetVanillaCombatHintActive(hints.m_primaryAttackKB, active: false);
			SetVanillaCombatHintActive(hints.m_secondaryAttackGP, active: false);
			SetVanillaCombatHintActive(hints.m_secondaryAttackKB, active: false);
		}

		private static void SetVanillaCombatHintActive(GameObject? hint, bool active)
		{
			if ((Object)(object)hint != (Object)null)
			{
				hint.SetActive(active);
			}
		}

		private static void EnsureHints(KeyHints hints, int count)
		{
			GameObject val = ResolveCombatHintTemplate(hints);
			if ((Object)(object)val == (Object)null || (Object)(object)val.transform.parent == (Object)null)
			{
				return;
			}
			if (HintCells.Count > 0 && (Object)(object)HintCells[0].Root.transform.parent != (Object)(object)val.transform.parent)
			{
				DestroyHints();
			}
			while (HintCells.Count < count)
			{
				KeyHintCell keyHintCell = KeyHintCell.CloneFrom(val, $"CaptainValheim_ShieldOnlyHint_{HintCells.Count}");
				if (keyHintCell == null)
				{
					break;
				}
				keyHintCell.MoveBefore(val);
				HintCells.Add(keyHintCell);
			}
			foreach (KeyHintCell hintCell in HintCells)
			{
				hintCell.MoveBefore(val);
			}
		}

		private static GameObject? ResolveCombatHintTemplate(KeyHints hints)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			GameObject val = (ZInput.IsGamepadActive() ? hints.m_primaryAttackGP : hints.m_primaryAttackKB);
			if (KeyHintCell.IsUsableTemplate(val))
			{
				return val;
			}
			GameObject val2 = (ZInput.IsGamepadActive() ? hints.m_primaryAttackKB : hints.m_primaryAttackGP);
			if (KeyHintCell.IsUsableTemplate(val2))
			{
				return val2;
			}
			GameObject val3 = (ZInput.IsGamepadActive() ? hints.m_secondaryAttackGP : hints.m_secondaryAttackKB);
			if (KeyHintCell.IsUsableTemplate(val3))
			{
				return val3;
			}
			GameObject val4 = (ZInput.IsGamepadActive() ? hints.m_secondaryAttackKB : hints.m_secondaryAttackGP);
			if (KeyHintCell.IsUsableTemplate(val4))
			{
				return val4;
			}
			if ((Object)(object)hints.m_combatHints == (Object)null)
			{
				return null;
			}
			foreach (Transform item in KeyHintCell.FindParentWithTemplates(hints.m_combatHints, ZInput.IsGamepadActive() ? "Gamepad" : "Keyboard") ?? KeyHintCell.FindParentWithTemplates(hints.m_combatHints, "Keyboard") ?? KeyHintCell.FindParentWithTemplates(hints.m_combatHints, "Gamepad") ?? hints.m_combatHints.transform)
			{
				Transform val5 = item;
				if (KeyHintCell.IsUsableTemplate(((Component)val5).gameObject))
				{
					return ((Component)val5).gameObject;
				}
			}
			return null;
		}

		private static string ResolveButtonLabel(string button)
		{
			bool flag = ZInput.IsGamepadActive();
			string text = button;
			if (flag && button.Equals("Attack", StringComparison.OrdinalIgnoreCase))
			{
				text = "JoyAttack";
			}
			else if (flag && button.Equals("Block", StringComparison.OrdinalIgnoreCase))
			{
				text = "JoyBlock";
			}
			else if (flag && button.Equals("SecondaryAttack", StringComparison.OrdinalIgnoreCase))
			{
				text = "JoySecondaryAttack";
			}
			ZInput instance = ZInput.instance;
			string text2 = ((instance != null) ? instance.GetBoundKeyString(text, true) : null) ?? "";
			if (!string.IsNullOrWhiteSpace(text2))
			{
				if (Localization.instance == null)
				{
					return text2;
				}
				return Localization.instance.Localize(text2);
			}
			if (!(button == "Attack"))
			{
				if (button == "Block")
				{
					return flag ? "LB" : "RMB";
				}
				return flag ? "RB" : "MMB";
			}
			return flag ? "RT" : "LMB";
		}

		private static void HideHints()
		{
			if (!_showingHints)
			{
				return;
			}
			foreach (KeyHintCell hintCell in HintCells)
			{
				hintCell.SetActive(active: false);
				hintCell.RebuildParentLayout();
			}
			_showingHints = false;
		}

		private static void DestroyHints()
		{
			foreach (KeyHintCell hintCell in HintCells)
			{
				if ((Object)(object)hintCell.Root != (Object)null)
				{
					Object.Destroy((Object)(object)hintCell.Root);
				}
			}
			HintCells.Clear();
		}

		private static void RememberHintState(ShieldHintState state)
		{
			_lastHintState = state;
			_hasLastHintState = true;
		}
	}
	[HarmonyPatch(typeof(KeyHints), "Awake")]
	internal static class KeyHintsAwakeShieldOnlyPatch
	{
		private static void Postfix(KeyHints __instance)
		{
			ShieldOnlyKeyHintSystem.InitializeKeyHints(__instance);
		}
	}
	[HarmonyPatch(typeof(KeyHints), "UpdateHints")]
	internal static class KeyHintsUpdateShieldOnlyPatch
	{
		private static void Postfix(KeyHints __instance)
		{
			ShieldOnlyKeyHintSystem.UpdateKeyHint(__instance, force: true);
		}
	}
	internal sealed class ThrowProjectileVisualSpin : MonoBehaviour
	{
		internal enum AxisMode
		{
			None,
			HorizontalSide,
			WorldUp
		}

		private const float DegreesPerSecond = 720f;

		private const float ForwardEpsilonSqr = 0.0001f;

		private AxisMode _axisMode = AxisMode.HorizontalSide;

		private Vector3 _horizontalForward;

		private bool _hasHorizontalForward;

		private void LateUpdate()
		{
			//IL_001a: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (_axisMode != AxisMode.None)
			{
				Vector3 val = ((_axisMode == AxisMode.WorldUp) ? Vector3.up : ResolveHorizontalSideAxis());
				((Component)this).transform.Rotate(val, 720f * Time.deltaTime, (Space)0);
			}
		}

		private Vector3 ResolveHorizontalSideAxis()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			//IL_005b: 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)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (_hasHorizontalForward)
			{
				return ResolveSideAxis(_horizontalForward);
			}
			Transform val = (((Object)(object)((Component)this).transform.parent != (Object)null) ? ((Component)this).transform.parent : ((Component)this).transform);
			Vector3 forward = Vector3.ProjectOnPlane(val.forward, Vector3.up);
			if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
			{
				forward = Vector3.ProjectOnPlane(val.right, Vector3.up);
			}
			if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
			{
				return Vector3.right;
			}
			return ResolveSideAxis(forward);
		}

		private static Vector3 ResolveSideAxis(Vector3 forward)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			forward = Vector3.ProjectOnPlane(forward, Vector3.up);
			if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
			{
				return Vector3.right;
			}
			Vector3 val = Vector3.Cross(Vector3.up, ((Vector3)(ref forward)).normalized);
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.001f))
			{
				return Vector3.right;
			}
			return ((Vector3)(ref val)).normalized;
		}

		internal static void Ensure(GameObject? visual, AxisMode axisMode = AxisMode.HorizontalSide, Vector3 horizontalForward = default(Vector3))
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)visual == (Object)null || IsConfigured(visual, axisMode, horizontalForward))
			{
				return;
			}
			if (axisMode == AxisMode.None)
			{
				ThrowProjectileVisualSpin component = visual.GetComponent<ThrowProjectileVisualSpin>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
			}
			else
			{
				ThrowProjectileVisualSpin throwProjectileVisualSpin = visual.GetComponent<ThrowProjectileVisualSpin>() ?? visual.AddComponent<ThrowProjectileVisualSpin>();
				throwProjectileVisualSpin._axisMode = axisMode;
				throwProjectileVisualSpin._horizontalForward = Vector3.ProjectOnPlane(horizontalForward, Vector3.up);
				throwProjectileVisualSpin._hasHorizontalForward = axisMode == AxisMode.HorizontalSide && ((Vector3)(ref throwProjectileVisualSpin._horizontalForward)).sqrMagnitude > 0.001f;
			}
		}

		internal static bool IsConfigured(GameObject? visual, AxisMode axisMode = AxisMode.HorizontalSide, Vector3 horizontalForward = default(Vector3))
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)visual == (Object)null)
			{
				return false;
			}
			ThrowProjectileVisualSpin component = visual.GetComponent<ThrowProjectileVisualSpin>();
			if (axisMode == AxisMode.None)
			{
				return (Object)(object)component == (Object)null;
			}
			if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
			{
				return component.Matches(axisMode, horizontalForward);
			}
			return false;
		}

		private bool Matches(AxisMode axisMode, Vector3 horizontalForward)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (_axisMode != axisMode)
			{
				return false;
			}
			Vector3 val = Vector3.ProjectOnPlane(horizontalForward, Vector3.up);
			bool flag = axisMode == AxisMode.HorizontalSide && ((Vector3)(ref val)).sqrMagnitude > 0.001f;
			if (_hasHorizontalForward != flag)
			{
				return false;
			}
			if (flag)
			{
				Vector3 val2 = _horizontalForward - val;
				return ((Vector3)(ref val2)).sqrMagnitude <= 0.0001f;
			}
			return true;
		}
	}
	internal static class ProjectileSpinAxis
	{
		internal const string None = "none";

		internal const string Horizontal = "horizontal";

		internal const string Vertical = "vertical";

		internal static string Normalize(string? raw)
		{
			string text = raw?.Trim() ?? "";
			if (text.Length == 0)
			{
				return "";
			}
			if (text.Equals("none", StringComparison.OrdinalIgnoreCase))
			{
				return "none";
			}
			if (text.Equals("horizontal", StringComparison.OrdinalIgnoreCase))
			{
				return "horizontal";
			}
			if (!text.Equals("vertical", StringComparison.OrdinalIgnoreCase))
			{
				return "";
			}
			return "vertical";
		}

		internal static bool TryResolveAxisMode(string? raw, out ThrowProjectileVisualSpin.AxisMode axisMode)
		{
			string text = Normalize(raw);
			axisMode = ThrowProjectileVisualSpin.AxisMode.None;
			return text switch
			{
				"none" => Set(ThrowProjectileVisualSpin.AxisMode.None, out axisMode), 
				"horizontal" => Set(ThrowProjectileVisualSpin.AxisMode.HorizontalSide, out axisMode), 
				"vertical" => Set(ThrowProjectileVisualSpin.AxisMode.WorldUp, out axisMode), 
				_ => false, 
			};
		}

		private static bool Set(ThrowProjectileVisualSpin.AxisMode value, out ThrowProjectileVisualSpin.AxisMode axisMode)
		{
			axisMode = value;
			return true;
		}
	}
	internal sealed class ThrowProjectileVisualRotationOffset : MonoBehaviour
	{
		private const float OffsetEpsilonSqr = 0.0001f;

		private bool _hasBaseRotation;

		private Quaternion _baseLocalRotation;

		private Vector3 _offset;

		internal static void Ensure(GameObject? visual, Vector3 offset)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visual == (Object)null))
			{
				(visual.GetComponent<ThrowProjectileVisualRotationOffset>() ?? visual.AddComponent<ThrowProjectileVisualRotationOffset>()).Apply(offset);
			}
		}

		private void Apply(Vector3 offset)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (_hasBaseRotation)
			{
				Vector3 val = offset - _offset;
				if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
				{
					return;
				}
			}
			if (!_hasBaseRotation)
			{
				_baseLocalRotation = ((Component)this).transform.localRotation;
				_hasBaseRotation = true;
			}
			_offset = offset;
			((Component)this).transform.localRotation = _baseLocalRotation * Quaternion.Euler(offset);
		}
	}
	[BepInPlugin("sighsorry.CaptainValheim", "CaptainValheim", "1.0.0")]
	public class CaptainValheimPlugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		internal sealed class PluginSettings
		{
			internal GeneralSettings General { get; } = new GeneralSettings();

			internal void Bind(CaptainValheimPlugin plugin)
			{
				General.Bind(plugin);
			}
		}

		internal sealed class GeneralSettings
		{
			internal ConfigEntry<Toggle> LockConfiguration;

			internal void Bind(CaptainValheimPlugin plugin)
			{
				LockConfiguration = plugin.config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			}
		}

		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[UsedImplicitly]
			public string? Category;

			[UsedImplicitly]
			public Action<ConfigEntryBase>? CustomDrawer;
		}

		private class AcceptableShortcuts : AcceptableValueBase
		{
			public AcceptableShortcuts()
				: base(typeof(KeyboardShortcut))
			{
			}

			public override object Clamp(object value)
			{
				return value;
			}

			public override bool IsValid(object value)
			{
				return true;
			}

			public override string ToDescriptionString()
			{
				return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes);
			}
		}

		internal const string ModName = "CaptainValheim";

		internal const string ModVersion = "1.0.0";

		internal const string Author = "sighsorry";

		private const string ModGUID = "sighsorry.CaptainValheim";

		private static string ConfigFileName = "sighsorry.CaptainValheim.cfg";

		private static string ConfigFileFullPath = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName;

		internal static string ConnectionError = "";

		private readonly Harmony _harmony = new Harmony("sighsorry.CaptainValheim");

		public static readonly ManualLogSource ModLogger = Logger.CreateLogSource("CaptainValheim");

		internal static readonly ConfigSync ConfigSync = new ConfigSync("sighsorry.CaptainValheim")
		{
			DisplayName = "CaptainValheim",
			CurrentVersion = "1.0.0",
			MinimumRequiredVersion = "1.0.0"
		};

		private FileSystemWatcher? _watcher;

		private readonly object _reloadLock = new object();

		private DateTime _lastConfigReloadTime;

		private string? _lastConfigFileText;

		private bool _suppressWorldApplySettingChange;

		private const long RELOAD_DELAY = 10000000L;

		private static ConfigEntry<Toggle> _serverConfigLocked = null;

		internal static PluginSettings Settings { get; } = new PluginSettings();

		public void Awake()
		{
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			Settings.Bind(this);
			RegisterWorldApplySettingHandlers();
			_serverConfigLocked = Settings.General.LockConfiguration;
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			PatchCaptainValheimHooks();
			SecondaryAttackFacade.Initialize();
			SetupWatcher();
			((BaseUnityPlugin)this).Config.Save();
			_lastConfigFileText = ReadFileTextIfExists(ConfigFileFullPath);
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private void OnDestroy()
		{
			UnregisterWorldApplySettingHandlers();
			SecondaryAttackFacade.Dispose();
			SaveWithRespectToConfigSet();
			_watcher?.Dispose();
		}

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

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (_reloadLock)
			{
				if (!File.Exists(ConfigFileFullPath))
				{
					ModLogger.LogWarning((object)"Config file does not exist. Skipping reload.");
					return;
				}
				try
				{
					string b = File.ReadAllText(ConfigFileFullPath);
					if (string.Equals(_lastConfigFileText, b, StringComparison.Ordinal))
					{
						return;
					}
					_suppressWorldApplySettingChange = true;
					try
					{
						SaveWithRespectToConfigSet(reload: true);
					}
					finally
					{
						_suppressWorldApplySettingChange = false;
					}
					SecondaryAttackFacade.RequestCurrentWorldReapply();
					_lastConfigFileText = ReadFileTextIfExists(ConfigFileFullPath);
					ModLogger.LogInfo((object)"Configuration reload complete.");
				}
				catch (Exception ex)
				{
					ModLogger.LogError((object)("Error reloading configuration: " + ex.Message));
				}
			}
			_lastConfigReloadTime = now;
		}

		private static string? ReadFileTextIfExists(string path)
		{
			if (!File.Exists(path))
			{
				return null;
			}
			return File.ReadAllText(path);
		}

		private void SaveWithRespectToConfigSet(bool reload = false)
		{
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			if (reload)
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			((BaseUnityPlugin)this).Config.Save();
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private void PatchCaptainValheimHooks()
		{
			Type[] array = new Type[15]
			{
				typeof(ProjectileUpdateVisualPatch),
				typeof(ProjectileOnHitPatch),
				typeof(PlayerUpdatePendingConfigPatch),
				typeof(ObjectDbAwakePatch),
				typeof(ObjectDbCopyOtherDbPatch),
				typeof(HumanoidGetCurrentWeaponPatch),
				typeof(HumanoidPickupThrownShieldPatch),
				typeof(HumanoidBlockAttackPatch),
				typeof(HumanoidStartAttackPatch),
				typeof(AttackOnAttackTriggerPatch),
				typeof(AttackDoMeleeAttackSecondaryDurabilityFactorPatch),
				typeof(AttackDoAreaAttackSecondaryDurabilityFactorPatch),
				typeof(AttackProjectileAttackTriggeredSecondaryDurabilityFactorPatch),
				typeof(KeyHintsAwakeShieldOnlyPatch),
				typeof(KeyHintsUpdateShieldOnlyPatch)
			};
			foreach (Type type in array)
			{
				_harmony.CreateClassProcessor(type).Patch();
			}
		}

		private void RegisterWorldApplySettingHandlers()
		{
		}

		private void UnregisterWorldApplySettingHandlers()
		{
		}

		private void OnWorldApplySettingChanged(object? sender, EventArgs e)
		{
			if (!_suppressWorldApplySettingChange)
			{
				SecondaryAttackFacade.RequestCurrentWorldReapply();
			}
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}
	}
	public static class KeyboardExtensions
	{
		[SpecialName]
		public sealed class <G>$8D1D3E80A18AA9715780B6CB7003B2F1
		{
			[SpecialName]
			public static class <M>$895AB635D4D087636CF1C26BA650BA11
			{
			}

			[ExtensionMarker("<M>$895AB635D4D087636CF1C26BA650BA11")]
			public bool IsKeyDown()
			{
				throw new NotSupportedException();
			}

			[ExtensionMarker("<M>$895AB635D4D087636CF1C26BA650BA11")]
			public bool IsKeyHeld()
			{
				throw new NotSupportedException();
			}
		}

		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}
	}
	public static class ToggleExtentions
	{
		[SpecialName]
		public sealed class <G>$9E7C82BC55DED4AA4CD9E4F2D97F4E68
		{
			[SpecialName]
			public static class <M>$D090B0687CCBD39B38D3C95725B16919
			{
			}

			[ExtensionMarker("<M>$D090B0687CCBD39B38D3C95725B16919")]
			public bool IsOn()
			{
				throw new NotSupportedException();
			}

			[ExtensionMarker("<M>$D090B0687CCBD39B38D3C95725B16919")]
			public bool IsOff()
			{
				throw new NotSupportedException();
			}
		}

		public static bool IsOn(this CaptainValheimPlugin.Toggle value)
		{
			return value == CaptainValheimPlugin.Toggle.On;
		}

		public static bool IsOff(this CaptainValheimPlugin.Toggle value)
		{
			return value == CaptainValheimPlugin.Toggle.Off;
		}
	}
	internal static class ProjectileAccess
	{
		private static readonly FieldInfo? WeaponField = AccessTools.Field(typeof(Projectile), "m_weapon");

		private static readonly FieldInfo? AmmoField = AccessTools.Field(typeof(Projectile), "m_ammo");

		private static readonly FieldInfo? OwnerField = AccessTools.Field(typeof(Projectile), "m_owner");

		private static readonly FieldInfo? OriginalHitDataField = AccessTools.Field(typeof(Projectile), "m_originalHitData");

		private static readonly FieldInfo? StatusEffectHashField = AccessTools.Field(typeof(Projectile), "m_statusEffectHash");

		private static readonly FieldInfo? VelocityField = AccessTools.Field(typeof(Projectile), "m_vel");

		private static readonly FieldInfo? DidHitField = AccessTools.Field(typeof(Projectile), "m_didHit");

		internal static ItemData? GetWeapon(Projectile projectile)
		{
			object? obj = WeaponField?.GetValue(projectile);
			return (ItemData?)((obj is ItemData) ? obj : null);
		}

		internal static ItemData? GetAmmo(Projectile projectile)
		{
			object? obj = AmmoField?.GetValue(projectile);
			return (ItemData?)((obj is ItemData) ? obj : null);
		}

		internal static Character? GetOwner(Projectile projectile)
		{
			object? obj = OwnerField?.GetValue(projectile);
			return (Character?)((obj is Character) ? obj : null);
		}

		internal static HitData? GetOriginalHitData(Projectile projectile)
		{
			object? obj = OriginalHitDataField?.GetValue(projectile);
			return (HitData?)((obj is HitData) ? obj : null);
		}

		internal static int GetStatusEffectHash(Projectile projectile)
		{
			object obj = StatusEffectHashField?.GetValue(projectile);
			if (obj is int)
			{
				return (int)obj;
			}
			return 0;
		}

		internal static Vector3 GetVelocity(Projectile projectile)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			object obj = VelocityField?.GetValue(projectile);
			if (obj is Vector3)
			{
				return (Vector3)obj;
			}
			return Vector3.zero;
		}

		internal static void SetVelocity(Projectile projectile, Vector3 velocity)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			VelocityField?.SetValue(projectile, velocity);
		}

		internal static void SetDidHit(Projectile projectile, bool didHit)
		{
			DidHitField?.SetValue(projectile, didHit);
		}
	}
	internal static class ProjectileRuntimeSystem
	{
		internal readonly struct ProjectileLaunchData
		{
			public static readonly ProjectileLaunchData Invalid = new ProjectileLaunchData(null, null, 0f, 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, useRandomVelocity: false);

			public GameObject? ProjectilePrefab { get; }

			public ItemData? AmmoItem { get; }

			public float ProjectileVelocity { get; }

			public float ProjectileVelocityMin { get; }

			public float ProjectileAccuracy { get; }

			public float ProjectileAccuracyMin { get; }

			public float AttackHitNoise { get; }

			public float DamageFactor { get; }

			public float ConfiguredDamageFactor { get; }

			public float ConfiguredSkillRaiseFactor { get; }

			public float ConfiguredAdrenalineFactor { get; }

			public bool UseRandomVelocity { get; }

			public bool IsValid => (Object)(object)ProjectilePrefab != (Object)null;

			public ProjectileLaunchData(GameObject? projectilePrefab, ItemData? ammoItem, float projectileVelocity, float projectileVelocityMin, float projectileAccuracy, float projectileAccuracyMin, float attackHitNoise, float damageFactor, float configuredDamageFactor, float configuredSkillRaiseFactor, float configuredAdrenalineFactor, bool useRandomVelocity)
			{
				ProjectilePrefab = projectilePrefab;
				AmmoItem = ammoItem;
				ProjectileVelocity = projectileVelocity;
				ProjectileVelocityMin = projectileVelocityMin;
				ProjectileAccuracy = projectileAccuracy;
				ProjectileAccuracyMin = projectileAccuracyMin;
				AttackHitNoise = attackHitNoise;
				DamageFactor = damageFactor;
				ConfiguredDamageFactor = configuredDamageFactor;
				ConfiguredSkillRaiseFactor = configuredSkillRaiseFactor;
				ConfiguredAdrenalineFactor = configuredAdrenalineFactor;
				UseRandomVelocity = useRandomVelocity;
			}
		}

		internal static Character? GetHitCharacter(Collider collider)
		{
			GameObject obj = Projectile.FindHitObject(collider);
			if (obj == null)
			{
				return null;
			}
			return obj.GetComponent<Character>();
		}
	}
	internal sealed class SecondaryAttackCompiledSnapshot
	{
		public static readonly SecondaryAttackCompiledSnapshot Empty = new SecondaryAttackCompiledSnapshot(0, new NormalizedSecondaryAttackConfigFile());

		public int SnapshotId { get; }

		public NormalizedSecondaryAttackConfigFile Config { get; }

		public IReadOnlyDictionary<string, NormalizedWeaponConfig> Weapons => Config.Weapons;

		public NormalizedWeaponConfig? GlobalShieldFallback => Config.GlobalShieldFallback;

		public SecondaryAttackCompiledSnapshot(int snapshotId, NormalizedSecondaryAttackConfigFile config)
		{
			SnapshotId = snapshotId;
			Config = config ?? throw new ArgumentNullException("config");
		}
	}
	internal sealed class SecondaryAttackAppliedWorldSnapshot
	{
		public static readonly SecondaryAttackAppliedWorldSnapshot Empty = new SecondaryAttackAppliedWorldSnapshot(SecondaryAttackCompiledSnapshot.Empty, new Dictionary<string, SecondaryAttackDefinition>(StringComparer.OrdinalIgnoreCase), 0);

		public SecondaryAttackCompiledSnapshot CompiledSnapshot { get; }

		public int SnapshotId => CompiledSnapshot.SnapshotId;

		public int ApplyRevision { get; }

		public IReadOnlyDictionary<string, SecondaryAttackDefinition> DefinitionsByPrefabName { get; }

		public SecondaryAttackAppliedWorldSnapshot(SecondaryAttackCompiledSnapshot compiledSnapshot, IReadOnlyDictionary<string, SecondaryAttackDefinition> definitionsByPrefabName, int applyRevision)
		{
			CompiledSnapshot = compiledSnapshot ?? throw new ArgumentNullException("compiledSnapshot");
			DefinitionsByPrefabName = definitionsByPrefabName ?? throw new ArgumentNullException("definitionsByPrefabName");
			ApplyRevision = applyRevision;
		}
	}
	internal enum SecondaryAttackYamlDomainId
	{
		Shields
	}
	internal sealed class SecondaryAttackYamlDomain
	{
		public SecondaryAttackYamlDomainId Id { get; }

		public string FileName { get; }

		public string FilePath { get; }

		public string SyncedIdentifier { get; }

		public Func<string> GetDefaultContents { get; }

		internal SecondaryAttackYamlDomain(SecondaryAttackYamlDomainId id, string fileName, string filePath, string syncedIdentifier, Func<string> getDefaultContents)
		{
			Id = id;
			FileName = fileName;
			FilePath = filePath;
			SyncedIdentifier = syncedIdentifier;
			GetDefaultContents = getDefaultContents;
		}
	}
	internal static class SecondaryAttackYamlDomainRegistry
	{
		internal const string ShieldsYamlFileName = "CaptainValheim.yml";

		private const string SyncedShieldsYamlIdentifier = "captain_valheim_yaml";

		internal const long ReloadDelayTicks = 10000000L;

		internal static readonly string ConfigDirectoryPath = Paths.ConfigPath;

		internal static readonly string ShieldsYamlFilePath = Path.Combine(ConfigDirectoryPath, "CaptainValheim.yml");

		private static readonly SecondaryAttackYamlDomain[] OrderedDomains = new SecondaryAttackYamlDomain[1]
		{
			new SecondaryAttackYamlDomain(SecondaryAttackYamlDomainId.Shields, "CaptainValheim.yml", ShieldsYamlFilePath, "captain_valheim_yaml", () => SecondaryAttackDefaultYamlResources.Load("CaptainValheim.yml"))
		};

		private static readonly Dictionary<SecondaryAttackYamlDomainId, SecondaryAttackYamlDomain> DomainsById = OrderedDomains.ToDictionary((SecondaryAttackYamlDomain domain) => domain.Id);

		public static IReadOnlyList<SecondaryAttackYamlDomain> Domains => OrderedDomains;

		public static SecondaryAttackYamlDomain Get(SecondaryAttackYamlDomainId id)
		{
			return DomainsById[id];
		}
	}
	internal sealed class SecondaryAttackYamlTexts
	{
		private readonly Dictionary<SecondaryAttackYamlDomainId, string> _texts;

		public IReadOnlyDictionary<SecondaryAttackYamlDomainId, string> All => _texts;

		public SecondaryAttackYamlTexts(IReadOnlyDictionary<SecondaryAttackYamlDomainId, string> texts)
		{
			_texts = new Dictionary<SecondaryAttackYamlDomainId, string>(texts);
			foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
			{
				_texts.TryAdd(domain.Id, string.Empty);
			}
		}

		public string Get(SecondaryAttackYamlDomainId id)
		{
			if (!_texts.TryGetValue(id, out string value))
			{
				return string.Empty;
			}
			return value;
		}

		public string GetContentFingerprint()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
			{
				string text = Get(domain.Id);
				stringBuilder.Append((int)domain.Id).Append(':').Append(text.Length)
					.Append(':')
					.Append(text)
					.Append('\n');
			}
			return stringBuilder.ToString();
		}
	}
	internal sealed class SecondaryAttackParsedYaml
	{
		public IReadOnlyDictionary<string, ShieldWeaponConfig> Shields { get; set; } = new Dictionary<string, ShieldWeaponConfig>(StringComparer.OrdinalIgnoreCase);
	}
	internal static class SecondaryAttackConfigLoader
	{
		private static readonly IDeserializer Deserializer = new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();

		public static void EnsureLocalFilesExist()
		{
			Directory.CreateDirectory(SecondaryAttackYamlDomainRegistry.ConfigDirectoryPath);
			foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
			{
				if (!File.Exists(domain.FilePath))
				{
					File.WriteAllText(domain.FilePath, domain.GetDefaultContents());
				}
			}
		}

		public static SecondaryAttackYamlTexts ReadLocalYamlTexts()
		{
			Dictionary<SecondaryAttackYamlDomainId, string> dictionary = new Dictionary<SecondaryAttackYamlDomainId, string>();
			foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
			{
				dictionary[domain.Id] = File.ReadAllText(domain.FilePath);
			}
			return new SecondaryAttackYamlTexts(dictionary);
		}

		public static bool TryCompileSnapshot(int snapshotId, SecondaryAttackYamlTexts yamlTexts, out SecondaryAttackCompiledSnapshot? snapshot)
		{
			snapshot = null;
			if (!TryParseYamlTexts(yamlTexts, out SecondaryAttackParsedYaml parsedYaml))
			{
				return false;
			}
			snapshot = SecondaryAttackConfigCompiler.Compile(snapshotId, parsedYaml);
			return true;
		}

		private static bool TryParseYamlTexts(SecondaryAttackYamlTexts yamlTexts, out SecondaryAttackParsedYaml? parsedYaml)
		{
			parsedYaml = null;
			if (!TryParseDictionary(SecondaryAttackYamlDomainId.Shields, yamlTexts.Get(SecondaryAttackYamlDomainId.Shields), out Dictionary<string, ShieldWeaponConfig> parsed))
			{
				return false;
			}
			parsedYaml = new SecondaryAttackParsedYaml
			{
				Shields = parsed
			};
			return true;
		}

		private static bool TryParseDictionary<T>(SecondaryAttackYamlDomainId domainId, string yamlText, out Dictionary<string, T>? parsed)
		{
			parsed = null;
			if (string.IsNullOrWhiteSpace(yamlText))
			{
				parsed = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
				return true;
			}
			try
			{
				parsed = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
				YamlStream yamlStream = new YamlStream();
				yamlStream.Load(new StringReader(yamlText));
				if (yamlStream.Documents.Count == 0 || !(yamlStream.Documents[0].RootNode is YamlMappingNode yamlMappingNode))
				{
					return true;
				}
				SecondaryAttackYamlDomain secondaryAttackYamlDomain = SecondaryAttackYamlDomainRegistry.Get(domainId);
				foreach (KeyValuePair<YamlNode, YamlNode> child in yamlMappingNode.Children)
				{
					string text = (child.Key as YamlScalarNode)?.Value?.Trim() ?? "";
					if (!string.IsNullOrWhiteSpace(text))
					{
						try
						{
							Dictionary<string, T>? obj = parsed;
							T val = DeserializeYamlNode<T>(child.Value);
							obj[text] = ((val != null) ? val : Activator.CreateInstance<T>());
						}
						catch (Exception ex)
						{
							CaptainValheimPlugin.ModLogger.LogWarning((object)("Skipping " + secondaryAttackYamlDomain.FileName + " block '" + text + "': " + ex.Message));
						}
					}
				}
				return true;
			}
			catch (Exception ex2)
			{
				SecondaryAttackYamlDomain secondaryAttackYamlDomain2 = SecondaryAttackYamlDomainRegistry.Get(domainId);
				CaptainValheimPlugin.ModLogger.LogError((object)("Failed to parse " + secondaryAttackYamlDomain2.FileName + ": " + ex2.Message));
				return false;
			}
		}

		private static T? DeserializeYamlNode<T>(YamlNode node)
		{
			using StringWriter stringWriter = new StringWriter();
			new YamlStream(new YamlDocument(node)).Save(stringWriter, assignAnchors: false);
			return Deserializer.Deserialize<T>(stringWriter.ToString());
		}
	}
	internal static class SecondaryAttackAdrenalineSystem
	{
		private sealed class AttackAdrenalineState
		{
			internal readonly HashSet<string> GrantedKeys = new HashSet<string>();
		}

		private static readonly ConditionalWeakTable<Attack, AttackAdrenalineState> AttackStates = new ConditionalWeakTable<Attack, AttackAdrenalineState>();

		internal static void Reset(Attack attack)
		{
			if (attack != null)
			{
				AttackStates.Remove(attack);
			}
		}

		internal static float ResolveFactor(ActiveSecondaryAttack activeAttack)
		{
			if (!(activeAttack.Definition.Behavior is ShieldSpecialSecondaryBehavior shieldSpecialSecondaryBehavior))
			{
				return 1f;
			}
			return activeAttack.ShieldMode switch
			{
				ShieldSpecialMode.PrimaryAttack => shieldSpecialSecondaryBehavior.ShieldPrimaryAttackAdrenalineFactor, 
				ShieldSpecialMode.Charge => shieldSpecialSecondaryBehavior.ShieldChargeAdrenalineFactor, 
				_ => shieldSpecialSecondaryBehavior.ShieldThrowAdrenalineFactor, 
			};
		}

		internal static bool TryGrantOnceRaw(Attack attack, Character target, float baseAdrenaline, float factor, string key)
		{
			if ((Object)(object)attack?.m_character == (Object)null || (Object)(object)target == (Object)null || target.m_enemyAdrenalineMultiplier <= 0f || baseAdrenaline <= 0f || factor <= 0f || !TryMarkGranted(attack, key))
			{
				return false;
			}
			((Character)attack.m_character).AddAdrenaline(baseAdrenaline * Mathf.Max(0f, factor) * target.m_enemyAdrenalineMultiplier);
			return true;
		}

		private static bool TryMarkGranted(Attack attack, string key)
		{
			return AttackStates.GetValue(attack, (Attack _) => new AttackAdrenalineState()).GrantedKeys.Add(key);
		}
	}
	internal sealed class SecondaryAttackWeaponNormalizationResult
	{
		public Dictionary<string, NormalizedWeaponConfig> Weapons { get; set; } = new Dictionary<string, NormalizedWeaponConfig>(StringComparer.OrdinalIgnoreCase);

		public NormalizedWeaponConfig? GlobalShieldFallback { get; set; }
	}
	internal static class SecondaryAttackWeaponConfigNormalizer
	{
		private const string GlobalFallbackKey = "Global";

		internal static SecondaryAttackWeaponNormalizationResult Normalize(IReadOnlyDictionary<string, ShieldWeaponConfig> shields)
		{
			Dictionary<string, NormalizedWeaponConfig> dictionary = new Dictionary<string, NormalizedWeaponConfig>(StringComparer.OrdinalIgnoreCase);
			NormalizedWeaponConfig normalizedWeaponConfig = CreateGlobalDefaultShieldFallback();
			ShieldWeaponConfig shieldWeaponConfig = null;
			string key;
			ShieldWeaponConfig value;
			foreach (KeyValuePair<string, ShieldWeaponConfig> shield in shields)
			{
				shield.Deconstruct(out key, out value);
				string text = key;
				ShieldWeaponConfig shieldWeaponConfig2 = value;
				if (!string.IsNullOrWhiteSpace(text) && shieldWeaponConfig2 != null && text.Trim().Equals("Global", StringComparison.OrdinalIgnoreCase))
				{
					shieldWeaponConfig = shieldWeaponConfig2;
					break;
				}
			}
			NormalizedWeaponConfig normalizedWeaponConfig2 = ((shieldWeaponConfig != null) ? FromShieldRaw(shieldWeaponConfig, normalizedWeaponConfig) : null);
			NormalizedWeaponConfig fallback = normalizedWeaponConfig2 ?? normalizedWeaponConfig;
			foreach (KeyValuePair<string, ShieldWeaponConfig> shield2 in shields)
			{
				shield2.Deconstruct(out key, out value);
				string text2 = key;
				ShieldWeaponConfig shieldWeaponConfig3 = value;
				if (!string.IsNullOrWhiteSpace(text2) && shieldWeaponConfig3 != null)
				{
					string text3 = text2.Trim();
					if (!text3.Equals("Global", StringComparison.OrdinalIgnoreCase))
					{
						dictionary[text3] = FromShieldRaw(shieldWeaponConfig3, fallback);
					}
				}
			}
			return new SecondaryAttackWeaponNormalizationResult
			{
				Weapons = dictionary,
				GlobalShieldFallback = normalizedWeaponConfig2
			};
		}

		public static NormalizedWeaponConfig FromShieldRaw(ShieldWeaponConfig raw, NormalizedWeaponConfig? fallback = null)
		{
			if (fallback == null)
			{
				fallback = CreateGlobalDefaultShieldFallback();
			}
			return new NormalizedWeaponConfig
			{
				Shield = NormalizeShield(raw, fallback.Shield ?? new NormalizedShieldModeConfig())
			};
		}

		public static NormalizedWeaponConfig CreateGlobalDefaultShieldFallback()
		{
			return new NormalizedWeaponConfig
			{
				Shield = new NormalizedShieldModeConfig
				{
					PrimaryAttack = new NormalizedShieldPrimaryAttackConfig(),
					Throw = new NormalizedShieldThrowConfig(),
					Charge = new NormalizedShieldChargeConfig(),
					Reflect = new NormalizedShieldReflectConfig(),
					BlockCharge = new NormalizedShieldBlockChargeConfig()
				}
			};
		}

		private static NormalizedShieldModeConfig NormalizeShield(ShieldWeaponConfig rawShield, NormalizedShieldModeConfig fallback)
		{
			return new NormalizedShieldModeConfig
			{
				PrimaryAttack = NormalizeShieldPrimaryAttack(rawShield.PrimaryAttack, fallback.PrimaryAttack),
				Throw = NormalizeShieldThrow(rawShield.Throw, fallback.Throw),
				Charge = NormalizeShieldCharge(rawShield.Charge, fallback.Charge),
				Reflect = NormalizeShieldReflect(rawShield.Reflect, fallback.Reflect),
				BlockCharge = NormalizeShieldBlockCharge(rawShield.BlockCharge, fallback.BlockCharge)
			};
		}

		private static NormalizedShieldPrimaryAttackConfig? NormalizeShieldPrimaryAttack(ShieldPrimaryAttackConfig? rawPrimaryAttack, NormalizedShieldPrimaryAttackConfig? fallback)
		{
			if (rawPrimaryAttack == null)
			{
				return fallback;
			}
			if (rawPrimaryAttack.Enabled == false)
			{
				return null;
			}
			NormalizedShieldPrimaryAttackConfig normalizedShieldPrimaryAttackConfig = fallback ?? new NormalizedShieldPrimaryAttackConfig();
			return new NormalizedShieldPrimaryAttackConfig
			{
				DamageFactor = (rawPrimaryAttack.DamageFactor ?? normalizedShieldPrimaryAttackConfig.DamageFactor),
				PushFactor = (rawPrimaryAttack.PushFactor ?? normalizedShieldPrimaryAttackConfig.PushFactor),
				StaminaFactor = (rawPrimaryAttack.StaminaFactor ?? normalizedShieldPrimaryAttackConfig.StaminaFactor),
				DurabilityFactor = (rawPrimaryAttack.DurabilityFactor ?? normalizedShieldPrimaryAttackConfig.DurabilityFactor),
				AdrenalineFactor = 1f
			};
		}

		private static NormalizedShieldThrowConfig? NormalizeShieldThrow(ShieldThrowConfig? rawThrow, NormalizedShieldThrowConfig? fallback)
		{
			if (rawThrow == null)
			{
				return fallback;
			}
			if (rawThrow.Enabled == false)
			{
				return null;
			}
			NormalizedShieldThrowConfig normalizedShieldThrowConfig = fallback ?? new NormalizedShieldThrowConfig();
			return new NormalizedShieldThrowConfig
			{
				Animation = ((!string.IsNullOrWhiteSpace(rawThrow.Animation)) ? rawThrow.Animation.Trim() : normalizedShieldThrowConfig.Animation),
				DamageFactor = (rawThrow.DamageFactor ?? normalizedShieldThrowConfig.DamageFactor),
				PushFactor = (rawThrow.PushFactor ?? normalizedShieldThrowConfig.PushFactor),
				StaminaFactor = (rawThrow.StaminaFactor ?? normalizedShieldThrowConfig.StaminaFactor),
				DurabilityFactor = (rawThrow.DurabilityFactor ?? normalizedShieldThrowConfig.DurabilityFactor),
				Targets = (rawThrow.Targets ?? normalizedShieldThrowConfig.Targets),
				DamageDecay = (rawThrow.DamageDecay ?? normalizedShieldThrowConfig.DamageDecay),
				RadiusFactor = (rawThrow.RadiusFactor ?? normalizedShieldThrowConfig.RadiusFactor),
				TtlFactor = (rawThrow.TtlFactor ?? normalizedShieldThrowConfig.TtlFactor),
				AdrenalineFactor = 1f
			};
		}

		private static NormalizedShieldChargeConfig? NormalizeShieldCharge(ShieldChargeConfig? rawCharge, NormalizedShieldChargeConfig? fallback)
		{
			if (rawCharge == null)
			{
				return fallback;
			}
			if (rawCharge.Enabled == false)
			{
				return null;
			}
			NormalizedShieldChargeConfig normalizedShieldChargeConfig = fallback ?? new NormalizedShieldChargeConfig();
			return new NormalizedShieldChargeConfig
			{
				DamageFactor = (rawCharge.DamageFactor ?? normalizedShieldChargeConfig.DamageFactor),
				PushFactor = (rawCharge.PushFactor ?? normalizedShieldChargeConfig.PushFactor),
				StaminaFactor = (rawCharge.StaminaFactor ?? normalizedShieldChargeConfig.StaminaFactor),
				Distance = (rawCharge.Distance ?? normalizedShieldChargeConfig.Distance),
				Speed = (rawCharge.Speed ?? normalizedShieldChargeConfig.Speed),
				Cooldown = (rawCharge.Cooldown ?? normalizedShieldChargeConfig.Cooldown),
				CooldownReductionFactor = (rawCharge.CooldownReductionFactor ?? normalizedShieldChargeConfig.CooldownReductionFactor),
				DurabilityFactor = (rawCharge.DurabilityFactor ?? normalizedShieldChargeConfig.DurabilityFactor),
				HitRadiusFactor = (rawCharge.HitRadiusFactor ?? normalizedShieldChargeConfig.HitRadiusFactor),
				AdrenalineFactor = 5f
			};
		}

		private static NormalizedShieldReflectConfig? NormalizeShieldReflect(ShieldReflectConfig? rawReflect, NormalizedShieldReflectConfig? fallback)
		{
			if (rawReflect == null)
			{
				return fallback;
			}
			if (rawReflect.Enabled == false)
			{
				return null;
			}
			NormalizedShieldReflectConfig normalizedShieldReflectConfig = fallback ?? new NormalizedShieldReflectConfig();
			return new NormalizedShieldReflectConfig
			{
				StaminaFactor = (rawReflect.StaminaFactor ?? normalizedShieldReflectConfig.StaminaFactor),
				ReflectionFactor = (rawReflect.ReflectionFactor ?? normalizedShieldReflectConfig.ReflectionFactor)
			};
		}

		private static NormalizedShieldBlockChargeConfig? NormalizeShieldBlockCharge(ShieldBlockChargeConfig? rawBlockCharge, NormalizedShieldBlockChargeConfig? fallback)
		{
			if (rawBlockCharge == null)
			{
				return fallback;
			}
			if (rawBlockCharge.Enabled == false)
			{
				return null;
			}
			return new NormalizedShieldBlockChargeConfig
			{
				ChargeCount = (rawBlockCharge.ChargeCount ?? fallback?.ChargeCount),
				DecayTime = (rawBlockCharge.DecayTime ?? fallback?.DecayTime),
				BlockingDecayFactor = (rawBlockCharge.BlockingDecayFactor ?? fallback?.BlockingDecayFactor)
			};
		}
	}
	internal static class SecondaryAttackFacade
	{
		private enum YamlAuthorityMode
		{
			LocalFiles,
			SyncedOnly
		}

		private static readonly object ReloadLock = new object();

		private static FileSystemWatcher? _watcher;

		private static readonly Dictionary<SecondaryAttackYamlDomainId, CustomSyncedValue<string>> SyncedYamlValues = new Dictionary<SecondaryAttackYamlDomainId, CustomSyncedValue<string>>();

		private static SecondaryAttackCompiledSnapshot _currentCompiledSnapshot = SecondaryAttackCompiledSnapshot.Empty;

		private static SecondaryAttackCompiledSnapshot? _pendingCompiledSnapshot;

		private static SecondaryAttackAppliedWorldSnapshot _currentAppliedWorldSnapshot = SecondaryAttackAppliedWorldSnapshot.Empty;

		private static DateTime _lastYamlReloadTime;

		private static bool _hasPendingConfig;

		private static bool _hasPendingWorldReapply;

		private static int _nextSnapshotId = 1;

		private static bool _suppressSyncedYamlChanged;

		private static YamlAuthorityMode _yamlAuthorityMode;

		private static string _currentYamlFingerprint = string.Empty;

		private static string? _pendingYamlFingerprint;

		internal static SecondaryAttackCompiledSnapshot CurrentCompiledSnapshot => _currentCompiledSnapshot;

		internal static SecondaryAttackAppliedWorldSnapshot CurrentAppliedWorldSnapshot => _currentAppliedWorldSnapshot;

		public static void Initialize()
		{
			SecondaryAttackConfigLoader.EnsureLocalFilesExist();
			InitializeSyncedYamlValues();
			RefreshYamlAuthorityMode(force: true);
		}

		public static void Dispose()
		{
			DisposeSyncedYamlValues();
			_watcher?.Dispose();
			_watcher = null;
		}

		public static void ApplyToObjectDb(ObjectDB objectDb, bool emitMissingWarnings)
		{
			RefreshYamlAuthorityMode();
			ApplyCompiledSnapshotToObjectDb(objectDb, _currentCompiledSnapshot, emitMissingWarnings);
		}

		internal static void TryApplyPendingConfig()
		{
			RefreshYamlAuthorityMode();
			if (!CommitPendingConfig(force: false, applyToObjectDbImmediately: true))
			{
				CommitPendingWorldReapply(force: false);
			}
		}

		internal static void RequestCurrentWorldReapply()
		{
			lock (ReloadLock)
			{
				StageWorldReapply();
			}
		}

		internal static void ApplyPendingConfigToObjectDb(ObjectDB objectDb, bool emitMissingWarnings)
		{
			RefreshYamlAuthorityMode();
			bool num = CommitPendingConfig(force: true, applyToObjectDbImmediately: false);
			ApplyCompiledSnapshotToObjectDb(objectDb, _currentCompiledSnapshot, emitMissingWarnings);
			if (num)
			{
				CaptainValheimPlugin.ModLogger.LogInfo((object)"Applied staged YAML config changes.");
			}
		}

		internal static void ApplyPendingConfigToZNetScene(ZNetScene scene, bool emitMissingWarnings)
		{
			RefreshYamlAuthorityMode();
			bool num = CommitPendingConfig(force: true, applyToObjectDbImmediately: false);
			ApplyCompiledSnapshotToZNetScene(scene, _currentCompiledSnapshot, emitMissingWarnings);
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				ApplyCompiledSnapshotToObjectDb(ObjectDB.instance, _currentCompiledSnapshot, emitMissingWarnings, applyZNetScene: false);
			}
			if (num)
			{
				CaptainValheimPlugin.ModLogger.LogInfo((object)"Applied staged YAML config changes.");
			}
		}

		private static void SetupWatcher()
		{
			if (_watcher == null)
			{
				Directory.CreateDirectory(SecondaryAttackYamlDomainRegistry.ConfigDirectoryPath);
				_watcher = new FileSystemWatcher(SecondaryAttackYamlDomainRegistry.ConfigDirectoryPath, "CaptainValheim.yml");
				_watcher.Changed += OnYamlFileChanged;
				_watcher.Created += OnYamlFileChanged;
				_watcher.Renamed += OnYamlFileChanged;
				_watcher.IncludeSubdirectories = false;
				_watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
				_watcher.EnableRaisingEvents = true;
			}
		}

		private static void OnYamlFileChanged(object sender, FileSystemEventArgs e)
		{
			if (_yamlAuthorityMode != YamlAuthorityMode.LocalFiles)
			{
				return;
			}
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastYamlReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (ReloadLock)
			{
				ReloadLocalYaml();
				_lastYamlReloadTime = now;
			}
		}

		private static void ReloadLocalYaml()
		{
			if (_yamlAuthorityMode != YamlAuthorityMode.LocalFiles)
			{
				return;
			}
			SecondaryAttackConfigLoader.EnsureLocalFilesExist();
			SecondaryAttackYamlTexts secondaryAttackYamlTexts = SecondaryAttackConfigLoader.ReadLocalYamlTexts();
			if (SyncedYamlValues.Count == SecondaryAttackYamlDomainRegistry.Domains.Count)
			{
				_suppressSyncedYamlChanged = true;
				try
				{
					foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
					{
						SyncedYamlValues[domain.Id].AssignLocalValue(secondaryAttackYamlTexts.Get(domain.Id));
					}
				}
				finally
				{
					_suppressSyncedYamlChanged = false;
				}
			}
			ApplyYamlTexts(secondaryAttackYamlTexts);
		}

		private static void OnSyncedYamlChanged()
		{
			if (!_suppressSyncedYamlChanged)
			{
				ApplyYamlTexts(ReadSyncedYamlTexts());
			}
		}

		private static void RefreshYamlAuthorityMode(bool force = false)
		{
			YamlAuthorityMode yamlAuthorityMode = DetermineYamlAuthorityMode();
			if (!force && yamlAuthorityMode == _yamlAuthorityMode)
			{
				return;
			}
			_yamlAuthorityMode = yamlAuthorityMode;
			switch (yamlAuthorityMode)
			{
			case YamlAuthorityMode.LocalFiles:
				SetupWatcher();
				ReloadLocalYaml();
				CaptainValheimPlugin.ModLogger.LogInfo((object)"CaptainValheim YAML authority mode: LocalFiles.");
				break;
			case YamlAuthorityMode.SyncedOnly:
				DisposeWatcher();
				if (AnySyncedYamlHasValue())
				{
					ApplyYamlTexts(ReadSyncedYamlTexts());
				}
				else
				{
					_pendingCompiledSnapshot = null;
					_pendingYamlFingerprint = null;
					_hasPendingConfig = false;
					_hasPendingWorldReapply = false;
					_currentCompiledSnapshot = SecondaryAttackCompiledSnapshot.Empty;
					_currentYamlFingerprint = string.Empty;
					_currentAppliedWorldSnapshot = SecondaryAttackAppliedWorldSnapshot.Empty;
					if ((Object)(object)ZNetScene.instance != (Object)null)
					{
						ApplyCompiledSnapshotToZNetScene(ZNetScene.instance, _currentCompiledSnapshot, emitMissingWarnings: true);
					}
				}
				CaptainValheimPlugin.ModLogger.LogInfo((object)"CaptainValheim YAML authority mode: SyncedOnly.");
				break;
			}
		}

		private static YamlAuthorityMode DetermineYamlAuthorityMode()
		{
			if (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer())
			{
				return YamlAuthorityMode.LocalFiles;
			}
			return YamlAuthorityMode.SyncedOnly;
		}

		private static void InitializeSyncedYamlValues()
		{
			DisposeSyncedYamlValues();
			foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
			{
				CustomSyncedValue<string> customSyncedValue = new CustomSyncedValue<string>(CaptainValheimPlugin.ConfigSync, domain.SyncedIdentifier, "");
				customSyncedValue.ValueChanged += OnSyncedYamlChanged;
				SyncedYamlValues[domain.Id] = customSyncedValue;
			}
		}

		private static void DisposeSyncedYamlValues()
		{
			foreach (CustomSyncedValue<string> value in SyncedYamlValues.Values)
			{
				value.ValueChanged -= OnSyncedYamlChanged;
			}
			SyncedYamlValues.Clear();
		}

		private static SecondaryAttackYamlTexts ReadSyncedYamlTexts()
		{
			Dictionary<SecondaryAttackYamlDomainId, string> dictionary = new Dictionary<SecondaryAttackYamlDomainId, string>();
			foreach (SecondaryAttackYamlDomain domain in SecondaryAttackYamlDomainRegistry.Domains)
			{
				dictionary[domain.Id] = (SyncedYamlValues.TryGetValue(domain.Id, out CustomSyncedValue<string> value) ? value.Value : string.Empty);
			}
			return new SecondaryAttackYamlTexts(dictionary);
		}

		private static bool AnySyncedYamlHasValue()
		{
			return SyncedYamlValues.Values.Any((CustomSyncedValue<string> syncedValue) => !string.IsNullOrEmpty(syncedValue.Value));
		}

		private static void DisposeWatcher()
		{
			if (_watcher != null)
			{
				_watcher.Dispose();
				_watcher = null;
			}
		}

		private static void ApplyYamlTexts(SecondaryAttackYamlTexts yamlTexts)
		{
			string contentFingerprint = yamlTexts.GetContentFingerprint();
			if (!string.Equals(_currentYamlFingerprint, contentFingerprint, StringComparison.Ordinal) && (!_hasPendingConfig || !string.Equals(_pendingYamlFingerprint, contentFingerprint, StringComparison.Ordinal)) && SecondaryAttackConfigLoader.TryCompileSnapshot(_nextSnapshotId++, yamlTexts, out SecondaryAttackCompiledSnapshot snapshot))
			{
				StageConfig(snapshot, contentFingerprint);
			}
		}

		private static void StageConfig(SecondaryAttackCompiledSnapshot snapshot, string fingerprint)
		{
			_pendingCompiledSnapshot = snapshot;
			_pendingYamlFingerprint = fingerprint;
			_hasPendingConfig = true;
			CommitPendingConfig(force: true, applyToObjectDbImmediately: true);
		}

		private static void StageWorldReapply()
		{
			_hasPendingWorldReapply = true;
			CommitPendingWorldReapply(force: true);
		}

		private static bool CommitPendingConfig(bool force, bool applyToObjectDbImmediately)
		{
			if (!_hasPendingConfig || _pendingCompiledSnapshot == null)
			{
				return false;
			}
			if (!force && !CanApplyPendingConfigNow())
			{
				return false;
			}
			_currentCompiledSnapshot = _pendingCompiledSnapshot;
			_currentYamlFingerprint = _pendingYamlFingerprint ?? _currentYamlFingerprint;
			_pendingCompiledSnapshot = null;
			_pendingYamlFingerprint = null;
			_hasPendingConfig = false;
			if (applyToObjectDbImmediately && (Object)(object)ObjectDB.instance != (Object)null)
			{
				ApplyCompiledSnapshotToObjectDb(ObjectDB.instance, _currentCompiledSnapshot, emitMissingWarnings: true);
			}
			CaptainValheimPlugin.ModLogger.LogInfo((object)"Applied staged YAML config changes.");
			return true;
		}

		private static bool CommitPendingWorldReapply(bool force)
		{
			if (!_hasPendingWorldReapply)
			{
				return false;
			}
			if (!force && !CanApplyPendingConfigNow())
			{
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			ApplyCompiledSnapshotToObjectDb(ObjectDB.instance, _currentCompiledSnapshot, emitMissingWarnings: true);
			CaptainValheimPlugin.ModLogger.LogInfo((object)"Applied staged world-apply config changes.");
			return true;
		}

		private static void ApplyCompiledSnapshotToObjectDb(ObjectDB objectDb, SecondaryAttackCompiledSnapshot compiledSnapshot, bool emitMissingWarnings, bool applyZNetScene = true)
		{
			_hasPendingWorldReapply = false;
			if (applyZNetScene && (Object)(object)ZNetScene.instance != (Object)null)
			{
				ApplyCompiledSnapshotToZNetScene(ZNetScene.instance, compiledSnapshot, emitMissingWarnings);
			}
			_currentAppliedWorldSnapshot = SecondaryAttackWorldApplySystem.Apply(objectDb, compiledSnapshot, emitMissingWarnings);
		}

		private static void ApplyCompiledSnapshotToZNetScene(ZNetScene scene, SecondaryAttackCompiledSnapshot compiledSnapshot, bool emitMissingWarnings)
		{
			SecondaryAttackWorldApplyContributors.ApplyToZNetScene(scene, compiledSnapshot, emitMissingWarnings);
		}

		private static bool CanApplyPendingConfigNow()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			if (((Humanoid)localPlayer).m_currentAttack != null)
			{
				return false;
			}
			if (!ShieldRuntimeSystem.IsShieldChargeActiveForDebug((Humanoid)(object)localPlayer))
			{
				return !SecondaryAttackManager.HasActiveAsyncSecondaryWorkForFacade((Character?)(object)localPlayer);
			}
			return false;
		}
	}
	internal static class SecondaryAttackConfigCompiler
	{
		public static SecondaryAttackCompiledSnapshot Compile(int snapshotId, SecondaryAttackParsedYaml parsedYaml)
		{
			return Compile(snapshotId, parsedYaml.Shields);
		}

		public static SecondaryAttackCompiledSnapshot Compile(int snapshotId, IReadOnlyDictionary<string, ShieldWeaponConfig> parsedShields)
		{
			return new SecondaryAttackCompiledSnapshot(snapshotId, SecondaryAttackNormalizedConfigFacade.FromParsed(parsedShields));
		}
	}
	internal readonly struct SecondaryAttackDefinitionBuildContext
	{
		public ObjectDB ObjectDb { get; }

		public bool EmitMissingWarnings { get; }

		public SecondaryAttackDefinitionBuildContext(ObjectDB objectDb, bool emitMissingWarnings)
		{
			ObjectDb = objectDb;
			EmitMissingWarnings = emitMissingWarnings;
		}
	}
	internal static class SecondaryAttackDefinitionCompiler
	{
		private readonly struct DefinitionFeatures
		{
			public bool HasShieldConfig { get; }

			public bool UsesShieldSpecials { get; }

			public bool UsesShieldReflect { get; }

			public bool UsesShieldBlockCharge { get; }

			public bool WantsSecondaryOverride => UsesShieldSpecials;

			public DefinitionFeatures(bool hasShieldConfig, bool usesShieldSpecials, bool usesShieldReflect, bool usesShieldBlockCharge)
			{
				HasShieldConfig = hasShieldConfig;
				UsesShieldSpecials = usesShieldSpecials;
				UsesShieldReflect = usesShieldReflect;
				UsesShieldBlockCharge = usesShieldBlockCharge;
			}
		}

		private enum DefinitionValidationDisposition
		{
			Continue,
			Skip,
			EffectOnly
		}

		private readonly struct DefinitionValidationResult
		{
			public DefinitionValidationDisposition Disposition { get; }

			public Attack? PrimaryAttack { get; }

			public DefinitionValidationResult(DefinitionValidationDisposition disposition, Attack? primaryAttack = null)
			{
				Disposition = disposition;
				PrimaryAttack = primaryAttack;
			}
		}

		internal static bool TryCreateDefinition(SecondaryAttackDefinitionBuildContext buildContext, string prefabName, ItemDrop itemDrop, NormalizedWeaponConfig weaponConfig, out SecondaryAttackDefinition? definition)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			definition = null;
			SharedData val = itemDrop.m_itemData?.m_shared;
			if (val == null)
			{
				return false;
			}
			DefinitionFeatures features = AnalyzeDefinitionFeatures(weaponConfig);
			DefinitionValidationResult definitionValidationResult = ValidateDefinitionRequest(prefabName, val, weaponConfig, features);
			switch (definitionValidationResult.Disposition)
			{
			case DefinitionValidationDisposition.EffectOnly:
				definition = SecondaryAttackManager.CreateEffectOnlyDefinition(prefabName, weaponConfig);
				return true;
			case DefinitionValidationDisposition.Skip:
				return false;
			default:
				return TryCreateValidatedDefinition(buildContext, prefabName, val, (Attack)(((object)definitionValidationResult.PrimaryAttack) ?? ((object)new Attack())), weaponConfig, features, out definition);
			}
		}

		private static DefinitionFeatures AnalyzeDefinitionFeatures(NormalizedWeaponConfig weaponConfig)
		{
			bool hasShieldConfig = weaponConfig.Shield != null;
			bool usesShieldSpecials = weaponConfig.Shield?.PrimaryAttack != null || weaponConfig.Shield?.Throw != null || weaponConfig.Shield?.Charge != null;
			bool usesShieldReflect = weaponConfig.Shield?.Reflect != null;
			bool usesShieldBlockCharge = weaponConfig.Shield?.BlockCharge != null;
			return new DefinitionFeatures(hasShieldConfig, usesShieldSpecials, usesShieldReflect, usesShieldBlockCharge);
		}

		private static bool TryCreateValidatedDefinition(SecondaryAttackDefinitionBuildContext buildContext, string prefabName, SharedData sharedData, Attack primaryAttack, NormalizedWeaponConfig weaponConfig, DefinitionFeatures features, out SecondaryAttackDefinition? definition)
		{
			definition = null;
			if (features.UsesShieldSpecials)
			{
				return SecondaryAttackManager.TryCreateShieldSpecialDefinition(prefabName, sharedData, weaponConfig, out definition);
			}
			if (features.UsesShieldReflect || features.UsesShieldBlockCharge)
			{
				definition = SecondaryAttackManager.CreateEffectOnlyDefinition(prefabName, weaponConfig);
				return true;
			}
			return false;
		}

		private static DefinitionValidationResult ValidateDefinitionRequest(string prefabName, SharedData sharedData, NormalizedWeaponConfig weaponConfig, DefinitionFeatures features)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (!features.HasShieldConfig)
			{
				return new DefinitionValidationResult(DefinitionValidationDisposition.Skip);
			}
			if ((int)sharedData.m_itemType != 5)
			{
				CaptainValheimPlugin.ModLogger.LogWarning((object)("Skipping " + prefabName + ": CaptainValheim shield features can only be used on shield prefabs."));
				return new DefinitionValidationResult(DefinitionValidationDisposition.Skip);
			}
			if (!features.WantsSecondaryOverride)
			{
				if (!features.UsesShieldReflect && !features.UsesShieldBlockCharge)
				{
					return new DefinitionValidationResult(DefinitionValidationDisposition.Skip);
				}
				return new DefinitionValidationResult(DefinitionValidationDisposition.EffectOnly);
			}
			return new DefinitionValidationResult(DefinitionValidationDisposition.Continue, (Attack?)(((object)sharedData.m_attack) ?? ((object)new Attack())));
		}
	}
	internal sealed class NormalizedSecondaryAttackConfigFile
	{
		public Dictionary<string, NormalizedWeaponConfig> Weapons { get; set; } = new Dictionary<string, NormalizedWeaponConfig>(StringComparer.OrdinalIgnoreCase);

		public NormalizedWeaponConfig? GlobalShieldFallback { get; set; }
	}
	internal static class SecondaryAttackNormalizedConfigFacade
	{
		internal static NormalizedSecondaryAttackConfigFile FromParsed(IReadOnlyDictionary<string, ShieldWeaponConfig> shields)
		{
			SecondaryAttackWeaponNormalizationResult secondaryAttackWeaponNormalizationResult = SecondaryAttackWeaponConfigNormalizer.Normalize(shields);
			return new NormalizedSecondaryAttackConfigFile
			{
				Weapons = secondaryAttackWeaponNormalizationResult.Weapons,
				GlobalShieldFallback = secondaryAttackWeaponNormalizationResult.GlobalShieldFallback
			};
		}
	}
	internal sealed class NormalizedShieldModeConfig
	{
		public NormalizedShieldPrimaryAttackConfig? PrimaryAttack { get; set; }

		public NormalizedShieldThrowConfig? Throw { get; set; }

		public NormalizedShieldChargeConfig? Charge { get; set; }

		public NormalizedShieldReflectConfig? Reflect { get; set; }

		public NormalizedShieldBlockChargeConfig? BlockCharge { get; set; }
	}
	internal sealed class NormalizedShieldPrimaryAttackConfig
	{
		public float DamageFactor { get; set; } = 0.4f;

		public float PushFactor { get; set; } = 1f;

		public float StaminaFactor { get; set; } = 0.8f;

		public float DurabilityFactor { get; set; } = 1f;

		public float AdrenalineFactor { get; set; } = 1f;
	}
	internal sealed class NormalizedShieldThrowConfig
	{
		public string Animation { get; set; } = "battleaxe_attack1";

		public float DamageFactor { get; set; } = 0.8f;

		public float PushFactor { get; set; } = 1f;

		public float StaminaFactor { get; set; } = 2f;

		public float DurabilityFactor { get; set; } = 1f;

		public int Targets { get; set; } = 3;

		public float DamageDecay { get; set; } = 0.5f;

		public float RadiusFactor { get; set; } = 6f;

		public float TtlFactor { get; set; } = 1f;

		public float AdrenalineFactor { get; set; } = 1f;
	}
	internal sealed class NormalizedShieldChargeConfig
	{
		public float DamageFactor { get; set; } = 1.2f;

		public float PushFactor { get; set; } = 2f;

		public float StaminaFactor { get; set; } = 3f;

		public float Distance { get; set; } = 4f;

		public float Speed { get; set; } = 12f;

		public float Cooldown { get; set; } = 10f;

		public float CooldownReductionFactor { get; set; } = 0.5f;

		public float DurabilityFactor { get; set; } = 2f;

		public float HitRadiusFactor { get; set; } = 0.4f;

		public float AdrenalineFactor { get; set; } = 5f;
	}
	internal static class ShieldAdrenalineFactors
	{
		public const float PrimaryAttack = 1f;

		public const float Throw = 1f;

		public const float Charge = 5f;
	}
	internal sealed class NormalizedShieldReflectConfig
	{
		public float StaminaFactor { get; set; } = 2f;

		public float ReflectionFactor { get; set; } = 0.01f;
	}
	internal sealed class NormalizedShieldBlockChargeConfig
	{
		public int? ChargeCount { get; set; }

		public float? DecayTime { get; set; }

		public float? BlockingDecayFactor { get; set; }
	}
	internal sealed class NormalizedWeaponConfig
	{
		public NormalizedShieldModeConfig? Shield { get; set; }
	}
	internal sealed class ShieldWeaponConfig
	{
		public ShieldPrimaryAttackConfig? PrimaryAttack { get; set; }

		public ShieldThrowConfig? Throw { get; set; }

		public ShieldChargeConfig? Charge { get; set; }

		public ShieldReflectConfig? Reflect { get; set; }

		public ShieldBlockChargeConfig? BlockCharge { get; set; }
	}
	internal sealed class ShieldPrimaryAttackConfig
	{
		public bool? Enabled { get; set; }

		public float? DamageFactor { get; set; }

		public float? PushFactor { get; set; }

		public float? StaminaFactor { get; set; }

		public float? DurabilityFactor { get; set; }
	}
	internal sealed class ShieldThrowConfig
	{
		public bool? Enabled { get; set; }

		public string? Animation { get; set; }

		public float? DamageFactor { get; set; }

		public float? PushFactor { get; set; }

		public float? StaminaFactor { get; set; }

		public float? DurabilityFactor { get; set; }

		public int? Targets { get; set; }

		public float? DamageDecay { get; set; }

		public float? RadiusFactor { get; set; }

		public float? TtlFactor { get; set; }
	}
	internal sealed class ShieldChargeConfig
	{
		public bool? Enabled { get; set; }

		public float? Damage