Decompiled source of OreWeakSpots v0.9.3

plugins/OreWeakSpots/OreWeakSpots.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace OreWeakSpots;

public enum SpotColorOption
{
	Blue,
	Gold
}
public enum CritSoundOption
{
	Auto,
	File,
	Game,
	Mod,
	None
}
public enum CritNumberColorOption
{
	Yellow,
	Red,
	Normal
}
[BepInPlugin("felih.OreWeakSpots", "Ore Weak Spots", "0.9.3")]
public class Plugin : BaseUnityPlugin
{
	public const string GUID = "felih.OreWeakSpots";

	public const string NAME = "Ore Weak Spots";

	public const string VERSION = "0.9.3";

	public static ManualLogSource Log;

	public static ConfigEntry<bool> Enabled;

	public static ConfigEntry<float> CritMultiplier;

	public static ConfigEntry<bool> CritUsesMidDamage;

	public static ConfigEntry<int> SpotCount;

	public static ConfigEntry<float> HitTolerance;

	public static ConfigEntry<float> SpotLifetime;

	public static ConfigEntry<float> MaxDistance;

	public static ConfigEntry<float> ActiveDuration;

	public static ConfigEntry<SpotColorOption> SpotColor;

	public static ConfigEntry<float> SpotSize;

	public static ConfigEntry<float> SoundVolume;

	public static ConfigEntry<CritSoundOption> CritSound;

	public static ConfigEntry<bool> AllRocks;

	public static ConfigEntry<string> OreNames;

	public static ConfigEntry<string> Excluded;

	public static ConfigEntry<float> MinSpacing;

	public static ConfigEntry<CritNumberColorOption> CritNumberColor;

	public static ConfigEntry<float> CritNumberScale;

	public static ConfigEntry<bool> DebugLog;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Expected O, but got Unknown
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Expected O, but got Unknown
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Expected O, but got Unknown
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Expected O, but got Unknown
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: Expected O, but got Unknown
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Expected O, but got Unknown
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Expected O, but got Unknown
		//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f0: Expected O, but got Unknown
		//IL_0364: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Expected O, but got Unknown
		//IL_0398: Unknown result type (might be due to invalid IL or missing references)
		//IL_039e: Expected O, but got Unknown
		//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bb: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Turns the mod on or off.");
		CritMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "CritMultiplier", 2f, new ConfigDescription("Pickaxe damage multiplier when you hit a weak spot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), new object[0]));
		CritUsesMidDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "CritUsesMidDamage", true, "Always use 2x mid damage: a crit ignores the game's random damage roll and uses the middle of your pickaxe skill's damage range before multiplying, so crits are never weak. Off = the crit multiplies whatever the game rolled.");
		AllRocks = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "AllRocks", true, "If on, weak spots appear on any rock, not only on ores.");
		OreNames = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "OreNames", "copper,silver,obsidian,mudpile,meteorite,flametal,softtissue,giant,blackmarble,iron", "Parts of object names that count as ore (comma-separated). Used when AllRocks is off.");
		Excluded = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Exclude", "tin", "Parts of rock names that NEVER get weak spots, even with AllRocks on (comma-separated). Default: tin, which is too small.");
		SpotCount = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Weak spots", "Count", 4, new ConfigDescription("How many weak spots appear at the same time.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), new object[0]));
		MinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "MinSpacing", 1.2f, new ConfigDescription("Minimum distance (meters) between two weak spots. On a rock that is too small, fewer spots appear instead of crowding together.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 5f), new object[0]));
		HitTolerance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "HitTolerance", 0.6f, new ConfigDescription("Maximum distance (meters) between the hit and the spot for a crit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), new object[0]));
		SpotLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "SpotLifetime", 5f, new ConfigDescription("Seconds each spot stays visible before it moves.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[0]));
		MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "MaxDistance", 8f, new ConfigDescription("Maximum distance (meters) from your eyes where a spot can appear. Spots spread over the whole ore surface within this distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 20f), new object[0]));
		ActiveDuration = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "IdleTimeout", 3f, new ConfigDescription("Seconds without aiming at or hitting the ore before the spots disappear.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 60f), new object[0]));
		SpotColor = ((BaseUnityPlugin)this).Config.Bind<SpotColorOption>("3 - Visuals", "Color", SpotColorOption.Gold, "Weak spot color.");
		SpotSize = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Visuals", "Size", 1f, new ConfigDescription("Scale of the glowing orbs (1 = about 16 cm).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), new object[0]));
		SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Visuals", "SoundVolume", 1f, new ConfigDescription("Crit sound volume (0 = off). Also follows the game's effects volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
		CritSound = ((BaseUnityPlugin)this).Config.Bind<CritSoundOption>("3 - Visuals", "CritSound", CritSoundOption.Auto, "Auto = a file from the mod's SFX folder if there is one, otherwise the game sound. File = only .wav/.ogg files from BepInEx/plugins/OreWeakSpots/SFX (one at random). Game = Valheim's sound for hitting a staggered enemy. Mod = the mod's own chime. None = no sound.");
		CritNumberColor = ((BaseUnityPlugin)this).Config.Bind<CritNumberColorOption>("3 - Visuals", "CritNumberColor", CritNumberColorOption.Yellow, "Color of a crit's damage number. Normal = the game's default color.");
		CritNumberScale = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Visuals", "CritNumberSize", 2f, new ConfigDescription("Size of a crit's damage number (2 = double, 1 = unchanged).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 4f), new object[0]));
		DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "DetailedLog", false, "Writes each hit, where the spots were placed and the distance from the hit to the spot to the BepInEx log (helps tuning).");
		GameObject val = new GameObject("OreWeakSpots_Manager");
		Object.DontDestroyOnLoad((Object)(object)val);
		val.AddComponent<WeakSpotManager>();
		_harmony = new Harmony("felih.OreWeakSpots");
		_harmony.PatchAll(typeof(Plugin).Assembly);
		Log.LogInfo((object)"Ore Weak Spots 0.9.3 loaded.");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
[HarmonyPatch]
internal static class DamagePatches
{
	[HarmonyPatch(typeof(MineRock5), "Damage")]
	[HarmonyPrefix]
	private static void MineRock5Damage(MineRock5 __instance, HitData __0)
	{
		WeakSpotManager.OnPickaxeHit((Component)(object)__instance, __0);
	}

	[HarmonyPatch(typeof(MineRock), "Damage")]
	[HarmonyPrefix]
	private static void MineRockDamage(MineRock __instance, HitData __0)
	{
		WeakSpotManager.OnPickaxeHit((Component)(object)__instance, __0);
	}

	[HarmonyPatch(typeof(Destructible), "Damage")]
	[HarmonyPrefix]
	private static void DestructibleDamage(Destructible __instance, HitData __0)
	{
		WeakSpotManager.OnPickaxeHit((Component)(object)__instance, __0);
	}
}
[HarmonyPatch(typeof(Skills), "GetRandomSkillFactor")]
internal static class SkillRollPatch
{
	private static void Postfix(Skills __instance, SkillType __0, float __result)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		WeakSpotManager.NoteSkillRoll(__instance, __0, __result);
	}
}
[HarmonyPatch(typeof(DamageText), "AddInworldText")]
internal static class CritNumberPatch
{
	private static FieldInfo _worldTexts;

