Decompiled source of SecondaryAttacks v1.0.1

SecondaryAttacks.dll

Decompiled 6 hours 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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
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("SecondaryAttacks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyProduct("SecondaryAttacks")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 LocalizationManager
{
	[PublicAPI]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		private static BaseUnityPlugin? _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		public static event Action? OnLocalizationComplete;

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out string value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out Dictionary<string, Func<string>> value2))
			{
				text = value2.Aggregate(text, (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, Func<T, string>? convertConfigValue = null) where T : notnull
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += delegate
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			_ = plugin;
			if (Localization.instance != null)
			{
				LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage());
			}
		}

		public static void LoadLocalizationLater()
		{
			if (Localization.instance != null)
			{
				LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage());
			}
		}

		public static void SafeCallLocalizeComplete()
		{
			Localizer.OnLocalizationComplete?.Invoke();
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string[] array = Path.GetFileNameWithoutExtension(item).Split('.');
				if (array.Length >= 2)
				{
					string text = array[1];
					if (dictionary.ContainsKey(text))
					{
						Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
					}
					else
					{
						dictionary[text] = item;
					}
				}
			}
			byte[] array2 = LoadTranslationFromAssembly("English");
			if (array2 == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml.");
			}
			Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array2));
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.TryGetValue(language, out var value))
				{
					text2 = File.ReadAllText(value);
				}
				else
				{
					byte[] array3 = LoadTranslationFromAssembly(language);
					if (array3 != null)
					{
						text2 = Encoding.UTF8.GetString(array3);
					}
				}
			}
			if (text2 == null && dictionary.TryGetValue("English", out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			if (text2 != null)
			{
				foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//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)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string>(2) { ".json", ".yml" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static byte[]? LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
	public static class LocalizationManagerVersion
	{
		public const string Version = "1.4.0";
	}
}
namespace SecondaryAttacks
{
	internal static class AftershockSystem
	{
		internal sealed class AftershockController : MonoBehaviour
		{
			private int _nextWave;

			private float _nextWaveTime;

			private bool _registered;

			private bool _durabilityDrained;

			private bool _finished;

			internal Attack Attack { get; private set; }

			internal AftershockDefinition Aftershock { get; private set; }

			internal Vector3 BaseOrigin { get; private set; }

			internal Vector3 Forward { get; private set; }

			internal Quaternion Rotation { get; private set; }

			internal void Initialize(Attack attack, AftershockDefinition aftershock)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				Attack = attack;
				Aftershock = aftershock;
				Transform transform = ((Component)attack.m_character).transform;
				Transform val = ResolveAttackOrigin(attack);
				Forward = transform.forward;
				Rotation = transform.rotation;
				BaseOrigin = val.position + Vector3.up * attack.m_attackHeight + Forward * attack.m_attackRange + transform.right * attack.m_attackOffset;
				_nextWave = 0;
				_nextWaveTime = Time.time;
				_registered = true;
				SecondaryAttackManager.RegisterAsyncSecondaryWork((Character?)(object)attack.m_character);
				((Behaviour)this).enabled = true;
			}

			private void Update()
			{
				if ((Object)(object)Attack?.m_character == (Object)null || Attack.m_weapon == null || ((Character)Attack.m_character).IsDead() || !SecondaryAttackManager.HasCharacterAuthority((Character?)(object)Attack.m_character))
				{
					Finish();
					return;
				}
				while (_nextWave <= Aftershock.Waves && Time.time >= _nextWaveTime)
				{
					ApplyWave(this, _nextWave);
					_nextWave++;
					float num = Mathf.Max(0f, Aftershock.Interval);
					_nextWaveTime += num;
					if (num > 0f)
					{
						break;
					}
				}
				if (_nextWave > Aftershock.Waves)
				{
					Finish();
				}
			}

			internal void DrainDurabilityOnce()
			{
				if (!_durabilityDrained)
				{
					SecondaryAttackManager.DrainAttackDurability(Attack, Aftershock.DurabilityFactor);
					_durabilityDrained = true;
				}
			}

			private void Finish()
			{
				if (!_finished)
				{
					_finished = true;
					Object.Destroy((Object)(object)this);
				}
			}

			private void OnDestroy()
			{
				if (_registered)
				{
					SecondaryAttackManager.UnregisterAsyncSecondaryWork((Character?)(object)Attack?.m_character);
					_registered = false;
				}
			}
		}

		private static readonly Collider[] Hits = (Collider[])(object)new Collider[128];

		private static readonly HashSet<GameObject> HitObjects = new HashSet<GameObject>();

		private static int _attackMask;

		private static int _attackMaskTerrain;

		private static int _attackMaskCharacters;

		internal static bool CanHandle(Attack attack, SecondaryAttackDefinition definition)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			if (attack != null && definition?.Aftershock != null && (Object)(object)attack.m_character != (Object)null && attack.m_weapon != null && (int)attack.m_attackType == 4)
			{
				return attack.m_attackRayWidth > 0f;
			}
			return false;
		}

		internal static void Trigger(Attack attack, SecondaryAttackDefinition definition)
		{
			if (CanHandle(attack, definition) && SecondaryAttackManager.HasCharacterAuthority((Character?)(object)attack.m_character))
			{
				AftershockDefinition aftershock = definition.Aftershock;
				ApplyAttackTriggerSideEffects(attack);
				((Component)attack.m_character).gameObject.AddComponent<AftershockController>().Initialize(attack, aftershock);
			}
		}

		private static void ApplyAttackTriggerSideEffects(Attack attack)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			if (attack.m_toggleFlying)
			{
				if (((Character)attack.m_character).IsFlying())
				{
					((Character)attack.m_character).Land();
				}
				else
				{
					((Character)attack.m_character).TakeOff();
				}
			}
			if (attack.m_recoilPushback != 0f)
			{
				((Character)attack.m_character).ApplyPushback(-((Component)attack.m_character).transform.forward, attack.m_recoilPushback);
			}
			if ((float)attack.m_selfDamage > 0f)
			{
				HitData val = new HitData();
				val.m_damage.m_damage = attack.m_selfDamage;
				((Character)attack.m_character).Damage(val);
			}
			if (attack.m_consumeItem)
			{
				attack.ConsumeItem();
			}
			if (attack.m_requiresReload)
			{
				attack.m_character.ResetLoadedWeapon();
			}
		}

		private static void ApplyWave(AftershockController controller, int waveIndex)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			Attack attack = controller.Attack;
			AftershockDefinition aftershock = controller.Aftershock;
			Character character = (Character)(object)attack.m_character;
			ItemData weapon = attack.m_weapon;
			if ((Object)(object)character == (Object)null || weapon?.m_shared == null)
			{
				return;
			}
			float visualScale;
			float pushScale;
			float num;
			float damageScale;
			float volumeScale = (visualScale = (pushScale = (num = (damageScale = ((waveIndex <= 0) ? 1f : Mathf.Pow(1f - aftershock.WaveDecay, (float)waveIndex))))));
			float num2 = Mathf.Max(0.01f, attack.m_attackRayWidth * num);
			float num3 = Mathf.Max(0.01f, (attack.m_attackRayWidth + attack.m_attackRayWidthCharExtra) * num);
			Vector3 val = controller.BaseOrigin + controller.Forward * aftershock.ForwardStep * (float)waveIndex;
			Transform parent = ResolveAttackOrigin(attack);
			CreateScaledEffects(weapon.m_shared.m_triggerEffect, val, controller.Rotation, parent, visualScale, volumeScale);
			CreateScaledEffects(attack.m_triggerEffect, val, controller.Rotation, parent, visualScale, volumeScale);
			int hitCount = 0;
			Vector3 averageHitPoint = Vector3.zero;
			float randomSkillFactor = character.GetRandomSkillFactor(weapon.m_shared.m_skillType);
			float maxAdrenalineMultiplier = 0f;
			HitObjects.Clear();
			int num4 = (attack.m_hitTerrain ? GetAttackMaskTerrain() : GetAttackMask());
			CheckHits(controller, val, Physics.OverlapSphereNonAlloc(val, num2, Hits, num4, (QueryTriggerInteraction)0), damageScale, pushScale, randomSkillFactor, ref hitCount, ref averageHitPoint, ref maxAdrenalineMultiplier);
			if (attack.m_attackRayWidthCharExtra > 0f || attack.m_attackHeightChar1 != 0f)
			{
				CheckHits(controller, val, Physics.OverlapSphereNonAlloc(val + Vector3.up * attack.m_attackHeightChar1, num3, Hits, GetAttackMaskCharacters(), (QueryTriggerInteraction)0), damageScale, pushScale, randomSkillFactor, ref hitCount, ref averageHitPoint, ref maxAdrenalineMultiplier);
				if (!Mathf.Approximately(attack.m_attackHeightChar2, attack.m_attackHeightChar1))
				{
					CheckHits(controller, val, Physics.OverlapSphereNonAlloc(val + Vector3.up * attack.m_attackHeightChar2, num3, Hits, GetAttackMaskCharacters(), (QueryTriggerInteraction)0), damageScale, pushScale, randomSkillFactor, ref hitCount, ref averageHitPoint, ref maxAdrenalineMultiplier);
				}
			}
			if (hitCount > 0)
			{
				averageHitPoint /= (float)hitCount;
				CreateScaledEffects(weapon.m_shared.m_hitEffect, averageHitPoint, Quaternion.identity, null, visualScale, volumeScale);
				CreateScaledEffects(attack.m_hitEffect, averageHitPoint, Quaternion.identity, null, visualScale, volumeScale);
				controller.DrainDurabilityOnce();
				character.AddNoise(attack.m_attackHitNoise);
				if (maxAdrenalineMultiplier > 0f)
				{
					SecondaryAttackAdrenalineSystem.TryGrantOnce(attack, maxAdrenalineMultiplier, 1f, "aftershock");
				}
			}
			if ((Object)(object)attack.m_spawnOnTrigger != (Object)null)
			{
				IProjectile component = Object.Instantiate<GameObject>(attack.m_spawnOnTrigger, val, Quaternion.identity).GetComponent<IProjectile>();
				if (component != null)
				{
					component.Setup(character, ((Component)character).transform.forward, -1f, (HitData)null, (ItemData)null, attack.m_lastUsedAmmo);
				}
			}
		}

		private static void CheckHits(AftershockController controller, Vector3 origin, int count, float damageScale, float pushScale, float skillDamageFactor, ref int hitCount, ref Vector3 averageHitPoint, ref float maxAdrenalineMultiplier)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			Attack attack = controller.Attack;
			Character character = (Character)(object)attack.m_character;
			ItemData weapon = attack.m_weapon;
			Transform transform = ((Component)character).transform;
			for (int i = 0; i < count; i++)
			{
				Collider val = Hits[i];
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)(object)((Component)character).gameObject)
				{
					continue;
				}
				GameObject val2 = Projectile.FindHitObject(val);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)((Component)character).gameObject || !HitObjects.Add(val2))
				{
					continue;
				}
				Vector3 val3 = SecondaryAttackManager.ResolveSafeClosestPoint(val, origin);
				Vector3 val4 = val3 - origin;
				if (((Vector3)(ref val4)).sqrMagnitude < 0.0001f)
				{
					Bounds bounds = val.bounds;
					val3 = ((Bounds)(ref bounds)).center;
				}
				IDestructible component = val2.GetComponent<IDestructible>();
				if (component == null)
				{
					continue;
				}
				Vector3 val5 = val3 - origin;
				val5.y = 0f;
				Vector3 val6 = val3 - transform.position;
				if (Vector3.Dot(val6, val5) < 0f)
				{
					val5 = val6;
				}
				if (((Vector3)(ref val5)).sqrMagnitude < 0.0001f)
				{
					val5 = transform.forward;
				}
				((Vector3)(ref val5)).Normalize();
				HitData val7 = CreateHitData(attack, val, val3, val5, skillDamageFactor, damageScale, pushScale);
				Character val8 = (Character)(object)((component is Character) ? component : null);
				bool flag = false;
				if ((Object)(object)val8 != (Object)null)
				{
					flag = BaseAI.IsEnemy(character, val8) || ((Object)(object)val8.GetBaseAI() != (Object)null && val8.GetBaseAI().IsAggravatable() && character.IsPlayer());
					if (((!attack.m_hitFriendly || character.IsTamed()) && !character.IsPlayer() && !flag) || (!weapon.m_shared.m_tamedOnly && character.IsPlayer() && !character.IsPVPEnabled() && !flag) || (weapon.m_shared.m_tamedOnly && !val8.IsTamed()))
					{
						continue;
					}
					if (flag && val8.m_enemyAdrenalineMultiplier > maxAdrenalineMultiplier)
					{
						maxAdrenalineMultiplier = val8.m_enemyAdrenalineMultiplier;
					}
					if (val7.m_dodgeable && val8.IsDodgeInvincible())
					{
						if (val8.IsPlayer())
						{
							Character obj = ((val8 is Player) ? val8 : null);
							if (obj != null)
							{
								((Player)obj).HitWhileDodging();
							}
						}
						continue;
					}
				}
				else if (weapon.m_shared.m_tamedOnly)
				{
					continue;
				}
				TrySpawnOnHit(attack, val2);
				character.GetSEMan().ModifyAttack(weapon.m_shared.m_skillType, ref val7);
				if (attack.m_attackHealthReturnHit > 0f && flag)
				{
					character.Heal(attack.m_attackHealthReturnHit, true);
				}
				component.Damage(val7);
				hitCount++;
				averageHitPoint += val3;
			}
		}

		private static HitData CreateHitData(Attack attack, Collider collider, Vector3 hitPoint, Vector3 hitDirection, float skillDamageFactor, float damageScale, float pushScale)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return SecondaryAttackHitDataFactory.CreateMeleeHit(attack, collider, hitPoint, hitDirection, skillDamageFactor, damageScale, pushScale);
		}

		private static void TrySpawnOnHit(Attack attack, GameObject hitObject)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!(attack.m_spawnOnHitChance <= 0f) && !((Object)(object)attack.m_spawnOnHit == (Object)null) && !(Random.Range(0f, 1f) >= attack.m_spawnOnHitChance))
			{
				IProjectile componentInChildren = Object.Instantiate<GameObject>(attack.m_spawnOnHit, hitObject.transform.position, hitObject.transform.rotation).GetComponentInChildren<IProjectile>();
				if (componentInChildren != null)
				{
					componentInChildren.Setup((Character)(object)attack.m_character, ((Component)attack.m_character).transform.forward, -1f, (HitData)null, attack.m_weapon, attack.m_lastUsedAmmo);
				}
			}
		}

		private static Transform ResolveAttackOrigin(Attack attack)
		{
			if (!string.IsNullOrWhiteSpace(attack.m_attackOriginJoint))
			{
				GameObject visual = ((Character)attack.m_character).GetVisual();
				if ((Object)(object)visual != (Object)null)
				{
					Transform val = Utils.FindChild(visual.transform, attack.m_attackOriginJoint, (IterativeSearchType)0);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return ((Component)attack.m_character).transform;
		}

		private static void CreateScaledEffects(EffectList effects, Vector3 position, Quaternion rotation, Transform? parent, float visualScale, float volumeScale)
		{
			//IL_001a: 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)
			if (effects == null || !effects.HasEffects())
			{
				return;
			}
			float num = Mathf.Max(0f, visualScale);
			GameObject[] array = effects.Create(position, rotation, parent, num, -1);
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ScaleParticleSystems(val, num);
				ZSFX[] componentsInChildren = val.GetComponentsInChildren<ZSFX>(true);
				foreach (ZSFX obj in componentsInChildren)
				{
					obj.SetVolumeModifier(obj.GetVolumeModifier() * volumeScale);
				}
				AudioSource[] componentsInChildren2 = val.GetComponentsInChildren<AudioSource>(true);
				foreach (AudioSource val2 in componentsInChildren2)
				{
					if ((Object)(object)((Component)val2).GetComponent<ZSFX>() == (Object)null)
					{
						val2.volume *= volumeScale;
					}
				}
			}
		}

		private static void ScaleParticleSystems(GameObject instance, float visualScale)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			if (Mathf.Approximately(visualScale, 1f))
			{
				return;
			}
			ParticleSystem[] componentsInChildren = instance.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem obj in componentsInChildren)
			{
				MainModule main = obj.main;
				if (((MainModule)(ref main)).startSize3D)
				{
					((MainModule)(ref main)).startSizeX = ScaleCurve(((MainModule)(ref main)).startSizeX, visualScale);
					((MainModule)(ref main)).startSizeY = ScaleCurve(((MainModule)(ref main)).startSizeY, visualScale);
					((MainModule)(ref main)).startSizeZ = ScaleCurve(((MainModule)(ref main)).startSizeZ, visualScale);
				}
				else
				{
					((MainModule)(ref main)).startSize = ScaleCurve(((MainModule)(ref main)).startSize, visualScale);
				}
				((MainModule)(ref main)).startSpeed = ScaleCurve(((MainModule)(ref main)).startSpeed, visualScale);
				ShapeModule shape = obj.shape;
				if (((ShapeModule)(ref shape)).enabled)
				{
					((ShapeModule)(ref shape)).radius = ((ShapeModule)(ref shape)).radius * visualScale;
					((ShapeModule)(ref shape)).scale = ((ShapeModule)(ref shape)).scale * visualScale;
					((ShapeModule)(ref shape)).position = ((ShapeModule)(ref shape)).position * visualScale;
				}
				TrailModule trails = obj.trails;
				if (((TrailModule)(ref trails)).enabled)
				{
					((TrailModule)(ref trails)).widthOverTrail = ScaleCurve(((TrailModule)(ref trails)).widthOverTrail, visualScale);
				}
				ParticleSystemRenderer component = ((Component)obj).GetComponent<ParticleSystemRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					component.lengthScale *= visualScale;
					component.velocityScale *= visualScale;
				}
			}
		}

		private static MinMaxCurve ScaleCurve(MinMaxCurve curve, float scale)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected I4, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystemCurveMode mode = ((MinMaxCurve)(ref curve)).mode;
			switch ((int)mode)
			{
			case 0:
				((MinMaxCurve)(ref curve)).constant = ((MinMaxCurve)(ref curve)).constant * scale;
				break;
			case 3:
				((MinMaxCurve)(ref curve)).constantMin = ((MinMaxCurve)(ref curve)).constantMin * scale;
				((MinMaxCurve)(ref curve)).constantMax = ((MinMaxCurve)(ref curve)).constantMax * scale;
				break;
			case 1:
			case 2:
				((MinMaxCurve)(ref curve)).curveMultiplier = ((MinMaxCurve)(ref curve)).curveMultiplier * scale;
				break;
			}
			return curve;
		}

		private static int GetAttackMask()
		{
			if (_attackMask == 0)
			{
				_attackMask = LayerMask.GetMask(new string[11]
				{
					"Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "character", "character_net", "character_ghost", "hitbox", "character_noenv",
					"vehicle"
				});
			}
			return _attackMask;
		}

		private static int GetAttackMaskTerrain()
		{
			if (_attackMaskTerrain == 0)
			{
				_attackMaskTerrain = LayerMask.GetMask(new string[12]
				{
					"Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "character", "character_net", "character_ghost", "hitbox",
					"character_noenv", "vehicle"
				});
			}
			return _attackMaskTerrain;
		}

		private static int GetAttackMaskCharacters()
		{
			if (_attackMaskCharacters == 0)
			{
				_attackMaskCharacters = LayerMask.GetMask(new string[6] { "character", "character_net", "character_ghost", "hitbox", "character_noenv", "vehicle" });
			}
			return _attackMaskCharacters;
		}
	}
	internal static class BackstabSkillGainSystem
	{
		internal readonly struct BackstabDamageState
		{
			internal static BackstabDamageState Inactive => new BackstabDamageState(active: false, 0f);

			internal bool Active { get; }

			internal float PreviousBackstabTime { get; }

			internal BackstabDamageState(bool active, float previousBackstabTime)
			{
				Active = active;
				PreviousBackstabTime = previousBackstabTime;
			}
		}

		internal const string GrantSneakSkillRpcName = "SecondaryAttacks_GrantBackstabSneakSkill";

		internal const float BackstabCooldownSeconds = 300f;

		private const float BackstabTimeDetectionWindow = 1f;

		private static readonly FieldRef<Character, float>? BackstabTimeField = TryCreateBackstabTimeFieldRef();

		internal static BackstabDamageState CaptureBackstabState(Character target, HitData hit)
		{
			if ((Object)(object)target == (Object)null || hit == null || hit.m_backstabBonus <= 1f)
			{
				return BackstabDamageState.Inactive;
			}
			return new BackstabDamageState(active: true, GetBackstabTime(target));
		}

		internal static void TryGrantForBackstab(Character target, HitData hit, BackstabDamageState state)
		{
			if (!state.Active || (Object)(object)target == (Object)null || hit == null)
			{
				return;
			}
			float raiseAmount = GetRaiseAmount();
			if (!(raiseAmount <= 0f) && DidBackstabSucceed(target, state.PreviousBackstabTime))
			{
				Character attacker = hit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if (val != null)
				{
					GrantToPlayer(val, raiseAmount);
				}
			}
		}

		internal static void GrantLocal(Player player, float amount)
		{
			if (!((Object)(object)player == (Object)null) && !(amount <= 0f))
			{
				float num = Mathf.Min(Mathf.Max(0f, amount), GetRaiseAmount());
				if (!(num <= 0f))
				{
					((Character)player).RaiseSkill((SkillType)101, num);
				}
			}
		}

		private static float GetRaiseAmount()
		{
			return Mathf.Max(0f, SecondaryAttacksPlugin.BackstabSneakSkillRaiseAmount?.Value ?? 0f);
		}

		private static bool DidBackstabSucceed(Character target, float previousBackstabTime)
		{
			float backstabTime = GetBackstabTime(target);
			if (backstabTime > previousBackstabTime + 0.001f && backstabTime >= Time.time - 1f)
			{
				return backstabTime <= Time.time + 0.001f;
			}
			return false;
		}

		private static void GrantToPlayer(Player player, float amount)
		{
			//IL_0001: 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_0015: Expected O, but got Unknown
			//IL_0015: Expected O, but got Unknown
			ZNetView nview;
			ZDO zdo;
			if ((Object)player == (Object)Player.m_localPlayer)
			{
				GrantLocal(player, amount);
			}
			else if (SecondaryAttackManager.TryGetCharacterZdo((Character?)(object)player, out nview, out zdo))
			{
				nview.InvokeRPC("SecondaryAttacks_GrantBackstabSneakSkill", new object[1] { amount });
			}
		}

		internal static float GetBackstabTime(Character target)
		{
			if ((Object)(object)target == (Object)null || BackstabTimeField == null)
			{
				return 0f;
			}
			return BackstabTimeField.Invoke(target);
		}

		private static FieldRef<Character, float>? TryCreateBackstabTimeFieldRef()
		{
			try
			{
				return AccessTools.FieldRefAccess<Character, float>("m_backstabTime");
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
	internal static class BloodMagicSkillGainSystem
	{
		private static bool _allowConfiguredBloodMagicRaise;

		private static float GetHealthCostSkillRaiseFactor()
		{
			return Mathf.Max(0f, SecondaryAttacksPlugin.BloodMagicHealthCostSkillRaiseFactor?.Value ?? 0f);
		}

		internal static bool IsHealthCostSkillGainEnabled()
		{
			return GetHealthCostSkillRaiseFactor() > 0f;
		}

		internal static bool ShouldUseMaxHealthForPercentageCost()
		{
			ConfigEntry<SecondaryAttacksPlugin.Toggle> bloodMagicHealthCostUsesMaxHealth = SecondaryAttacksPlugin.BloodMagicHealthCostUsesMaxHealth;
			if (bloodMagicHealthCostUsesMaxHealth == null)
			{
				return false;
			}
			return bloodMagicHealthCostUsesMaxHealth.Value == SecondaryAttacksPlugin.Toggle.On;
		}

		internal static void ApplyMaxHealthPercentageCost(Attack attack, ref float healthCost)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			if (!ShouldUseMaxHealthForPercentageCost() || attack == null || (Object)(object)attack.m_character == (Object)null)
			{
				return;
			}
			ItemData weapon = attack.m_weapon;
			if (weapon != null && (int)weapon.m_shared.m_skillType == 10 && !(attack.m_attackHealthPercentage <= 0f))
			{
				float num = Mathf.Max(0f, attack.m_attackHealth) + Mathf.Max(0f, ((Character)attack.m_character).GetMaxHealth()) * Mathf.Max(0f, attack.m_attackHealthPercentage) / 100f;
				if (num <= 0f)
				{
					healthCost = 0f;
					return;
				}
				float num2 = Mathf.Clamp01(((Character)attack.m_character).GetSkillFactor((SkillType)10));
				healthCost = num - num * 0.33f * num2;
			}
		}

		internal static bool ShouldBlockBloodMagicRaise(SkillType skillType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)skillType == 10 && IsHealthCostSkillGainEnabled())
			{
				return !_allowConfiguredBloodMagicRaise;
			}
			return false;
		}

		internal static void TryGrantForHealthUse(Character character, float previousHealth)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			if (!IsHealthCostSkillGainEnabled())
			{
				return;
			}
			Player val = (Player)(object)((character is Player) ? character : null);
			if (val == null)
			{
				return;
			}
			Humanoid val2 = (Humanoid)(object)((character is Humanoid) ? character : null);
			if (val2 == null)
			{
				return;
			}
			float num = previousHealth - character.GetHealth();
			if (num <= 0.001f)
			{
				return;
			}
			Attack currentAttack = val2.m_currentAttack;
			if (currentAttack == null || (Object)(object)currentAttack.m_character != (Object)(object)val2)
			{
				return;
			}
			ItemData weapon = currentAttack.m_weapon;
			if (weapon == null || (int)weapon.m_shared.m_skillType != 10)
			{
				return;
			}
			float healthCostSkillRaiseFactor = GetHealthCostSkillRaiseFactor();
			float num2 = num * healthCostSkillRaiseFactor;
			if (num2 <= 0f)
			{
				return;
			}
			_allowConfiguredBloodMagicRaise = true;
			try
			{
				((Character)val).RaiseSkill((SkillType)10, num2);
			}
			finally
			{
				_allowConfiguredBloodMagicRaise = false;
			}
		}
	}
	internal static class BowSecondaryKeyHintSystem
	{
		private const int MissingBlockHintRefreshFrames = 30;

		private static readonly string[] BowSecondaryHintKeys = new string[1];

		private static readonly string[] DetonateBlockHintKeys = new string[1];

		private static KeyHints? _activeKeyHints;

		private static KeyHintCell? _bowSecondaryHint;

		private static KeyHintCell? _detonateBlockHint;

		private static GameObject? _bowSecondaryHintTemplate;

		private static KeyHints? _cachedTemplateHints;

		private static GameObject? _cachedCombatHintTemplate;

		private static KeyHints? _cachedBlockHintHints;

		private static GameObject? _cachedBlockHint;

		private static bool _showingBowSecondaryHint;

		private static bool _showingDetonateBlockHint;

		private static bool _cachedTemplateGamepadActive;

		private static bool _cachedBlockHintGamepadActive;

		private static bool _cachedBlockHintResolved;

		private static bool _lastGamepadActive;

		private static bool _lastDetonateBlockGamepadActive;

		private static bool _keyHintApplied;

		private static bool _detonateBlockHintApplied;

		private static int _cachedBlockHintFrame;

		private static string _lastButtonLabel = string.Empty;

		private static string _lastDetonateBlockButtonLabel = string.Empty;

		internal static void InitializeKeyHints(KeyHints hints)
		{
			_activeKeyHints = hints;
			DestroyBowSecondaryHint();
			RestoreDetonateBlockHint();
			_detonateBlockHint = null;
			ClearBlockHintCache();
			_showingBowSecondaryHint = false;
			UpdateKeyHint(hints);
		}

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

		internal static void UpdateKeyHint(KeyHints hints)
		{
			if ((Object)(object)hints == (Object)null)
			{
				return;
			}
			_activeKeyHints = hints;
			if (!ShouldAllowCustomCombatHints(hints))
			{
				HideBowSecondaryHint();
				RestoreDetonateBlockHint();
				if ((Object)(object)hints.m_combatHints != (Object)null)
				{
					hints.m_combatHints.SetActive(false);
				}
				return;
			}
			UpdateDetonateBlockHint(hints);
			if (!ShouldShowBowSecondaryHint())
			{
				HideBowSecondaryHint();
				return;
			}
			bool flag = ZInput.IsGamepadActive();
			EnsureBowSecondaryHint(hints, flag);
			KeyHintCell? bowSecondaryHint = _bowSecondaryHint;
			if (bowSecondaryHint != null && bowSecondaryHint.IsValid)
			{
				if ((Object)(object)hints.m_combatHints != (Object)null)
				{
					hints.m_combatHints.SetActive(true);
				}
				SetVanillaCombatHintActive(hints.m_secondaryAttackGP, active: false);
				SetVanillaCombatHintActive(hints.m_secondaryAttackKB, active: false);
				bool flag2 = !_showingBowSecondaryHint;
				string text = ResolveSecondaryAttackButtonLabel(flag);
				if (!_keyHintApplied || _lastGamepadActive != flag || !string.Equals(_lastButtonLabel, text, StringComparison.Ordinal))
				{
					BowSecondaryHintKeys[0] = text;
					_bowSecondaryHint.SetKeys(BowSecondaryHintKeys, hideExtraTexts: true);
					_lastButtonLabel = text;
					_lastGamepadActive = flag;
					_keyHintApplied = true;
					flag2 = true;
				}
				if ((Object)(object)_bowSecondaryHint.Root != (Object)null && _bowSecondaryHint.Root.transform.GetSiblingIndex() != 0)
				{
					_bowSecondaryHint.MoveToStart();
					flag2 = true;
				}
				if (flag2)
				{
					_bowSecondaryHint.RebuildParentLayout();
				}
				_showingBowSecondaryHint = true;
			}
		}

		private static void UpdateDetonateBlockHint(KeyHints hints)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!ShouldShowCombatHints(localPlayer) || !StickyDetonatorSystem.ShouldShowDetonateBlockHint(localPlayer))
			{
				RestoreDetonateBlockHint();
				return;
			}
			bool flag = ZInput.IsGamepadActive();
			GameObject val = ResolveCachedBlockHint(hints, flag);
			if ((Object)(object)val == (Object)null)
			{
				RestoreDetonateBlockHint();
				return;
			}
			if (_detonateBlockHint == null || (Object)(object)_detonateBlockHint.Root != (Object)(object)val)
			{
				RestoreDetonateBlockHint();
				_detonateBlockHint = KeyHintCell.FromGameObject(val);
				_detonateBlockHintApplied = false;
			}
			KeyHintCell? detonateBlockHint = _detonateBlockHint;
			if (detonateBlockHint != null && detonateBlockHint.IsValid)
			{
				if ((Object)(object)hints.m_combatHints != (Object)null)
				{
					hints.m_combatHints.SetActive(true);
				}
				string text = ResolveBlockButtonLabel(flag);
				if (!_detonateBlockHintApplied || _lastDetonateBlockGamepadActive != flag || !string.Equals(_lastDetonateBlockButtonLabel, text, StringComparison.Ordinal))
				{
					ApplyDetonateBlockHint(_detonateBlockHint, text);
					_lastDetonateBlockButtonLabel = text;
					_lastDetonateBlockGamepadActive = flag;
					_detonateBlockHintApplied = true;
					_detonateBlockHint.RebuildParentLayout();
				}
				_showingDetonateBlockHint = true;
			}
		}

		private static bool ShouldShowBowSecondaryHint()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			Player localPlayer = Player.m_localPlayer;
			if (!ShouldShowCombatHints(localPlayer))
			{
				return false;
			}
			ItemData val = ResolveEquippedBow(localPlayer);
			if (val?.m_shared == null)
			{
				return false;
			}
			if ((int)val.m_shared.m_itemType != 4)
			{
				return false;
			}
			if (!val.m_shared.m_attack.m_bowDraw)
			{
				return false;
			}
			return HasVisibleSecondaryAttack(val);
		}

		private static bool HasVisibleSecondaryAttack(ItemData weapon)
		{
			if (weapon == null)
			{
				return false;
			}
			if (!SecondaryAttackRuntimeFacade.TryGetDefinition(weapon, out SecondaryAttackDefinition definition))
			{
				return false;
			}
			if (definition.BehaviorType != SecondaryAttackBehaviorType.Projectile)
			{
				return false;
			}
			return true;
		}

		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 SetVanillaCombatHintActive(GameObject? hint, bool active)
		{
			if ((Object)(object)hint != (Object)null && hint.activeSelf != active)
			{
				hint.SetActive(active);
			}
		}

		private static void EnsureBowSecondaryHint(KeyHints hints, bool gamepadActive)
		{
			if (_bowSecondaryHint != null && (Object)(object)_bowSecondaryHint.Root != (Object)null && (Object)(object)_bowSecondaryHintTemplate != (Object)null && (Object)(object)_bowSecondaryHintTemplate.transform.parent != (Object)null && (Object)(object)_cachedTemplateHints == (Object)(object)hints && _cachedTemplateGamepadActive == gamepadActive && (Object)(object)_bowSecondaryHint.Root.transform.parent == (Object)(object)_bowSecondaryHintTemplate.transform.parent)
			{
				return;
			}
			GameObject val = ResolveCachedCombatHintTemplate(hints, gamepadActive);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.transform.parent == (Object)null))
			{
				if (_bowSecondaryHint != null && (Object)(object)_bowSecondaryHint.Root != (Object)null && (Object)(object)_bowSecondaryHint.Root.transform.parent == (Object)(object)val.transform.parent)
				{
					_bowSecondaryHintTemplate = val;
					return;
				}
				DestroyBowSecondaryHint();
				_bowSecondaryHint = KeyHintCell.CloneFrom(val, "SecondaryAttacks_BowSecondaryHint", hideOnRestore: true);
				_bowSecondaryHintTemplate = val;
				_cachedTemplateHints = hints;
				_cachedTemplateGamepadActive = gamepadActive;
				_cachedCombatHintTemplate = val;
				_keyHintApplied = false;
			}
		}

		private static GameObject? ResolveCachedCombatHintTemplate(KeyHints hints, bool gamepadActive)
		{
			if ((Object)(object)_cachedTemplateHints == (Object)(object)hints && _cachedTemplateGamepadActive == gamepadActive && (Object)(object)_cachedCombatHintTemplate != (Object)null && (Object)(object)_cachedCombatHintTemplate.transform.parent != (Object)null)
			{
				return _cachedCombatHintTemplate;
			}
			_cachedTemplateHints = hints;
			_cachedTemplateGamepadActive = gamepadActive;
			_cachedCombatHintTemplate = ResolveCombatHintTemplate(hints, gamepadActive);
			return _cachedCombatHintTemplate;
		}

		private static string ResolveSecondaryAttackButtonLabel(bool gamepadActive)
		{
			string text = (gamepadActive ? "JoySecondaryAttack" : "SecondaryAttack");
			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 (!gamepadActive)
			{
				return "MMB";
			}
			return "RB";
		}

		private static string ResolveBlockButtonLabel(bool gamepadActive)
		{
			string text = (gamepadActive ? "JoyBlock" : "Block");
			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 (!gamepadActive)
			{
				return "Mouse-2";
			}
			return "LT";
		}

		private static void ApplyDetonateBlockHint(KeyHintCell hint, string buttonLabel)
		{
			string text = SecondaryAttackLocalization.Localize("$sa_hint_detonate", "Detonate");
			if (hint.HasKeyTexts)
			{
				DetonateBlockHintKeys[0] = buttonLabel;
				hint.Set(text, DetonateBlockHintKeys, 0f, hideExtraTexts: true);
			}
			else
			{
				hint.SetText(text + " <mspace=0.6em>" + buttonLabel + "</mspace>");
			}
		}

		private static GameObject? ResolveCachedBlockHint(KeyHints hints, bool gamepadActive)
		{
			if (_cachedBlockHintResolved && (Object)(object)_cachedBlockHintHints == (Object)(object)hints && _cachedBlockHintGamepadActive == gamepadActive)
			{
				if ((Object)(object)_cachedBlockHint != (Object)null && (Object)(object)_cachedBlockHint.transform.parent != (Object)null)
				{
					return _cachedBlockHint;
				}
				if ((Object)(object)_cachedBlockHint == (Object)null && Time.frameCount - _cachedBlockHintFrame < 30)
				{
					return null;
				}
			}
			_cachedBlockHintHints = hints;
			_cachedBlockHintGamepadActive = gamepadActive;
			_cachedBlockHint = ResolveBlockHintUncached(hints, gamepadActive);
			_cachedBlockHintResolved = true;
			_cachedBlockHintFrame = Time.frameCount;
			return _cachedBlockHint;
		}

		private static GameObject? ResolveBlockHintUncached(KeyHints hints, bool gamepadActive)
		{
			GameObject val = FindBlockHint(ResolveCombatInputGroup(hints, gamepadActive));
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			return FindBlockHint(ResolveCombatInputGroup(hints, !gamepadActive));
		}

		private static void ClearBlockHintCache()
		{
			_cachedBlockHintHints = null;
			_cachedBlockHint = null;
			_cachedBlockHintResolved = false;
			_cachedBlockHintFrame = 0;
		}

		private static Transform? ResolveCombatInputGroup(KeyHints hints, bool gamepadActive)
		{
			GameObject val = (gamepadActive ? hints.m_primaryAttackGP : hints.m_primaryAttackKB);
			if ((Object)(object)((val != null) ? val.transform.parent : null) != (Object)null)
			{
				return val.transform.parent;
			}
			val = (gamepadActive ? hints.m_secondaryAttackGP : hints.m_secondaryAttackKB);
			if (val == null)
			{
				return null;
			}
			return val.transform.parent;
		}

		private static GameObject? FindBlockHint(Transform? group)
		{
			if ((Object)(object)group == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < group.childCount; i++)
			{
				GameObject gameObject = ((Component)group.GetChild(i)).gameObject;
				if ((string.Equals(((Object)gameObject).name, "Block", StringComparison.OrdinalIgnoreCase) || string.Equals(((Object)gameObject).name, "Text - Block", StringComparison.OrdinalIgnoreCase)) && KeyHintCell.IsUsableTemplate(gameObject))
				{
					return gameObject;
				}
			}
			TMP_Text[] componentsInChildren = ((Component)group).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || !ContainsBlockHintText(val.text))
				{
					continue;
				}
				Transform val2 = val.transform;
				while ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)group.parent)
				{
					GameObject gameObject2 = ((Component)val2).gameObject;
					if (KeyHintCell.IsUsableTemplate(gameObject2))
					{
						return gameObject2;
					}
					val2 = val2.parent;
				}
			}
			return null;
		}

		private static bool ContainsBlockHintText(string? value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			if (value.IndexOf("$settings_block", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return value.IndexOf("Block", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static ItemData? ResolveEquippedBow(Player? player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			if (IsBowDrawWeapon(currentWeapon))
			{
				return currentWeapon;
			}
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (IsBowDrawWeapon(rightItem))
			{
				return rightItem;
			}
			ItemData leftItem = ((Humanoid)player).GetLeftItem();
			if (!IsBowDrawWeapon(leftItem))
			{
				return null;
			}
			return leftItem;
		}

		private static bool IsBowDrawWeapon(ItemData? weapon)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (weapon?.m_shared != null && (int)weapon.m_shared.m_itemType == 4)
			{
				return weapon.m_shared.m_attack.m_bowDraw;
			}
			return false;
		}

		private static GameObject? ResolveCombatHintTemplate(KeyHints hints, bool gamepadActive)
		{
			GameObject val = (gamepadActive ? hints.m_secondaryAttackGP : hints.m_secondaryAttackKB);
			if (KeyHintCell.IsUsableTemplate(val))
			{
				return val;
			}
			GameObject val2 = (gamepadActive ? hints.m_secondaryAttackKB : hints.m_secondaryAttackGP);
			if (KeyHintCell.IsUsableTemplate(val2))
			{
				return val2;
			}
			GameObject val3 = (gamepadActive ? hints.m_bowDrawGP : hints.m_bowDrawKB);
			if (KeyHintCell.IsUsableTemplate(val3))
			{
				return val3;
			}
			GameObject val4 = (gamepadActive ? hints.m_bowDrawKB : hints.m_bowDrawGP);
			if (KeyHintCell.IsUsableTemplate(val4))
			{
				return val4;
			}
			GameObject val5 = (gamepadActive ? hints.m_primaryAttackGP : hints.m_primaryAttackKB);
			if (KeyHintCell.IsUsableTemplate(val5))
			{
				return val5;
			}
			GameObject val6 = (gamepadActive ? hints.m_primaryAttackKB : hints.m_primaryAttackGP);
			if (KeyHintCell.IsUsableTemplate(val6))
			{
				return val6;
			}
			return null;
		}

		private static void HideBowSecondaryHint()
		{
			if (_showingBowSecondaryHint)
			{
				_bowSecondaryHint?.Restore();
				_bowSecondaryHint?.RebuildParentLayout();
				_showingBowSecondaryHint = false;
				_keyHintApplied = false;
				_lastButtonLabel = string.Empty;
			}
		}

		private static void RestoreDetonateBlockHint()
		{
			if (_showingDetonateBlockHint || _detonateBlockHintApplied)
			{
				_detonateBlockHint?.Restore();
				_detonateBlockHint?.RebuildParentLayout();
				_showingDetonateBlockHint = false;
				_detonateBlockHintApplied = false;
				_lastDetonateBlockButtonLabel = string.Empty;
			}
		}

		private static void DestroyBowSecondaryHint()
		{
			if ((Object)(object)_bowSecondaryHint?.Root != (Object)null)
			{
				Object.Destroy((Object)(object)_bowSecondaryHint.Root);
			}
			_bowSecondaryHint = null;
			_bowSecondaryHintTemplate = null;
			_cachedTemplateHints = null;
			_cachedCombatHintTemplate = null;
			_keyHintApplied = false;
			_lastButtonLabel = string.Empty;
		}
	}
	[HarmonyPatch(typeof(KeyHints), "Awake")]
	internal static class KeyHintsAwakeBowSecondaryPatch
	{
		private static void Postfix(KeyHints __instance)
		{
			BowSecondaryKeyHintSystem.InitializeKeyHints(__instance);
		}
	}
	[HarmonyPatch(typeof(KeyHints), "UpdateHints")]
	internal static class KeyHintsUpdateBowSecondaryPatch
	{
		private static void Postfix(KeyHints __instance)
		{
			BowSecondaryKeyHintSystem.UpdateKeyHint(__instance);
		}
	}
	internal static class CopiedThrowProjectileVisualSystem
	{
		internal readonly struct BurstScope
		{
			public Attack? Attack { get; }

			public bool Active => Attack != null;

			public BurstScope(Attack attack)
			{
				Attack = attack;
			}
		}

		internal readonly struct SpawnedProjectileVisualContext
		{
			public ItemData? Weapon { get; }

			public string VisualPrefabName { get; }

			public GameObject? AttachPrefab { get; }

			public EffectData[]? HitEffectPrefabs { get; }

			public ThrowProjectileVisualSpin.AxisMode SpinAxisMode { get; }

			public Vector3 VisualRotationOffset { get; }

			public bool SkipVisualSwap { get; }

			public bool Active
			{
				get
				{
					if ((Object)(object)Weapon?.m_dropPrefab != (Object)null)
					{
						return !string.IsNullOrEmpty(VisualPrefabName);
					}
					return false;
				}
			}

			public SpawnedProjectileVisualContext(ItemData weapon, string visualPrefabName, GameObject? attachPrefab, EffectData[]? hitEffectPrefabs, ThrowProjectileVisualSpin.AxisMode spinAxisMode, Vector3 visualRotationOffset, bool skipVisualSwap)
			{
				//IL_0026: 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)
				Weapon = weapon;
				VisualPrefabName = visualPrefabName;
				AttachPrefab = attachPrefab;
				HitEffectPrefabs = hitEffectPrefabs;
				SpinAxisMode = spinAxisMode;
				VisualRotationOffset = visualRotationOffset;
				SkipVisualSwap = skipVisualSwap;
			}
		}

		private sealed class CopiedThrowSpinState : MonoBehaviour
		{
			private ThrowProjectileVisualSpin.AxisMode _axisMode;

			private Vector3 _rotationOffset;

			private Vector3 _horizontalForward;

			private bool _configured;

			internal bool IsCurrent(ThrowProjectileVisualSpin.AxisMode axisMode, Vector3 rotationOffset, Vector3 horizontalForward)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				if (_configured && _axisMode == axisMode)
				{
					Vector3 val = _rotationOffset - rotationOffset;
					if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
					{
						val = _horizontalForward - horizontalForward;
						if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
						{
							return ThrowProjectileVisualSpin.IsConfigured(((Component)this).gameObject, axisMode, horizontalForward);
						}
					}
				}
				return false;
			}

			internal void Configure(ThrowProjectileVisualSpin.AxisMode axisMode, Vector3 rotationOffset, Vector3 horizontalForward)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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_0010: Unknown result type (might be due to invalid IL or missing references)
				_axisMode = axisMode;
				_rotationOffset = rotationOffset;
				_horizontalForward = horizontalForward;
				_configured = true;
			}
		}

		private const string CopiedThrowProjectileMarkerKey = "SecondaryAttacks_CopiedThrowProjectile";

		private const string CopiedThrowProjectileSpinAxisKey = "SecondaryAttacks_CopiedThrowSpinAxis";

		private const string CopiedThrowProjectileRotationOffsetKey = "SecondaryAttacks_CopiedThrowRotationOffset";

		private const string CopiedThrowProjectileVisualRootName = "SecondaryAttacks_CopiedThrowVisualRoot";

		private const string CopiedThrowProjectileSpinRootName = "SecondaryAttacks_CopiedThrowSpinRoot";

		private const float SpinStateEpsilonSqr = 0.0001f;

		private static readonly List<Attack> ActiveCopiedThrowBursts = new List<Attack>();

		private static readonly List<Renderer> RendererBuffer = new List<Renderer>();

		internal static BurstScope BeginBurst(Attack attack)
		{
			if (!ShouldApplyCopiedThrowVisuals(attack))
			{
				return default(BurstScope);
			}
			ActiveCopiedThrowBursts.Add(attack);
			return new BurstScope(attack);
		}

		internal static void EndBurst(BurstScope scope)
		{
			if (scope.Active)
			{
				int num = ActiveCopiedThrowBursts.Count - 1;
				if (num >= 0 && ActiveCopiedThrowBursts[num] == scope.Attack)
				{
					ActiveCopiedThrowBursts.RemoveAt(num);
				}
				else
				{
					ActiveCopiedThrowBursts.Remove(scope.Attack);
				}
			}
		}

		internal static void TryApplyToProjectileSetup(Projectile projectile, ItemData item)
		{
			MeleeProjectileHitCascadeSystem.TryDescribeSpearRainFollowupProjectile(projectile, out string _);
			if ((Object)(object)projectile == (Object)null || ActiveCopiedThrowBursts.Count == 0)
			{
				return;
			}
			Attack val = ActiveCopiedThrowBursts[ActiveCopiedThrowBursts.Count - 1];
			if (val == null)
			{
				return;
			}
			ItemData val2 = val.m_weapon ?? item;
			if (!((Object)(object)val2?.m_dropPrefab == (Object)null))
			{
				MoveProjectileClearOfOwner(projectile, val);
				SecondaryAttackDefinition definition = ResolveCopiedThrowDefinition(val, val2, ((Object)val2.m_dropPrefab).name);
				SpawnedProjectileVisualContext context = CreateSpawnedProjectileVisualContext(val2, val.m_attackProjectile, definition, includeHitEffects: false);
				ApplyCurrentWeaponVisual(projectile, context);
				ApplyCurrentWeaponHitEffects(projectile, val2);
				ApplyCopiedThrowAttribution(projectile, val2);
				if (!SecondaryAttackStartAttackDispatch.ShouldSkipProjectilePresetEffectsForCooldown(val, out string _))
				{
					MeleeBoomerangProjectileSystem.TryApplyToProjectileSetup(projectile, val, val2);
					MeleeProjectileHitCascadeSystem.RegisterOnProjectileHitSource(projectile, val, val2);
				}
			}
		}

		internal static void PrepareProjectileIfNeeded(Projectile projectile)
		{
			if ((Object)(object)projectile == (Object)null)
			{
				return;
			}
			ZNetView component = ((Component)projectile).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO() != null && component.GetZDO().GetBool("SecondaryAttacks_CopiedThrowProjectile", false))
			{
				TryApplyHitEffectsFromSyncedVisual(projectile, component);
				if (!projectile.m_changedVisual)
				{
					PrepareProjectileForVisualSwap(projectile);
				}
			}
		}

		internal static void EnsureProjectileVisualSpinIfNeeded(Projectile projectile)
		{
			if (IsMarkedCopiedThrowProjectile(projectile))
			{
				string visualPrefabName = TryResolveSyncedVisualPrefabName(projectile);
				ApplyCopiedThrowVisualSpin(projectile, TryResolveSyncedVisualItem(visualPrefabName)?.m_itemData, visualPrefabName);
			}
		}

		internal static void ApplyCurrentWeaponVisualForSpawnedProjectile(Projectile projectile, ItemData weapon)
		{
			ApplyCurrentWeaponVisualForSpawnedProjectile(projectile, CreateSpawnedProjectileVisualContext(weapon));
		}

		internal static void ApplyCurrentWeaponVisualForSpawnedProjectile(Projectile projectile, SpawnedProjectileVisualContext context)
		{
			if (!((Object)(object)projectile == (Object)null) && context.Active)
			{
				if (!context.SkipVisualSwap)
				{
					ApplyCurrentWeaponVisual(projectile, context);
				}
				ApplyHitEffects(projectile, context.HitEffectPrefabs);
			}
		}

		internal static SpawnedProjectileVisualContext CreateSpawnedProjectileVisualContext(ItemData weapon)
		{
			return CreateSpawnedProjectileVisualContext(weapon, includeHitEffects: true);
		}

		internal static SpawnedProjectileVisualContext CreateSpawnedProjectileVisualContext(ItemData weapon, GameObject? sourceProjectilePrefab)
		{
			return CreateSpawnedProjectileVisualContext(weapon, sourceProjectilePrefab, includeHitEffects: true);
		}

		private static SpawnedProjectileVisualContext CreateSpawnedProjectileVisualContext(ItemData weapon, bool includeHitEffects)
		{
			return CreateSpawnedProjectileVisualContext(weapon, null, includeHitEffects);
		}

		private static SpawnedProjectileVisualContext CreateSpawnedProjectileVisualContext(ItemData weapon, GameObject? sourceProjectilePrefab, bool includeHitEffects)
		{
			return CreateSpawnedProjectileVisualContext(weapon, sourceProjectilePrefab, null, includeHitEffects);
		}

		private static SpawnedProjectileVisualContext CreateSpawnedProjectileVisualContext(ItemData weapon, GameObject? sourceProjectilePrefab, SecondaryAttackDefinition? definition, bool includeHitEffects)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)weapon?.m_dropPrefab == (Object)null)
			{
				return default(SpawnedProjectileVisualContext);
			}
			bool flag = UsesNativeProjectileVisual(weapon, sourceProjectilePrefab);
			GameObject attachPrefab = null;
			if (!flag)
			{
				attachPrefab = ResolveAttachGameObject(weapon.m_dropPrefab);
			}
			if (definition == null)
			{
				definition = ResolveCopiedThrowDefinition(weapon, ((Object)weapon.m_dropPrefab).name);
			}
			ThrowProjectileVisualSpin.AxisMode valueOrDefault = ResolveConfiguredCopiedThrowSpinAxisMode(definition).GetValueOrDefault();
			return new SpawnedProjectileVisualContext(weapon, ((Object)weapon.m_dropPrefab).name, attachPrefab, includeHitEffects ? CopyHitEffectPrefabs(weapon.m_shared?.m_hitEffect) : null, valueOrDefault, ResolveConfiguredCopiedThrowVisualRotationOffset(definition), flag);
		}

		internal static bool UsesNativeProjectileVisual(ItemData weapon, GameObject? sourceProjectilePrefab)
		{
			if ((Object)(object)weapon?.m_dropPrefab == (Object)null || (Object)(object)sourceProjectilePrefab == (Object)null)
			{
				return false;
			}
			return IsSameProjectilePrefab(sourceProjectilePrefab, weapon.m_shared?.m_secondaryAttack?.m_attackProjectile);
		}

		private static bool IsSameProjectilePrefab(GameObject sourceProjectilePrefab, GameObject? weaponProjectilePrefab)
		{
			if ((Object)(object)weaponProjectilePrefab != (Object)null)
			{
				if (sourceProjectilePrefab != weaponProjectilePrefab)
				{
					return string.Equals(((Object)sourceProjectilePrefab).name, ((Object)weaponProjectilePrefab).name, StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
			return false;
		}

		private static GameObject? ResolveAttachGameObject(GameObject itemPrefab)
		{
			Transform val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.transform.Find("attach") : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Transform val2 = val.Find("attachobj");
			if (!((Object)(object)val2 != (Object)null))
			{
				return ((Component)val).gameObject;
			}
			return ((Component)val2).gameObject;
		}

		private static bool ShouldApplyCopiedThrowVisuals(Attack attack)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			if ((Object)(object)attack?.m_weapon?.m_dropPrefab == (Object)null || (Object)(object)attack.m_attackProjectile == (Object)null || (int)attack.m_attackType != 2)
			{
				return false;
			}
			if (SecondaryAttackStartAttackDispatch.IsProjectilePresetOriginalCooldownFallback(attack, out string _))
			{
				return false;
			}
			if (SecondaryAttackRuntimeContext.TryGetActiveAttack(attack, out ActiveSecondaryAttack activeAttack) && activeAttack?.Definition.Behavior is CopiedSecondaryBehavior)
			{
				return true;
			}
			if (!IsConfiguredCopiedSecondaryAttack(attack))
			{
				return false;
			}
			return true;
		}

		private static bool IsConfiguredCopiedSecondaryAttack(Attack attack)
		{
			if (!SecondaryAttackRuntimeFacade.TryGetDefinition(attack.m_weapon, out SecondaryAttackDefinition definition) || !(definition.Behavior is CopiedSecondaryBehavior))
			{
				return false;
			}
			Humanoid character = attack.m_character;
			if (character != null && character.m_currentAttack == attack)
			{
				return character.m_currentAttackIsSecondary;
			}
			return attack == attack.m_weapon.m_shared.m_secondaryAttack;
		}

		private static void MoveProjectileClearOfOwner(Projectile projectile, Attack attack)
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			Character val = (Character)(((object)ProjectileAccess.GetOwner(projectile)) ?? ((object)attack.m_character));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Vector3 velocity = ProjectileAccess.GetVelocity(projectile);
			Vector3 val2 = ((((Vector3)(ref velocity)).sqrMagnitude > 0.001f) ? ((Vector3)(ref velocity)).normalized : ((Component)projectile).transform.forward);
			if (!(((Vector3)(ref val2)).sqrMagnitude < 0.001f))
			{
				Vector3 centerPoint = val.GetCenterPoint();
				float num = Mathf.Max(val.GetRadius() + Mathf.Max(0.1f, projectile.m_rayRadius) + 0.35f, 1.25f);
				Vector3 position = ((Component)projectile).transform.position;
				float num2 = Vector3.Dot(position - centerPoint, val2);
				if (!(num2 >= num))
				{
					Vector3 position2 = position + val2 * (num - num2);
					((Component)projectile).transform.position = position2;
				}
			}
		}

		private static void ApplyCopiedThrowAttribution(Projectile projectile, ItemData weapon)
		{
			if (SecondaryAttackRuntimeFacade.TryGetDefinition(weapon, out SecondaryAttackDefinition definition) && definition.Behavior is CopiedSecondaryBehavior)
			{
				SecondaryAttackRuntimeFacade.SetProjectileAttackAttribution(projectile, definition.PrefabName, secondaryAttack: true, definition, disableCurrentAttackFallback: false);
				SecondaryAttackProjectileToolTierSystem.ApplyToHitData(ProjectileAccess.GetOriginalHitData(projectile), projectile, weapon, "CopiedThrowProjectileVisualSystem.Setup");
			}
		}

		private static void ApplyCurrentWeaponVisual(Projectile projectile, ItemData weapon)
		{
			ApplyCurrentWeaponVisual(projectile, CreateSpawnedProjectileVisualContext(weapon, includeHitEffects: false));
		}

		private static void ApplyCurrentWeaponVisual(Projectile projectile, SpawnedProjectileVisualContext context)
		{
			if (!context.Active || context.SkipVisualSwap)
			{
				return;
			}
			SecondaryAttackPerformanceLog.Start();
			try
			{
				SecondaryAttackPerformanceLog.Start();
				PrepareProjectileForVisualSwap(projectile);
				SecondaryAttackPerformanceLog.Start();
				MarkCopiedThrowProjectile(projectile, context);
				SecondaryAttackPerformanceLog.Start();
				ZNetView component = ((Component)projectile).GetComponent<ZNetView>();
				bool flag = (Object)(object)component != (Object)null && component.IsValid();
				if (projectile.m_canChangeVisuals && (Object)(object)projectile.m_visual != (Object)null && flag)
				{
					if (component.IsOwner())
					{
						SecondaryAttackPerformanceLog.Start();
						component.GetZDO().Set(ZDOVars.s_visual, context.VisualPrefabName);
					}
					SecondaryAttackPerformanceLog.Start();
					projectile.UpdateVisual();
					SecondaryAttackPerformanceLog.Start();
					ApplyCopiedThrowVisualSpin(projectile, context);
				}
				else
				{
					SecondaryAttackPerformanceLog.Start();
					ApplyLocalFallbackVisual(projectile, context);
				}
			}
			finally
			{
			}
		}

		private static void ApplyCurrentWeaponHitEffects(Projectile projectile, ItemData weapon)
		{
			ApplyHitEffects(projectile, weapon.m_shared?.m_hitEffect);
		}

		private static void TryApplyHitEffectsFromSyncedVisual(Projectile projectile, ZNetView nview)
		{
			ApplyHitEffects(projectile, TryResolveSyncedVisualItem(nview)?.m_itemData?.m_shared?.m_hitEffect);
		}

		private static void ApplyHitEffects(Projectile projectile, EffectList? hitEffect)
		{
			if (hitEffect != null && hitEffect.HasEffects())
			{
				ApplyHitEffects(projectile, CopyHitEffectPrefabs(hitEffect));
			}
		}

		private static void ApplyHitEffects(Projectile projectile, EffectData[]? hitEffectPrefabs)
		{
			//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_001a: Expected O, but got Unknown
			if (hitEffectPrefabs != null && hitEffectPrefabs.Length != 0)
			{
				projectile.m_hitEffects = new EffectList
				{
					m_effectPrefabs = hitEffectPrefabs
				};
			}
		}

		private static EffectData[]? CopyHitEffectPrefabs(EffectList? hitEffect)
		{
			if (hitEffect?.m_effectPrefabs == null || !hitEffect.HasEffects())
			{
				return null;
			}
			return (EffectData[])hitEffect.m_effectPrefabs.Clone();
		}

		private static void MarkCopiedThrowProjectile(Projectile projectile, SpawnedProjectileVisualContext context)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = ((Component)projectile).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && component.GetZDO() != null)
			{
				ZDO zDO = component.GetZDO();
				zDO.Set("SecondaryAttacks_CopiedThrowProjectile", true);
				zDO.Set("SecondaryAttacks_CopiedThrowSpinAxis", ToProjectileSpinAxisString(context.SpinAxisMode));
				zDO.Set("SecondaryAttacks_CopiedThrowRotationOffset", SerializeVector3(context.VisualRotationOffset));
			}
		}

		private static bool IsMarkedCopiedThrowProjectile(Projectile projectile)
		{
			if ((Object)(object)projectile == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)projectile).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid() && component.GetZDO() != null)
			{
				return component.GetZDO().GetBool("SecondaryAttacks_CopiedThrowProjectile", false);
			}
			return false;
		}

		private static void PrepareProjectileForVisualSwap(Projectile projectile)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			SecondaryAttackPerformanceLog.Start();
			Transform val = ((Component)projectile).transform.Find("SecondaryAttacks_CopiedThrowVisualRoot");
			if ((Object)(object)val != (Object)null)
			{
				projectile.m_visual = ((Component)val).gameObject;
				projectile.m_canChangeVisuals = true;
				return;
			}
			SecondaryAttackPerformanceLog.Start();
			HideSourcePresentation(projectile);
			SecondaryAttackPerformanceLog.Start();
			GameObject val2 = new GameObject("SecondaryAttacks_CopiedThrowVisualRoot");
			val2.transform.SetParent(((Component)projectile).transform, false);
			val2.layer = ((Component)projectile).gameObject.layer;
			projectile.m_visual = val2;
			projectile.m_canChangeVisuals = true;
		}

		private static void HideSourcePresentation(Projectile projectile)
		{
			RendererBuffer.Clear();
			((Component)projectile).GetComponentsInChildren<Renderer>(true, RendererBuffer);
			foreach (Renderer item in RendererBuffer)
			{
				if (!(item is TrailRenderer) && !(item is ParticleSystemRenderer))
				{
					item.enabled = false;
				}
			}
			RendererBuffer.Clear();
		}

		private static void ApplyLocalFallbackVisual(Projectile projectile, ItemData weapon)
		{
			ApplyLocalFallbackVisual(projectile, CreateSpawnedProjectileVisualContext(weapon, includeHitEffects: false));
		}

		private static void ApplyLocalFallbackVisual(Projectile projectile, SpawnedProjectileVisualContext context)
		{
			ApplyLocalFallbackVisual(projectile, context, "copiedThrow.visual.fallback");
		}

		private static void ApplyLocalFallbackVisual(Projectile projectile, SpawnedProjectileVisualContext context, string perfScopePrefix)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (context.Active && !((Object)(object)context.AttachPrefab == (Object)null))
			{
				GameObject visual = projectile.m_visual;
				SecondaryAttackPerformanceLog.Start();
				GameObject val = Object.Instantiate<GameObject>(context.AttachPrefab, ((Component)projectile).transform, false);
				((Object)val).name = ((Object)context.AttachPrefab).name + "(ProjectileVisual)";
				val.transform.localPosition = Vector3.zero;
				val.transform.localRotation = Quaternion.identity;
				if ((Object)(object)visual != (Object)null && (Object)(object)visual != (Object)(object)val)
				{
					visual.SetActive(false);
				}
				SecondaryAttackPerformanceLog.Start();
				IEquipmentVisual componentInChildren = val.GetComponentInChildren<IEquipmentVisual>();
				if (componentInChildren != null)
				{
					componentInChildren.Setup(context.Weapon.m_variant);
				}
				projectile.m_visual = val;
				SecondaryAttackPerformanceLog.Start();
				ApplyCopiedThrowVisualSpin(projectile, context);
			}
		}

		private static void ApplyCopiedThrowVisualSpin(Projectile projectile, ItemData? weapon, string? visualPrefabName = null)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_005b: 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)
			if (!((Object)(object)projectile == (Object)null))
			{
				SecondaryAttackDefinition definition = ResolveCopiedThrowDefinition(weapon, visualPrefabName);
				ThrowProjectileVisualSpin.AxisMode axisMode;
				Vector3 rotationOffset;
				bool num = TryResolveSyncedProjectileSpin(projectile, out axisMode, out rotationOffset);
				ThrowProjectileVisualSpin.AxisMode valueOrDefault = (num ? new ThrowProjectileVisualSpin.AxisMode?(axisMode) : ResolveConfiguredCopiedThrowSpinAxisMode(definition)).GetValueOrDefault();
				Vector3 rotationOffset2 = (num ? rotationOffset : ResolveConfiguredCopiedThrowVisualRotationOffset(definition));
				Vector3 horizontalForward = ((valueOrDefault == ThrowProjectileVisualSpin.AxisMode.HorizontalSide) ? ResolveOwnerHorizontalForward(projectile) : Vector3.zero);
				ApplyCopiedThrowSpinConfiguration(projectile, valueOrDefault, rotationOffset2, horizontalForward);
			}
		}

		private static void ApplyCopiedThrowVisualSpin(Projectile projectile, SpawnedProjectileVisualContext context)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)projectile == (Object)null) && context.Active)
			{
				Vector3 horizontalForward = ((context.SpinAxisMode == ThrowProjectileVisualSpin.AxisMode.HorizontalSide) ? ResolveOwnerHorizontalForward(projectile) : Vector3.zero);
				ApplyCopiedThrowSpinConfiguration(projectile, context.SpinAxisMode, context.VisualRotationOffset, horizontalForward);
			}
		}

		private static void ApplyCopiedThrowSpinConfiguration(Projectile projectile, ThrowProjectileVisualSpin.AxisMode axisMode, Vector3 rotationOffset, Vector3 horizontalForward)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			//IL_0031: 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)
			GameObject val = ResolveCopiedThrowSpinVisual(projectile.m_visual);
			if (!((Object)(object)val == (Object)null))
			{
				CopiedThrowSpinState copiedThrowSpinState = val.GetComponent<CopiedThrowSpinState>() ?? val.AddComponent<CopiedThrowSpinState>();
				if (!IsProjectileVisualSpinCleared(projectile) || !copiedThrowSpinState.IsCurrent(axisMode, rotationOffset, horizontalForward))
				{
					ClearProjectileVisualSpin(projectile);
					ThrowProjectileVisualRotationOffset.Ensure(val, rotationOffset);
					ThrowProjectileVisualSpin.Ensure(val, axisMode, horizontalForward);
					copiedThrowSpinState.Configure(axisMode, rotationOffset, horizontalForward);
				}
			}
		}

		private static SecondaryAttackDefinition? ResolveCopiedThrowDefinition(Attack? attack, ItemData? weapon, string? visualPrefabName)
		{
			if (attack != null && SecondaryAttackRuntimeContext.TryGetActiveAttack(attack, out ActiveSecondaryAttack activeAttack) && activeAttack?.Definition != null)
			{
				return activeAttack.Definition;
			}
			return ResolveCopiedThrowDefinition(weapon, visualPrefabName);
		}

		private static SecondaryAttackDefinition? ResolveCopiedThrowDefinition(ItemData? weapon, string? visualPrefabName)
		{
			if (weapon != null && SecondaryAttackRuntimeFacade.TryGetDefinition(weapon, out SecondaryAttackDefinition definition))
			{
				return definition;
			}
			string text = visualPrefabName?.Trim() ?? "";
			if (text.Length > 0 && SecondaryAttackRuntimeFacade.TryGetDefinition(text, out SecondaryAttackDefinition definition2))
			{
				return definition2;
			}
			return null;
		}

		private static ThrowProjectileVisualSpin.AxisMode? ResolveConfiguredCopiedThrowSpinAxisMode(SecondaryAttackDefinition? definition)
		{
			if (definition == null)
			{
				return null;
			}
			if (definition.Boomerang != null && ProjectileSpinAxis.TryResolveAxisMode(definition.Boomerang.ProjectileSpinAxis, out var axisMode))
			{
				return axisMode;
			}
			if (definition.OnProjectileHit == null || !ProjectileSpinAxis.TryResolveAxisMode(definition.OnProjectileHit.ProjectileSpinAxis, out var axisMode2))
			{
				return null;
			}
			return axisMode2;
		}

		private static Vector3 ResolveConfiguredCopiedThrowVisualRotationOffset(SecondaryAttackDefinition? definition)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (definition?.Boomerang != null)
			{
				return definition.Boomerang.ProjectileVisualRotationOffset;
			}
			return (Vector3)(((??)definition?.OnProjectileHit?.ProjectileVisualRotationOffset) ?? Vector3.zero);
		}

		private static GameObject? ResolveCopiedThrowSpinVisual(GameObject? visual)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0055: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)visual == (Object)null)
			{
				return null;
			}
			Transform transform = visual.transform;
			Transform val = transform.Find("SecondaryAttacks_CopiedThrowSpinRoot");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).gameObject;
			}
			GameObject val2 = new GameObject("SecondaryAttacks_CopiedThrowSpinRoot");
			val2.layer = visual.layer;
			Transform transform2 = val2.transform;
			transform2.SetParent(transform, false);
			transform2.localPosition = Vector3.zero;
			transform2.localRotation = Quaternion.identity;
			transform2.localScale = Vector3.one;
			bool flag = false;
			for (int num = transform.childCount - 1; num >= 0; num--)
			{
				Transform child = transform.GetChild(num);
				if (!((Object)(object)child == (Object)(object)transform2))
				{
					child.SetParent(transform2, false);
					flag = true;
				}
			}
			if (flag)
			{
				return val2;
			}
			Object.Destroy((Object)(object)val2);
			return visual;
		}

		private static bool TryResolveSyncedProjectileSpin(Projectile projectile, out ThrowProjectileVisualSpin.AxisMode axisMode, out Vector3 rotationOffset)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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)
			axisMode = ThrowProjectileVisualSpin.AxisMode.None;
			rotationOffset = Vector3.zero;
			ZNetView val = (((Object)(object)projectile != (Object)null) ? ((Component)projectile).GetComponent<ZNetView>() : null);
			string raw = default(string);
			if ((Object)(object)val == (Object)null || !val.IsValid() || val.GetZDO() == null || !val.GetZDO().GetString("SecondaryAttacks_CopiedThrowSpinAxis", ref raw) || !ProjectileSpinAxis.TryResolveAxisMode(raw, out axisMode))
			{
				return false;
			}
			string raw2 = default(string);
			if (val.GetZDO().GetString("SecondaryAttacks_CopiedThrowRotationOffset", ref raw2) && TryParseVector3(raw2, out var value))
			{
				rotationOffset = value;
			}
			return true;
		}

		private static string ToProjectileSpinAxisString(ThrowProjectileVisualSpin.AxisMode axisMode)
		{
			return axisMode switch
			{
				ThrowProjectileVisualSpin.AxisMode.HorizontalSide => "horizontal", 
				ThrowProjectileVisualSpin.AxisMode.WorldUp => "vertical", 
				_ => "none", 
			};
		}

		private static string SerializeVector3(Vector3 value)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", value.x, value.y, value.z);
		}

		private static bool TryParseVector3(string raw, out Vector3 value)
		{
			//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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			value = Vector3.zero;
			if (string.IsNullOrWhiteSpace(raw))
			{
				return false;
			}
			string[] array = raw.Split(',');
			if (array.Length != 3)
			{
				return false;
			}
			if (!float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return false;
			}
			value = new Vector3(result, result2, result3);
			return true;
		}

		private static Vector3 ResolveOwnerHorizontalForward(Projectile projectile)
		{
			//IL_0023: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Character owner = ProjectileAccess.GetOwner(projectile);
			Vector3 val = (((Object)(object)owner != (Object)null) ? ((Component)owner).transform.forward : ((Component)projectile).transform.forward);
			val = Vector3.ProjectOnPlane(val, Vector3.up);
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.001f))
			{
				return Vector3.zero;
			}
			return ((Vector3)(ref val)).normalized;
		}

		private static void ClearProjectileVisualSpin(Projectile projectile)
		{
			projectile.m_rotateVisual = 0f;
			projectile.m_rotateVisualY = 0f;
			projectile.m_rotateVisualZ = 0f;
		}

		private static bool IsProjectileVisualSpinCleared(Projectile projectile)
		{
			if (Mathf.Approximately(projectile.m_rotateVisual, 0f) && Mathf.Approximately(projectile.m_rotateVisualY, 0f))
			{
				return Mathf.Approximately(projectile.m_rotateVisualZ, 0f);
			}
			return false;
		}

		private static string? TryResolveSyncedVisualPrefabName(Projectile projectile)
		{
			ZNetView val = ((projectile != null) ? ((Component)projectile).GetComponent<ZNetView>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				return TryResolveSyncedVisualPrefabName(val);
			}
			return null;
		}

		private static string? TryResolveSyncedVisualPrefabName(ZNetView nview)
		{
			string result = default(string);
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || nview.GetZDO() == null || !nview.GetZDO().GetString(ZDOVars.s_visual, ref result))
			{
				return null;
			}
			return result;
		}

		private static ItemDrop? TryResolveSyncedVisualItem(ZNetView nview)
		{
			return TryResolveSyncedVisualItem(TryResolveSyncedVisualPrefabName(nview));
		}

		private static ItemDrop? TryResolveSyncedVisualItem(string? visualPrefabName)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrWhiteSpace(visualPrefabName))
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(visualPrefabName);
			if (itemPrefab == null)
			{
				return null;
			}
			return itemPrefab.GetComponent<ItemDrop>();
		}

		private static string FormatVector(Vector3 value)
		{
			return ((Vector3)(ref value)).ToString("F2");
		}
	}
	internal static class CleavingThrustSystem
	{
		private readonly struct CleavingThrustHitTarget
		{
			public IDestructible Destructible { get; }

			public Character? Character { get; }

			public Collider? Collider { get; }

			public Vector3 Point { get; }

			public float Distance { get; }

			public CleavingThrustHitTarget(IDestructible destructible, Character? character, Collider? collider, Vector3 point, float distance)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				Destructible = destructible;
				Character = character;
				Collider = collider;
				Point = point;
				Distance = distance;
			}
		}

		private readonly struct CleavingThrustAttackShape
		{
			public float Range { get; }

			public float Angle { get; }

			public float RayWidth { get; }

			public float CharacterRayWidth { get; }

			public CleavingThrustAttackShape(float range, float angle, floa