	private static FieldInfo _textField;

	private static void Postfix(DamageText __instance, Vector3 pos, string text)
	{
		//IL_0000: 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_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			bool flag = WeakSpotManager.IsRecentCrit(pos);
			if (Plugin.DebugLog.Value && (flag || WeakSpotManager.IsRecentHit(pos)))
			{
				Plugin.Log.LogInfo((object)("On-screen number: " + text + (flag ? " (crit)" : "")));
			}
			if (!flag)
			{
				return;
			}
			if (_worldTexts == null)
			{
				_worldTexts = AccessTools.Field(typeof(DamageText), "m_worldTexts");
			}
			if (!(_worldTexts.GetValue(__instance) is IList { Count: not 0 } list))
			{
				return;
			}
			object obj = list[list.Count - 1];
			if (_textField == null)
			{
				_textField = AccessTools.Field(obj.GetType(), "m_textField");
			}
			object value = _textField.GetValue(obj);
			if (value != null)
			{
				Type type = value.GetType();
				if (Plugin.CritNumberColor.Value != CritNumberColorOption.Normal)
				{
					Color val = ((Plugin.CritNumberColor.Value == CritNumberColorOption.Red) ? new Color(1f, 0.18f, 0.12f) : new Color(1f, 0.82f, 0.1f));
					type.GetProperty("color").SetValue(value, val, null);
				}
				PropertyInfo property = type.GetProperty("fontSize");
				float num = (float)property.GetValue(value, null);
				property.SetValue(value, num * Plugin.CritNumberScale.Value, null);
			}
		}
		catch (Exception ex)
		{
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogWarning((object)("CritNumberPatch: " + ex.Message));
			}
		}
	}
}
public class WeakSpotManager : MonoBehaviour
{
	private static WeakSpotManager _inst;

	private Component _target;

	private float _lastSeenTime;

	private float _nextScan;

	private Vector3 _anchor;

	private readonly List<WeakSpot> _spots = new List<WeakSpot>();

	private int _critFrame = -1;

	private Texture2D _glowTex;

	private Mesh _quadMesh;

	private Mesh _sphereMesh;

	private Shader _shader;

	private AudioClip _critClip;

	private static float _lastRoll = 1f;

	private static float _midRoll = 1f;

	private static float _rollTime = -100f;

	private static float _lastHitTime = -100f;

	private static Vector3 _lastHitPos;

	private static float _lastCritTime = -100f;

	private static Vector3 _lastCritPos;

	private readonly List<AudioClip> _fileClips = new List<AudioClip>();

	private readonly List<AudioClip> _gameClips = new List<AudioClip>();

	private AudioMixerGroup _mixerGroup;

	private bool _gameSoundSearched;

	private AudioSource _playerAudio;

	private Player _audioOwner;

	public static FieldInfo FindField(Type t, string name)
	{
		while (t != null)
		{
			FieldInfo field = t.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field;
			}
			t = t.BaseType;
		}
		return null;
	}

	private void Awake()
	{
		_inst = this;
		_glowTex = MakeGlowTexture(64);
		_quadMesh = MakeQuadMesh();
		GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
		_sphereMesh = val.GetComponent<MeshFilter>().sharedMesh;
		Object.Destroy((Object)(object)val);
		string[] array = new string[4] { "Sprites/Default", "Legacy Shaders/Particles/Alpha Blended", "Unlit/Transparent", "UI/Default" };
		for (int i = 0; i < array.Length; i++)
		{
			if (!((Object)(object)_shader == (Object)null))
			{
				break;
			}
			_shader = Shader.Find(array[i]);
			if ((Object)(object)_shader != (Object)null)
			{
				Plugin.Log.LogInfo((object)("Shader in use: " + array[i]));
			}
		}
		if ((Object)(object)_shader == (Object)null)
		{
			Plugin.Log.LogWarning((object)"No transparent shader found; only the spot's light will be visible.");
		}
		_critClip = MakeCritClip();
		((MonoBehaviour)this).StartCoroutine(LoadSoundFiles());
	}

	public static void OnPickaxeHit(Component rock, HitData hit)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Invalid comparison between Unknown and I4
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_inst == (Object)null || hit == null || (Object)(object)rock == (Object)null || !Plugin.Enabled.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			Character attacker = hit.GetAttacker();
			string text = null;
			if ((Object)(object)attacker != (Object)(object)localPlayer)
			{
				text = "hit is not from the local player (" + (((Object)(object)attacker == (Object)null) ? "null" : ((Object)attacker).name) + ")";
			}
			else if ((int)hit.m_skill != 12)
			{
				text = string.Concat("tool is not a pickaxe (", hit.m_skill, ")");
			}
			else if (!IsOre(rock))
			{
				text = "not in the ore list";
			}
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("Hit on " + OreId(rock) + " (" + ((object)rock).GetType().Name + "): " + ((text == null) ? "accepted" : ("ignored, " + text))));
			}
			if (text == null)
			{
				_inst.HandleHit(rock, hit);
			}
		}
	}

	private static ZNetView NViewOf(Component rock)
	{
		ZNetView val = null;
		FieldInfo fieldInfo = FindField(((object)rock).GetType(), "m_nview");
		if (fieldInfo != null)
		{
			object? value = fieldInfo.GetValue(rock);
			val = (ZNetView)((value is ZNetView) ? value : null);
		}
		if ((Object)(object)val == (Object)null)
		{
			val = rock.GetComponentInParent<ZNetView>();
		}
		return val;
	}

	private static Transform RootOf(Component rock)
	{
		ZNetView val = NViewOf(rock);
		if (!((Object)(object)val != (Object)null))
		{
			return rock.transform.root;
		}
		return ((Component)val).transform;
	}

	private static string OreId(Component rock)
	{
		string text = ((Object)rock.gameObject).name;
		ZNetView val = NViewOf(rock);
		if ((Object)(object)val != (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
		{
			ZDO zDO = val.GetZDO();
			if (zDO != null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab());
				if ((Object)(object)prefab != (Object)null)
				{
					text = ((Object)prefab).name;
				}
			}
		}
		FieldInfo fieldInfo = FindField(((object)rock).GetType(), "m_name");
		if (fieldInfo != null)
		{
			string text2 = fieldInfo.GetValue(rock) as string;
			if (!string.IsNullOrEmpty(text2))
			{
				text = text + " " + text2;
			}
		}
		return text;
	}

	private bool BelongsToTarget(Collider c)
	{
		Transform transform = ((Component)c).transform;
		if (!transform.IsChildOf(RootOf(_target)))
		{
			return transform.IsChildOf(_target.transform);
		}
		return true;
	}

	private static bool NameMatches(string name, string list)
	{
		string[] array = list.ToLowerInvariant().Split(',');
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length > 0 && name.Contains(text))
			{
				return true;
			}
		}
		return false;
	}

	private static bool IsOre(Component rock)
	{
		string name = OreId(rock).ToLowerInvariant();
		if (NameMatches(name, Plugin.Excluded.Value))
		{
			return false;
		}
		if (!IsRock(rock))
		{
			return false;
		}
		if (Plugin.AllRocks.Value)
		{
			return true;
		}
		if (NameMatches(name, Plugin.OreNames.Value))
		{
			return true;
		}
		return DropsMoreThanStone(rock, 0);
	}

	private static bool IsRock(Component rock)
	{
		//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_0024: 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_002c: Invalid comparison between Unknown and I4
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Invalid comparison between Unknown and I4
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Invalid comparison between Unknown and I4
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Invalid comparison between Unknown and I4
		Destructible val = (Destructible)(object)((rock is Destructible) ? rock : null);
		if ((Object)(object)val == (Object)null)
		{
			return true;
		}
		DamageModifier pickaxe = val.m_damages.m_pickaxe;
		DamageModifier chop = val.m_damages.m_chop;
		bool flag = (int)pickaxe != 3 && (int)pickaxe != 4;
		bool result = (int)chop == 3 || (int)chop == 4;
		if (flag)
		{
			return result;
		}
		return false;
	}

	private static bool DropsMoreThanStone(Component rock, int depth)
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		DropTable val = null;
		FieldInfo fieldInfo = FindField(((object)rock).GetType(), "m_dropItems");
		if (fieldInfo != null)
		{
			object? value = fieldInfo.GetValue(rock);
			val = (DropTable)((value is DropTable) ? value : null);
		}
		Destructible val2 = (Destructible)(object)((rock is Destructible) ? rock : null);
		if ((Object)(object)val2 != (Object)null)
		{
			DropOnDestroyed component = ((Component)val2).GetComponent<DropOnDestroyed>();
			if ((Object)(object)component != (Object)null)
			{
				val = component.m_dropWhenDestroyed;
			}
			if ((val == null || val.m_drops == null || val.m_drops.Count == 0) && (Object)(object)val2.m_spawnWhenDestroyed != (Object)null && depth < 2)
			{
				Component component2 = (Component)(object)val2.m_spawnWhenDestroyed.GetComponent<MineRock5>();
				if ((Object)(object)component2 == (Object)null)
				{
					component2 = (Component)(object)val2.m_spawnWhenDestroyed.GetComponent<MineRock>();
				}
				if ((Object)(object)component2 != (Object)null)
				{
					return DropsMoreThanStone(component2, depth + 1);
				}
			}
		}
		if (val == null || val.m_drops == null)
		{
			return false;
		}
		for (int i = 0; i < val.m_drops.Count; i++)
		{
			GameObject item = val.m_drops[i].m_item;
			if ((Object)(object)item != (Object)null && ((Object)item).name != "Stone")
			{
				return true;
			}
		}
		return false;
	}

	private void SetTarget(Component rock, Vector3 anchor)
	{
		//IL_000e: 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)
		ClearSpots();
		_target = rock;
		_anchor = anchor;
		_lastSeenTime = Time.time;
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Marking " + OreId(rock) + " (" + ((object)rock).GetType().Name + ") with " + Plugin.SpotCount.Value + " weak spots."));
		}
		for (int i = 0; i < Plugin.SpotCount.Value; i++)
		{
			WeakSpot weakSpot = CreateSpot();
			weakSpot.Relocate((float)i * 0.3f);
			_spots.Add(weakSpot);
		}
	}

	private void HandleHit(Component rock, HitData hit)
	{
		//IL_0045: 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_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		_lastSeenTime = Time.time;
		NoteHit(hit);
		if (_critFrame == Time.frameCount && (Object)(object)_target == (Object)(object)rock)
		{
			ApplyCrit(hit);
			return;
		}
		if ((Object)(object)_target != (Object)(object)rock)
		{
			SetTarget(rock, hit.m_point);
			return;
		}
		WeakSpot weakSpot = null;
		float num = float.MaxValue;
		for (int i = 0; i < _spots.Count; i++)
		{
			WeakSpot weakSpot2 = _spots[i];
			if (weakSpot2.IsHittable)
			{
				float num2 = Vector3.Distance(weakSpot2.Position, hit.m_point);
				if (num2 < num)
				{
					num = num2;
					weakSpot = weakSpot2;
				}
			}
		}
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Hit on " + ((Object)rock).name + ": distance to the nearest spot = " + ((weakSpot == null) ? "no spot" : (num.ToString("0.00") + " m"))));
		}
		if (weakSpot != null && num <= Plugin.HitTolerance.Value)
		{
			_critFrame = Time.frameCount;
			ApplyCrit(hit);
			PlayCritEffects(weakSpot.Position, weakSpot.Color);
			weakSpot.Relocate(0.5f);
		}
	}

	private void ApplyCrit(HitData hit)
	{
		float pickaxe = hit.m_damage.m_pickaxe;
		string text = "";
		if (Plugin.CritUsesMidDamage.Value && Time.time - _rollTime < 1f && _lastRoll > 0.01f)
		{
			hit.m_damage.m_pickaxe = hit.m_damage.m_pickaxe / _lastRoll * _midRoll;
			text = ", roll " + _lastRoll.ToString("0.00") + " → mid " + _midRoll.ToString("0.00");
		}
		ref DamageTypes damage = ref hit.m_damage;
		damage.m_pickaxe *= Plugin.CritMultiplier.Value;
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Crit: pickaxe damage " + pickaxe.ToString("0.0") + " → " + hit.m_damage.m_pickaxe.ToString("0.0") + " (x" + Plugin.CritMultiplier.Value.ToString("0.##") + text + ")"));
		}
	}

	public static void NoteSkillRoll(Skills skills, SkillType skill, float roll)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		if ((int)skill == 12)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)skills != (Object)(object)((Character)localPlayer).GetSkills()))
			{
				float num = Mathf.Lerp(0.4f, 1f, skills.GetSkillFactor(skill));
				_midRoll = (Mathf.Clamp01(num - 0.15f) + Mathf.Clamp01(num + 0.15f)) * 0.5f;
				_lastRoll = roll;
				_rollTime = Time.time;
			}
		}
	}

	private static void NoteHit(HitData hit)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		_lastHitTime = Time.time;
		_lastHitPos = hit.m_point;
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Hit damage: pickaxe " + hit.m_damage.m_pickaxe.ToString("0.0") + ", total " + ((DamageTypes)(ref hit.m_damage)).GetTotalDamage().ToString("0.0")));
		}
	}

	public static bool IsRecentHit(Vector3 pos)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		if (Time.time - _lastHitTime < 1.5f)
		{
			Vector3 val = pos - _lastHitPos;
			return ((Vector3)(ref val)).sqrMagnitude < 16f;
		}
		return false;
	}

	private void Update()
	{
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_target == (Object)null && _spots.Count > 0)
		{
			ClearSpots();
		}
		Player localPlayer = Player.m_localPlayer;
		if (!Plugin.Enabled.Value || (Object)(object)localPlayer == (Object)null || !HoldingPickaxe(localPlayer))
		{
			if ((Object)(object)_target != (Object)null)
			{
				ClearSpots();
			}
			return;
		}
		if (Time.time >= _nextScan)
		{
			_nextScan = Time.time + 0.1f;
			ScanAimedOre(localPlayer);
		}
		if ((Object)(object)_target == (Object)null)
		{
			return;
		}
		bool flag = Vector3.Distance(((Component)localPlayer).transform.position, _anchor) > 10f;
		bool flag2 = Time.time - _lastSeenTime > Plugin.ActiveDuration.Value;
		if (flag || flag2)
		{
			ClearSpots();
			return;
		}
		Camera main = Camera.main;
		for (int i = 0; i < _spots.Count; i++)
		{
			_spots[i].Tick(main);
		}
	}

	private static bool HoldingPickaxe(Player player)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Invalid comparison between Unknown and I4
		ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
		if (currentWeapon != null && currentWeapon.m_shared != null)
		{
			return (int)currentWeapon.m_shared.m_skillType == 12;
		}
		return false;
	}

	private void ScanAimedOre(Player player)
	{
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		GameObject hoverObject = ((Humanoid)player).GetHoverObject();
		if ((Object)(object)hoverObject == (Object)null)
		{
			return;
		}
		Component componentInParent = (Component)(object)hoverObject.GetComponentInParent<MineRock5>();
		if ((Object)(object)componentInParent == (Object)null)
		{
			componentInParent = (Component)(object)hoverObject.GetComponentInParent<MineRock>();
		}
		if ((Object)(object)componentInParent == (Object)null)
		{
			componentInParent = (Component)(object)hoverObject.GetComponentInParent<Destructible>();
		}
		if ((Object)(object)componentInParent == (Object)null || !IsOre(componentInParent))
		{
			return;
		}
		Vector3 point;
		bool flag = AimPointOn(componentInParent, out point);
		if ((Object)(object)componentInParent != (Object)(object)_target)
		{
			SetTarget(componentInParent, flag ? point : hoverObject.transform.position);
			return;
		}
		_lastSeenTime = Time.time;
		if (flag)
		{
			_anchor = point;
		}
	}

	private bool AimPointOn(Component rock, out Vector3 point)
	{
		//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_0022: 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_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)
		point = Vector3.zero;
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			return false;
		}
		RaycastHit[] array = Physics.RaycastAll(((Component)main).transform.position, ((Component)main).transform.forward, 30f, -1, (QueryTriggerInteraction)1);
		float num = float.MaxValue;
		Component target = _target;
		_target = rock;
		for (int i = 0; i < array.Length; i++)
		{
			if (((RaycastHit)(ref array[i])).distance < num && BelongsToTarget(((RaycastHit)(ref array[i])).collider))
			{
				num = ((RaycastHit)(ref array[i])).distance;
				point = ((RaycastHit)(ref array[i])).point;
			}
		}
		_target = target;
		return num < float.MaxValue;
	}

	private void ClearSpots()
	{
		for (int i = 0; i < _spots.Count; i++)
		{
			_spots[i].Destroy();
		}
		_spots.Clear();
		_target = null;
	}

	private bool TargetBounds(out Bounds bounds)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: 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)
		bounds = default(Bounds);
		bool flag = false;
		Transform[] array = (Transform[])(object)new Transform[2]
		{
			RootOf(_target),
			_target.transform
		};
		for (int i = 0; i < array.Length && (i != 1 || !((Object)(object)array[1] == (Object)(object)array[0])); i++)
		{
			Collider[] componentsInChildren = ((Component)array[i]).GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger && ((Component)val).gameObject.activeInHierarchy)
				{
					if (!flag)
					{
						bounds = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val.bounds);
					}
				}
			}
		}
		return flag;
	}

	public bool FindSurfacePoint(WeakSpot self, out Vector3 pos, out Vector3 normal, out Collider col)
	{
		//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_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: 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_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: 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_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		pos = Vector3.zero;
		normal = Vector3.up;
		col = null;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)_target == (Object)null)
		{
			return false;
		}
		if (!TargetBounds(out var bounds))
		{
			return false;
		}
		Vector3 eyePoint = ((Character)localPlayer).GetEyePoint();
		float value = Plugin.MaxDistance.Value;
		float value2 = Plugin.MinSpacing.Value;
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		string text = "";
		for (int i = 0; i < 50; i++)
		{
			Vector3 val = ((Bounds)(ref bounds)).center + Vector3.Scale(Random.insideUnitSphere, ((Bounds)(ref bounds)).extents);
			Vector3 val2 = val - eyePoint;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude < 0.1f)
			{
				continue;
			}
			val2 /= magnitude;
			Vector3 val3 = val2;
			Vector3 size = ((Bounds)(ref bounds)).size;
			RaycastHit[] array = Physics.RaycastAll(eyePoint, val3, magnitude + ((Vector3)(ref size)).magnitude, -1, (QueryTriggerInteraction)1);
			if (array.Length == 0)
			{
				num++;
				continue;
			}
			Array.Sort(array, (RaycastHit h1, RaycastHit h2) => ((RaycastHit)(ref h1)).distance.CompareTo(((RaycastHit)(ref h2)).distance));
			RaycastHit val4 = default(RaycastHit);
			bool flag = false;
			for (int num5 = 0; num5 < array.Length; num5++)
			{
				if (!((Component)((RaycastHit)(ref array[num5])).collider).transform.IsChildOf(((Component)localPlayer).transform))
				{
					val4 = array[num5];
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				num++;
				continue;
			}
			if (!BelongsToTarget(((RaycastHit)(ref val4)).collider))
			{
				num2++;
				text = ((Object)((RaycastHit)(ref val4)).collider).name + " (layer " + LayerMask.LayerToName(((Component)((RaycastHit)(ref val4)).collider).gameObject.layer) + ")";
				continue;
			}
			if (((RaycastHit)(ref val4)).distance > value)
			{
				num3++;
				continue;
			}
			bool flag2 = false;
			for (int num6 = 0; num6 < _spots.Count; num6++)
			{
				WeakSpot weakSpot = _spots[num6];
				if (weakSpot != self && weakSpot.IsPlaced && Vector3.Distance(weakSpot.Position, ((RaycastHit)(ref val4)).point) < value2)
				{
					flag2 = true;
					break;
				}
			}
			if (flag2)
			{
				num4++;
				continue;
			}
			pos = ((RaycastHit)(ref val4)).point;
			normal = ((RaycastHit)(ref val4)).normal;
			col = ((RaycastHit)(ref val4)).collider;
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("Weak spot placed on " + ((Object)((RaycastHit)(ref val4)).collider).name + " a " + ((RaycastHit)(ref val4)).distance.ToString("0.0") + " m from the eyes."));
			}
			return true;
		}
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("No place found for the weak spot: no hit=" + num + ", blocked=" + num2 + ((num2 > 0) ? (" by " + text) : "") + ", far=" + num3 + ", near another=" + num4));
		}
		return false;
	}

	public Color CurrentColor()
	{
		//IL_0030: 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 (Plugin.SpotColor.Value != SpotColorOption.Blue)
		{
			return new Color(1f, 0.78f, 0.25f);
		}
		return new Color(0.35f, 0.75f, 1f);
	}

	private WeakSpot CreateSpot()
	{
		return new WeakSpot(this);
	}

	private static Mesh MakeQuadMesh()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//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_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: 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_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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		Mesh val = new Mesh();
		((Object)val).name = "OreWeakSpots_Quad";
		val.vertices = (Vector3[])(object)new Vector3[4]
		{
			new Vector3(-0.5f, -0.5f, 0f),
			new Vector3(0.5f, -0.5f, 0f),
			new Vector3(-0.5f, 0.5f, 0f),
			new Vector3(0.5f, 0.5f, 0f)
		};
		val.uv = (Vector2[])(object)new Vector2[4]
		{
			new Vector2(0f, 0f),
			new Vector2(1f, 0f),
			new Vector2(0f, 1f),
			new Vector2(1f, 1f)
		};
		val.triangles = new int[6] { 0, 2, 1, 2, 3, 1 };
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	public GameObject MakeSphere(string name, Transform parent, float diameter)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Expected O, but got Unknown
		GameObject val = new GameObject(name);
		val.transform.SetParent(parent, false);
		val.transform.localScale = Vector3.one * diameter;
		val.AddComponent<MeshFilter>().sharedMesh = _sphereMesh;
		MeshRenderer val2 = val.AddComponent<MeshRenderer>();
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)val2).receiveShadows = false;
		if ((Object)(object)_shader != (Object)null && (Object)(object)_sphereMesh != (Object)null)
		{
			Material val3 = new Material(_shader);
			val3.mainTexture = (Texture)(object)Texture2D.whiteTexture;
			val3.renderQueue = 3101;
			((Renderer)val2).material = val3;
		}
		else
		{
			((Renderer)val2).enabled = false;
		}
		return val;
	}

	public GameObject MakeQuad(string name, Transform parent, float size)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Expected O, but got Unknown
		GameObject val = new GameObject(name);
		val.transform.SetParent(parent, false);
		val.transform.localScale = Vector3.one * size;
		val.AddComponent<MeshFilter>().sharedMesh = _quadMesh;
		MeshRenderer val2 = val.AddComponent<MeshRenderer>();
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)val2).receiveShadows = false;
		if ((Object)(object)_shader != (Object)null)
		{
			Material val3 = new Material(_shader);
			val3.mainTexture = (Texture)(object)_glowTex;
			val3.renderQueue = 3100;
			((Renderer)val2).material = val3;
		}
		else
		{
			((Renderer)val2).enabled = false;
		}
		return val;
	}

	public static bool IsRecentCrit(Vector3 pos)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		if (Time.time - _lastCritTime < 1.5f)
		{
			Vector3 val = pos - _lastCritPos;
			return ((Vector3)(ref val)).sqrMagnitude < 16f;
		}
		return false;
	}

	private void PlayCritEffects(Vector3 pos, Color color)
	{
		//IL_000a: 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: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		_lastCritTime = Time.time;
		_lastCritPos = pos;
		GameObject val = new GameObject("OreWeakSpots_Burst");
		val.transform.position = pos;
		val.AddComponent<CritBurst>().Init(this, color);
		PlayCritSound();
	}

	private void PlayCritSound()
	{
		float value = Plugin.SoundVolume.Value;
		CritSoundOption value2 = Plugin.CritSound.Value;
		if (value <= 0f || value2 == CritSoundOption.None)
		{
			return;
		}
		FindGameCritSound();
		List<AudioClip> list = null;
		switch (value2)
		{
		case CritSoundOption.Auto:
			list = ((_fileClips.Count > 0) ? _fileClips : ((_gameClips.Count > 0) ? _gameClips : null));
			break;
		case CritSoundOption.File:
			list = ((_fileClips.Count > 0) ? _fileClips : null);
			break;
		case CritSoundOption.Game:
			list = ((_gameClips.Count > 0) ? _gameClips : null);
			break;
		}
		AudioClip val = ((list != null) ? list[Random.Range(0, list.Count)] : _critClip);
		AudioSource playerAudio = GetPlayerAudio();
		if (!((Object)(object)playerAudio == (Object)null) && !((Object)(object)val == (Object)null))
		{
			playerAudio.pitch = Random.Range(0.95f, 1.05f);
			playerAudio.PlayOneShot(val, value);
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("Crit sound: " + ((Object)val).name));
			}
		}
	}

	private AudioSource GetPlayerAudio()
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_0057: 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)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return null;
		}
		if ((Object)(object)_playerAudio != (Object)null && (Object)(object)_audioOwner == (Object)(object)localPlayer)
		{
			return _playerAudio;
		}
		GameObject val = new GameObject("OreWeakSpots_SFX");
		val.transform.SetParent(((Component)localPlayer).transform, false);
		val.transform.localPosition = Vector3.up * 1.5f;
		_playerAudio = val.AddComponent<AudioSource>();
		_playerAudio.playOnAwake = false;
		_playerAudio.loop = false;
		_playerAudio.spatialBlend = 0f;
		_playerAudio.outputAudioMixerGroup = (((Object)(object)_mixerGroup != (Object)null) ? _mixerGroup : FindAnyMixerGroup(localPlayer));
		_audioOwner = localPlayer;
		return _playerAudio;
	}

	private static AudioMixerGroup FindAnyMixerGroup(Player p)
	{
		AudioSource[] componentsInChildren = ((Component)p).GetComponentsInChildren<AudioSource>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			if ((Object)(object)componentsInChildren[i].outputAudioMixerGroup != (Object)null)
			{
				return componentsInChildren[i].outputAudioMixerGroup;
			}
		}
		return null;
	}

	private void FindGameCritSound()
	{
		if (_gameSoundSearched || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return;
		}
		_gameSoundSearched = true;
		string[] array = new string[6] { "Greydwarf", "Skeleton", "Draugr", "Troll", "Boar", "Deer" };
		for (int i = 0; i < array.Length; i++)
		{
			if (_gameClips.Count != 0)
			{
				break;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(array[i]);
			if ((Object)(object)prefab == (Object)null)
			{
				continue;
			}
			Character component = prefab.GetComponent<Character>();
			if ((Object)(object)component == (Object)null || component.m_critHitEffects == null || component.m_critHitEffects.m_effectPrefabs == null)
			{
				continue;
			}
			EffectData[] effectPrefabs = component.m_critHitEffects.m_effectPrefabs;
			for (int j = 0; j < effectPrefabs.Length; j++)
			{
				if ((Object)(object)effectPrefabs[j].m_prefab != (Object)null)
				{
					CollectClips(effectPrefabs[j].m_prefab);
				}
			}
		}
		Plugin.Log.LogInfo((object)("Game stagger sound: " + _gameClips.Count + " clip(s)" + (((Object)(object)_mixerGroup != (Object)null) ? (", channel " + ((Object)_mixerGroup).name) : ", no audio channel")));
	}

	private void CollectClips(GameObject fx)
	{
		Component[] componentsInChildren = fx.GetComponentsInChildren<Component>(true);
		foreach (Component val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			FieldInfo fieldInfo = FindField(((object)val).GetType(), "m_audioClips");
			if (fieldInfo != null && fieldInfo.GetValue(val) is AudioClip[] array)
			{
				for (int j = 0; j < array.Length; j++)
				{
					if ((Object)(object)array[j] != (Object)null && !_gameClips.Contains(array[j]))
					{
						_gameClips.Add(array[j]);
					}
				}
			}
			AudioSource val2 = (AudioSource)(object)((val is AudioSource) ? val : null);
			if ((Object)(object)val2 != (Object)null)
			{
				if ((Object)(object)val2.clip != (Object)null && !_gameClips.Contains(val2.clip))
				{
					_gameClips.Add(val2.clip);
				}
				if ((Object)(object)_mixerGroup == (Object)null && (Object)(object)val2.outputAudioMixerGroup != (Object)null)
				{
					_mixerGroup = val2.outputAudioMixerGroup;
				}
			}
		}
	}

	private IEnumerator LoadSoundFiles()
	{
		string dir = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "SFX");
		if (!Directory.Exists(dir))
		{
			try
			{
				Directory.CreateDirectory(dir);
				yield break;
			}
			catch
			{
				yield break;
			}
		}
		string[] files = Directory.GetFiles(dir);
		for (int i = 0; i < files.Length; i++)
		{
			string ext = Path.GetExtension(files[i]).ToLowerInvariant();
			AudioType type = (AudioType)((ext == ".wav") ? 20 : ((ext == ".ogg") ? 14 : 0));
			if ((int)type == 0)
			{
				continue;
			}
			UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file:///" + files[i].Replace('\\', '/'), type);
			try
			{
				yield return req.SendWebRequest();
				AudioClip clip = (((int)req.result == 1) ? DownloadHandlerAudioClip.GetContent(req) : null);
				if ((Object)(object)clip != (Object)null)
				{
					((Object)clip).name = Path.GetFileNameWithoutExtension(files[i]);
					_fileClips.Add(clip);
					Plugin.Log.LogInfo((object)("Sound loaded: " + Path.GetFileName(files[i])));
				}
				else
				{
					Plugin.Log.LogWarning((object)("Could not load sound " + files[i] + ": " + req.error));
				}
			}
			finally
			{
				((IDisposable)req)?.Dispose();
			}
		}
	}

	private static Texture2D MakeGlowTexture(int size)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		float num = (float)(size - 1) / 2f;
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				float num2 = Mathf.Sqrt(((float)j - num) * ((float)j - num) + ((float)i - num) * ((float)i - num)) / num;
				float num3 = Mathf.Clamp01(1f - num2 * 3f);
				float num4 = Mathf.Pow(Mathf.Clamp01(1f - num2), 2.2f);
				float num5 = Mathf.Clamp01(num4 * 0.8f + num3);
				val.SetPixel(j, i, new Color(1f, 1f, 1f, num5));
			}
		}
		val.Apply();
		return val;
	}

	private static AudioClip MakeCritClip()
	{
		int num = 44100;
		int num2 = (int)((float)num * 0.35f);
		float[] array = new float[num2];
		for (int i = 0; i < num2; i++)
		{
			float num3 = (float)i / (float)num;
			float num4 = Mathf.Exp((0f - num3) * 14f);
			float num5 = Mathf.Clamp01(num3 * 400f);
			array[i] = num5 * num4 * (0.55f * Mathf.Sin((float)Math.PI * 3136f * num3) + 0.3f * Mathf.Sin((float)Math.PI * 4698f * num3) + 0.15f * Mathf.Sin((float)Math.PI * 6272f * num3));
		}
		AudioClip val = AudioClip.Create("OreWeakSpots_Crit", num2, 1, num, false);
		val.SetData(array, 0);
		return val;
	}
}
public class WeakSpot
{
	private const float FadeIn = 0.5f;

	private const float FadeOut = 0.7f;

	private readonly WeakSpotManager _mgr;

	private readonly GameObject _root;

	private readonly Transform _orb;

	private readonly Transform _halo;

	private readonly Material _orbMat;

	private readonly Material _haloMat;

	private readonly Light _light;

	private readonly float _orbSize;

	private readonly float _haloSize;

	private Collider _surface;

	private Vector3 _normal = Vector3.up;

	private float _bornAt;

	private float _lifetime;

	private bool _placed;

	private float _retryAt;

	public Color Color { get; private set; }

	public Vector3 Position => _orb.position;

	public bool IsPlaced => _placed;

	public bool IsHittable
	{
		get
		{
			if (_placed)
			{
				return Time.time >= _bornAt;
			}
			return false;
		}
	}

	public WeakSpot(WeakSpotManager mgr)
	{
		//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_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		_mgr = mgr;
		_root = new GameObject("OreWeakSpot");
		float value = Plugin.SpotSize.Value;
		_orbSize = 0.16f * value;
		_haloSize = 0.55f * value;
		GameObject val = mgr.MakeSphere("Orb", _root.transform, _orbSize);
		GameObject val2 = mgr.MakeQuad("Halo", _root.transform, _haloSize);
		_orb = val.transform;
		_halo = val2.transform;
		_orbMat = ((Renderer)val.GetComponent<MeshRenderer>()).material;
		_haloMat = ((Renderer)val2.GetComponent<MeshRenderer>()).material;
		_light = val.AddComponent<Light>();
		_light.type = (LightType)2;
		_light.range = 1.3f;
		_light.shadows = (LightShadows)0;
		_root.SetActive(false);
	}

	public void Relocate(float delay)
	{
		_placed = false;
		_root.SetActive(false);
		_retryAt = Time.time + delay;
	}

	private void TryPlace()
	{
		//IL_0031: 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_004d: 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_0061: Unknown result type (might be due to invalid IL or missing references)
		if (!_mgr.FindSurfacePoint(this, out var pos, out var normal, out var col))
		{
			_retryAt = Time.time + 0.5f;
			return;
		}
		_root.transform.position = pos;
		_root.transform.rotation = Quaternion.identity;
		_normal = normal;
		_surface = col;
		Color = _mgr.CurrentColor();
		_lifetime = Plugin.SpotLifetime.Value * Random.Range(0.85f, 1.15f);
		_bornAt = Time.time;
		_placed = true;
		_root.SetActive(true);
	}

	public void Tick(Camera cam)
	{
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		if (!_placed)
		{
			if (Time.time >= _retryAt)
			{
				TryPlace();
			}
			return;
		}
		if ((Object)(object)_surface == (Object)null || !_surface.enabled || !((Component)_surface).gameObject.activeInHierarchy)
		{
			Relocate(0.2f);
			return;
		}
		float num = Time.time - _bornAt;
		if (num > _lifetime)
		{
			Relocate(0.4f);
			return;
		}
		float num2 = Mathf.SmoothStep(0f, 1f, num / 0.5f);
		float num3 = Mathf.SmoothStep(0f, 1f, (_lifetime - num) / 0.7f);
		float num4 = num2 * num3;
		float num5 = 0.8f + 0.2f * Mathf.Sin(num * 6f);
		float num6 = Mathf.Lerp(0.3f, 1f, num4);
		float num7 = _orbSize * num6 * (0.95f + 0.05f * num5);
		_orb.localPosition = _normal * (num7 * 0.35f);
		_orb.localScale = Vector3.one * num7;
		_halo.localPosition = _orb.localPosition;
		_halo.localScale = Vector3.one * (_haloSize * num6 * num5);
		Color color = Color;
		_orbMat.color = new Color(Mathf.Lerp(color.r, 1f, 0.45f), Mathf.Lerp(color.g, 1f, 0.45f), Mathf.Lerp(color.b, 1f, 0.45f), num4);
		_haloMat.color = new Color(color.r, color.g, color.b, 0.55f * num4 * num5);
		_light.color = color;
		_light.intensity = 1.8f * num4 * num5;
		if ((Object)(object)cam != (Object)null)
		{
			_halo.rotation = ((Component)cam).transform.rotation;
		}
	}

	public void Destroy()
	{
		Object.Destroy((Object)(object)_root);
		Object.Destroy((Object)(object)_orbMat);
		Object.Destroy((Object)(object)_haloMat);
	}
}
public class CritBurst : MonoBehaviour
{
	private const float Duration = 0.4f;

	private float _start;

	private Material _mat;

	private Light _light;

	private Color _color;

	private Transform _quad;

	public void Init(WeakSpotManager mgr, Color color)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		_start = Time.time;
		_color = color;
		GameObject val = mgr.MakeQuad("Flash", ((Component)this).transform, 0.4f);
		_quad = val.transform;
		_mat = ((Renderer)val.GetComponent<MeshRenderer>()).material;
		_light = ((Component)this).gameObject.AddComponent<Light>();
		_light.type = (LightType)2;
		_light.range = 3f;
		_light.color = color;
		_light.shadows = (LightShadows)0;
	}

	private void Update()
	{
		//IL_0040: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		float num = (Time.time - _start) / 0.4f;
		if (num >= 1f)
		{
			Object.Destroy((Object)(object)_mat);
			Object.Destroy((Object)(object)((Component)this).gameObject);
			return;
		}
		float num2 = 1f - num;
		_quad.localScale = Vector3.one * Mathf.Lerp(0.4f, 1.6f, num);
		_mat.color = new Color(Mathf.Lerp(_color.r, 1f, 0.4f), Mathf.Lerp(_color.g, 1f, 0.4f), Mathf.Lerp(_color.b, 1f, 0.4f), num2);
		_light.intensity = 5f * num2;
		Camera main = Camera.main;
		if ((Object)(object)main != (Object)null)
		{
			((Component)this).transform.rotation = ((Component)main).transform.rotation;
		}
	}
}