Decompiled source of TreeWeakSpots v0.9.2

plugins/TreeWeakSpots/TreeWeakSpots.dll

Decompiled 14 hours 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 TreeWeakSpots;

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

	public const string NAME = "Tree Weak Spots";

	public const string VERSION = "0.9.2";

	private const string ComboChoppingId = "diffByDefault.ComboChopping";

	public static ManualLogSource Log;

	public static ConfigEntry<bool> Enabled;

	public static ConfigEntry<float> CritMultiplier;

	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<float> MinSpacing;

	public static ConfigEntry<SpotColorOption> SpotColor;

	public static ConfigEntry<float> BandWidth;

	public static ConfigEntry<float> SoundVolume;

	public static ConfigEntry<CritSoundOption> CritSound;

	public static ConfigEntry<CritNumberColorOption> CritNumberColor;

	public static ConfigEntry<float> CritNumberScale;

	public static ConfigEntry<bool> SledgeSwing;

	public static ConfigEntry<string> SwingSource;

	public static ConfigEntry<float> SwingSpeed;

	public static ConfigEntry<bool> BlockComboChopping;

	public static ConfigEntry<bool> DebugLog;

	private Harmony _harmony;

	private void Start()
	{
		if (!BlockComboChopping.Value)
		{
			return;
		}
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(TreeLog), "Damage", (Type[])null, (Type[])null);
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo != null && patchInfo.Owners.Contains("diffByDefault.ComboChopping"))
			{
				_harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)0, "diffByDefault.ComboChopping");
				Log.LogInfo((object)"ComboChopping turned off on fallen logs (still active on standing trees).");
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not adjust ComboChopping: " + ex.Message));
		}
	}

	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_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Expected O, but got Unknown
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Expected O, but got Unknown
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Expected O, but got Unknown
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Expected O, but got Unknown
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Expected O, but got Unknown
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Expected O, but got Unknown
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0268: Expected O, but got Unknown
		//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e6: Expected O, but got Unknown
		//IL_035e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0368: Expected O, but got Unknown
		//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b8: Expected O, but got Unknown
		//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d5: 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("Axe damage multiplier when you hit a band.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), new object[0]));
		SpotCount = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Weak spots", "Count", 1, new ConfigDescription("How many glowing bands appear on the fallen log at the same time.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), new object[0]));
		MinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "MinSpacing", 1.2f, new ConfigDescription("Minimum distance (meters) between two bands.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 5f), new object[0]));
		HitTolerance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Weak spots", "HitTolerance", 0.35f, new ConfigDescription("Maximum distance (meters) along the log between the hit and the band's center 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 band 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 band can appear.", (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 log before the bands disappear.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 60f), new object[0]));
		SpotColor = ((BaseUnityPlugin)this).Config.Bind<SpotColorOption>("3 - Visuals", "Color", SpotColorOption.Gold, "Band color.");
		BandWidth = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Visuals", "BandWidth", 0.3f, new ConfigDescription("Width of the glowing band, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), new object[0]));
		SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Visuals", "SoundVolume", 1f, new ConfigDescription("Crit sound volume (0 = off).", (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/TreeWeakSpots/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]));
		SledgeSwing = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Swing", "SledgeSwing", true, "Axe swings aimed at a fallen log use the sledgehammer's overhead strike. With a shield, torch or any other item in the off hand, the whole mod stays off. Everywhere else (standing trees, combat) the axe works as usual.");
		SwingSource = ((BaseUnityPlugin)this).Config.Bind<string>("4 - Swing", "SwingSource", "SledgeStagbreaker", "Name of the item the swing animation is copied from (default: the Stagbreaker sledge).");
		SwingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Swing", "SwingSpeed", 1.3f, new ConfigDescription("Speed of the overhead strike on fallen logs (1 = the sledge's own speed, 1.3 = 30% faster). Each swing still costs the same stamina.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 2f), new object[0]));
		BlockComboChopping = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Swing", "ComboChoppingStandingTreesOnly", true, "With the ComboChopping mod installed, it keeps working on standing trees but no longer changes the damage and combo on fallen logs, where only Tree Weak Spots applies. Restart the game after changing this.");
		DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "DetailedLog", false, "Writes each hit, the log's size and the swing animation swap to the BepInEx log.");
		GameObject val = new GameObject("TreeWeakSpots_Manager");
		Object.DontDestroyOnLoad((Object)(object)val);
		val.AddComponent<WeakSpotManager>();
		_harmony = new Harmony("felih.TreeWeakSpots");
		_harmony.PatchAll(typeof(Plugin).Assembly);
		Log.LogInfo((object)"Tree Weak Spots 0.9.2 loaded.");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
[HarmonyPatch(typeof(TreeLog), "Damage")]
internal static class TreeLogDamagePatch
{
	private static void Prefix(TreeLog __instance, HitData __0)
	{
		WeakSpotManager.OnAxeHit(__instance, __0);
	}
}
[HarmonyPatch]
internal static class SledgeSwingPatch
{
	private class Saved
	{
		public Attack Attack;

		public string Animation;

		public int Chain;

		public int Random;

		public AttackType Type;
	}

	private static string _anim;

	private static int _chain = 1;

	private static int _random;

	private static bool _looked;

	private static float _lastLog = -10f;

	private static MethodBase TargetMethod()
	{
		foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(Humanoid)))
		{
			if (declaredMethod.Name == "StartAttack")
			{
				return declaredMethod;
			}
		}
		return null;
	}

	private static void FindSledge()
	{
		if (!_looked && !((Object)(object)ObjectDB.instance == (Object)null))
		{
			_looked = true;
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(Plugin.SwingSource.Value);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null && val.m_itemData.m_shared.m_attack != null)
			{
				Attack attack = val.m_itemData.m_shared.m_attack;
				_anim = attack.m_attackAnimation;
				_chain = attack.m_attackChainLevels;
				_random = attack.m_attackRandomAnimations;
			}
			Plugin.Log.LogInfo((object)("Sledge animation: " + (_anim ?? "not found") + " (combo " + _chain + ")"));
		}
	}

	private static void Prefix(Humanoid __instance, ref Saved __state)
	{
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		__state = null;
		if (!Plugin.Enabled.Value || !Plugin.SledgeSwing.Value)
		{
			return;
		}
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !WeakSpotManager.ModActive(val) || !WeakSpotManager.CanUseSledgeSwing(val))
		{
			return;
		}
		FindSledge();
		if (string.IsNullOrEmpty(_anim))
		{
			return;
		}
		Attack attack = ((Humanoid)val).GetCurrentWeapon().m_shared.m_attack;
		if (attack != null)
		{
			__state = new Saved
			{
				Attack = attack,
				Animation = attack.m_attackAnimation,
				Chain = attack.m_attackChainLevels,
				Random = attack.m_attackRandomAnimations,
				Type = attack.m_attackType
			};
			attack.m_attackAnimation = _anim;
			attack.m_attackChainLevels = _chain;
			attack.m_attackRandomAnimations = _random;
			attack.m_attackType = (AttackType)1;
			if (Plugin.DebugLog.Value && Time.time - _lastLog > 0.8f)
			{
				_lastLog = Time.time;
				Plugin.Log.LogInfo((object)("Sledge swing on log (" + _anim + ")"));
			}
		}
	}

	private static void Postfix(Humanoid __instance, Saved __state, bool __result)
	{
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
		{
			if (__state != null)
			{
				SwingSpeedPatch.Begin((Player)__instance);
			}
			else
			{
				SwingSpeedPatch.End();
			}
		}
		if (__state != null)
		{
			__state.Attack.m_attackAnimation = __state.Animation;
			__state.Attack.m_attackChainLevels = __state.Chain;
			__state.Attack.m_attackRandomAnimations = __state.Random;
			__state.Attack.m_attackType = __state.Type;
		}
	}
}
[HarmonyPatch]
internal static class SwingSpeedPatch
{
	private static readonly FieldInfo AnimatorField = AccessTools.Field(typeof(CharacterAnimEvent), "m_animator");

	private static readonly FieldInfo CharacterField = AccessTools.Field(typeof(CharacterAnimEvent), "m_character");

	private static bool _active;

	private static Animator AnimatorOf(CharacterAnimEvent ev)
	{
		if (!(AnimatorField != null))
		{
			return null;
		}
		object? value = AnimatorField.GetValue(ev);
		return (Animator)((value is Animator) ? value : null);
	}

	internal static void Begin(Player p)
	{
		float value = Plugin.SwingSpeed.Value;
		if (value <= 1.001f)
		{
			_active = false;
			return;
		}
		CharacterAnimEvent componentInChildren = ((Component)p).GetComponentInChildren<CharacterAnimEvent>();
		Animator val = (((Object)(object)componentInChildren != (Object)null) ? AnimatorOf(componentInChildren) : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		if (!_active)
		{
			val.speed *= value;
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("Swing speed x" + value.ToString("0.00") + " (animator " + val.speed.ToString("0.00") + ")"));
			}
		}
		_active = true;
	}

	internal static void End()
	{
		_active = false;
	}

	private static bool Mine(CharacterAnimEvent ev)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		if (CharacterField != null && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			return (Object)(Character)CharacterField.GetValue(ev) == (Object)(object)Player.m_localPlayer;
		}
		return false;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(CharacterAnimEvent), "Speed")]
	private static void EventSpeed(CharacterAnimEvent __instance)
	{
		if (_active && Mine(__instance))
		{
			Animator val = AnimatorOf(__instance);
			if ((Object)(object)val != (Object)null)
			{
				val.speed *= Plugin.SwingSpeed.Value;
			}
		}
	}

	[HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")]
	[HarmonyPostfix]
	private static void AfterUpdate(CharacterAnimEvent __instance)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		if (_active && Mine(__instance))
		{
			Character val = (Character)CharacterField.GetValue(__instance);
			if (!val.InAttack())
			{
				_active = false;
			}
		}
	}
}
[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 TreeLog _target;

	private float _lastSeenTime;

	private float _nextScan;

	private readonly List<LogRing> _rings = new List<LogRing>();

	private int _critFrame = -1;

	private Transform _meshT;

	private Vector3 _centerLocal;

	private Vector3 _axisLocal;

	private float _halfLenLocal;

	private float _radiusLocal;

	private Texture2D _glowTex;

	private Texture2D _bandTex;

	private Mesh _quadMesh;

	private Shader _shader;

	private AudioClip _critClip;

	private static FieldInfo _leftItemField;

	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 Transform MeshTransform => _meshT;

	public Shader BandShader => _shader;

	public Texture2D BandTexture => _bandTex;

	public Vector3 AxisLocal => _axisLocal;

	public float RadiusLocal => _radiusLocal;

	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);
		_bandTex = MakeBandTexture(64);
		_quadMesh = MakeQuadMesh();
		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 band's light will be visible.");
		}
		_critClip = MakeCritClip();
		((MonoBehaviour)this).StartCoroutine(LoadSoundFiles());
	}

	public static void OnAxeHit(TreeLog log, HitData hit)
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Invalid comparison between Unknown and I4
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Invalid comparison between Unknown and I4
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_inst == (Object)null || hit == null || (Object)(object)log == (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";
			}
			else if ((int)hit.m_skill != 13 && (int)hit.m_skill != 7)
			{
				text = string.Concat("tool is not an axe (", hit.m_skill, ")");
			}
			else if (!HoldingAxe(localPlayer))
			{
				text = "not holding an axe";
			}
			else if (!ModActive(localPlayer))
			{
				text = "off hand is busy (" + OffHandItem(localPlayer).m_shared.m_name + ")";
			}
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("Hit on log " + ((Object)log).name + ": " + ((text == null) ? "accepted" : ("ignored, " + text))));
			}
			if (text == null)
			{
				_inst.HandleHit(log, hit);
			}
		}
	}

	public static bool CanUseSledgeSwing(Player player)
	{
		return (Object)(object)LogUnderCrosshair(player) != (Object)null;
	}

	private static TreeLog LogUnderCrosshair(Player player)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		GameObject hoverObject = ((Humanoid)player).GetHoverObject();
		if ((Object)(object)hoverObject != (Object)null)
		{
			TreeLog componentInParent = hoverObject.GetComponentInParent<TreeLog>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent;
			}
		}
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			return null;
		}
		Vector3 position = ((Component)main).transform.position;
		Vector3 forward = ((Component)main).transform.forward;
		float num = Vector3.Distance(position, ((Character)player).GetEyePoint()) + 4f;
		TreeLog val = FirstLog(player, Physics.RaycastAll(position, forward, num, -1, (QueryTriggerInteraction)1));
		if ((Object)(object)val == (Object)null)
		{
			val = FirstLog(player, Physics.SphereCastAll(position, 0.35f, forward, num, -1, (QueryTriggerInteraction)1));
		}
		return val;
	}

	private static TreeLog FirstLog(Player player, RaycastHit[] hits)
	{
		Array.Sort(hits, (RaycastHit h1, RaycastHit h2) => ((RaycastHit)(ref h1)).distance.CompareTo(((RaycastHit)(ref h2)).distance));
		for (int num = 0; num < hits.Length; num++)
		{
			Collider collider = ((RaycastHit)(ref hits[num])).collider;
			if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)player).transform))
			{
				TreeLog componentInParent = ((Component)collider).GetComponentInParent<TreeLog>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					return componentInParent;
				}
				if ((Object)(object)((Component)collider).GetComponentInParent<Heightmap>() != (Object)null)
				{
					return null;
				}
				if ((Object)(object)((Component)collider).GetComponentInParent<WearNTear>() != (Object)null || (Object)(object)((Component)collider).GetComponentInParent<MineRock5>() != (Object)null)
				{
					return null;
				}
			}
		}
		return null;
	}

	public static bool AimingAtLog(Player player)
	{
		return (Object)(object)LogUnderCrosshair(player) != (Object)null;
	}

	public static bool HoldingAxe(Player player)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: 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 == 7;
		}
		return false;
	}

	public static ItemData OffHandItem(Player player)
	{
		if (_leftItemField == null)
		{
			_leftItemField = FindField(typeof(Humanoid), "m_leftItem");
		}
		if (!(_leftItemField != null))
		{
			return null;
		}
		object? value = _leftItemField.GetValue(player);
		return (ItemData)((value is ItemData) ? value : null);
	}

	public static bool ModActive(Player player)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_001e: Invalid comparison between Unknown and I4
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Invalid comparison between Unknown and I4
		if (!HoldingAxe(player))
		{
			return false;
		}
		ItemType itemType = ((Humanoid)player).GetCurrentWeapon().m_shared.m_itemType;
		if ((int)itemType == 14 || (int)itemType == 22)
		{
			return true;
		}
		return OffHandItem(player) == null;
	}

	private void HandleHit(TreeLog log, HitData hit)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: 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)log)
		{
			ApplyCrit(hit);
			return;
		}
		if ((Object)(object)_target != (Object)(object)log)
		{
			SetTarget(log);
			return;
		}
		LogRing logRing = null;
		float num = float.MaxValue;
		for (int i = 0; i < _rings.Count; i++)
		{
			LogRing logRing2 = _rings[i];
			if (logRing2.IsHittable)
			{
				float num2 = AxialDistance(logRing2.T, hit.m_point);
				if (num2 < num)
				{
					num = num2;
					logRing = logRing2;
				}
			}
		}
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Distance from hit to nearest band = " + ((logRing == null) ? "no band" : (num.ToString("0.00") + " m"))));
		}
		if (logRing != null && num <= Plugin.HitTolerance.Value)
		{
			_critFrame = Time.frameCount;
			ApplyCrit(hit);
			PlayCritEffects(hit.m_point, logRing.Color);
			logRing.Relocate(0.5f);
		}
	}

	private void ApplyCrit(HitData hit)
	{
		float chop = hit.m_damage.m_chop;
		ref DamageTypes damage = ref hit.m_damage;
		damage.m_chop *= Plugin.CritMultiplier.Value;
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Crit: chop damage " + chop.ToString("0.0") + " → " + hit.m_damage.m_chop.ToString("0.0") + " (x" + Plugin.CritMultiplier.Value.ToString("0.##") + ")"));
		}
	}

	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: chop " + hit.m_damage.m_chop.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 bool Measure(TreeLog log)
	{
		//IL_00c3: 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_00cc: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: 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_0137: 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_0142: 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_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		MeshFilter[] componentsInChildren = ((Component)log).GetComponentsInChildren<MeshFilter>();
		MeshFilter val = null;
		float num = 0f;
		foreach (MeshFilter val2 in componentsInChildren)
		{
			if ((Object)(object)val2.sharedMesh == (Object)null || !((Component)val2).gameObject.activeInHierarchy)
			{
				continue;
			}
			MeshRenderer component = ((Component)val2).GetComponent<MeshRenderer>();
			if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled)
			{
				Bounds bounds = val2.sharedMesh.bounds;
				Vector3 val3 = Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)val2).transform.lossyScale);
				float num2 = Mathf.Abs(val3.x * val3.y * val3.z);
				if (num2 > num)
				{
					num = num2;
					val = val2;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		Bounds bounds2 = val.sharedMesh.bounds;
		Vector3 size = ((Bounds)(ref bounds2)).size;
		Vector3 val4 = Vector3.Scale(size, ((Component)val).transform.lossyScale);
		int num3 = 0;
		if (Mathf.Abs(val4.y) > Mathf.Abs(((Vector3)(ref val4))[num3]))
		{
			num3 = 1;
		}
		if (Mathf.Abs(val4.z) > Mathf.Abs(((Vector3)(ref val4))[num3]))
		{
			num3 = 2;
		}
		_meshT = ((Component)val).transform;
		_centerLocal = ((Bounds)(ref bounds2)).center;
		_axisLocal = Vector3.zero;
		((Vector3)(ref _axisLocal))[num3] = 1f;
		_halfLenLocal = ((Vector3)(ref size))[num3] * 0.5f;
		float num4 = ((Vector3)(ref size))[(num3 + 1) % 3] * 0.5f;
		float num5 = ((Vector3)(ref size))[(num3 + 2) % 3] * 0.5f;
		_radiusLocal = Mathf.Max(num4, num5);
		if (Plugin.DebugLog.Value)
		{
			Plugin.Log.LogInfo((object)("Log " + ((Object)log).name + ": length " + (AxisScale() * ((Vector3)(ref size))[num3]).ToString("0.0") + " m, radius " + (_radiusLocal * AxisScale()).ToString("0.00") + " m, mesh " + ((Object)val).name));
		}
		return true;
	}

	public float AxisScale()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_meshT != (Object)null))
		{
			return 1f;
		}
		Vector3 val = _meshT.TransformVector(_axisLocal);
		return ((Vector3)(ref val)).magnitude;
	}

	public Vector3 LocalPointAt(float t)
	{
		//IL_0001: 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_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		return _centerLocal + _axisLocal * t;
	}

	private float AxialDistance(float t, Vector3 worldPoint)
	{
		//IL_0006: 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_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_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = _meshT.InverseTransformPoint(worldPoint);
		float num = Vector3.Dot(val - _centerLocal, _axisLocal);
		return Mathf.Abs(num - t) * AxisScale();
	}

	public bool PickPosition(LogRing self, out float t)
	{
		//IL_0073: 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_0095: 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)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		t = 0f;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)_meshT == (Object)null)
		{
			return false;
		}
		float num = AxisScale();
		float num2 = Mathf.Min(_halfLenLocal * 0.4f, 0.3f / Mathf.Max(num, 0.001f));
		float num3 = 0f - _halfLenLocal + num2;
		float num4 = _halfLenLocal - num2;
		if (num4 <= num3)
		{
			num3 = (num4 = 0f);
		}
		Vector3 eyePoint = ((Character)localPlayer).GetEyePoint();
		for (int i = 0; i < 30; i++)
		{
			float num5 = Random.Range(num3, num4);
			Vector3 val = _meshT.TransformPoint(LocalPointAt(num5));
			if (Vector3.Distance(eyePoint, val) > Plugin.MaxDistance.Value)
			{
				continue;
			}
			bool flag = false;
			for (int j = 0; j < _rings.Count; j++)
			{
				LogRing logRing = _rings[j];
				if (logRing != self && logRing.IsPlaced && Mathf.Abs(logRing.T - num5) * num < Plugin.MinSpacing.Value)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				t = num5;
				return true;
			}
		}
		return false;
	}

	private void SetTarget(TreeLog log)
	{
		ClearRings();
		if (Measure(log))
		{
			_target = log;
			_lastSeenTime = Time.time;
			for (int i = 0; i < Plugin.SpotCount.Value; i++)
			{
				LogRing logRing = new LogRing(this);
				logRing.Relocate((float)i * 0.3f);
				_rings.Add(logRing);
			}
		}
	}

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

	private void Update()
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		if (((Object)(object)_target == (Object)null || (Object)(object)_meshT == (Object)null) && _rings.Count > 0)
		{
			ClearRings();
		}
		Player localPlayer = Player.m_localPlayer;
		if (!Plugin.Enabled.Value || (Object)(object)localPlayer == (Object)null || !ModActive(localPlayer))
		{
			if ((Object)(object)_target != (Object)null)
			{
				ClearRings();
			}
			return;
		}
		if (Time.time >= _nextScan)
		{
			_nextScan = Time.time + 0.1f;
			TreeLog val = LogUnderCrosshair(localPlayer);
			if ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)val != (Object)(object)_target)
				{
					SetTarget(val);
				}
				else
				{
					_lastSeenTime = Time.time;
				}
			}
		}
		if ((Object)(object)_target == (Object)null)
		{
			return;
		}
		bool flag = Vector3.Distance(((Component)localPlayer).transform.position, ((Component)_target).transform.position) > 15f;
		bool flag2 = Time.time - _lastSeenTime > Plugin.ActiveDuration.Value;
		if (flag || flag2)
		{
			ClearRings();
			return;
		}
		for (int i = 0; i < _rings.Count; i++)
		{
			_rings[i].Tick();
		}
	}

	public Color CurrentColor()
	{
		//IL_001b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
		if (Plugin.SpotColor.Value == SpotColorOption.Blue)
		{
			return new Color(0.35f, 0.75f, 1f);
		}
		if (Plugin.SpotColor.Value == SpotColorOption.Green)
		{
			return new Color(0.45f, 1f, 0.35f);
		}
		return new Color(1f, 0.78f, 0.25f);
	}

	public static Mesh MakeBandMesh(float r, float w)
	{
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: 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_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Expected O, but got Unknown
		Vector3[] array = (Vector3[])(object)new Vector3[98];
		Vector2[] array2 = (Vector2[])(object)new Vector2[array.Length];
		int[] array3 = new int[288];
		for (int i = 0; i <= 48; i++)
		{
			float num = (float)i / 48f * (float)Math.PI * 2f;
			float num2 = Mathf.Cos(num) * r;
			float num3 = Mathf.Sin(num) * r;
			ref Vector3 reference = ref array[i * 2];
			reference = new Vector3(num2, num3, (0f - w) * 0.5f);
			ref Vector3 reference2 = ref array[i * 2 + 1];
			reference2 = new Vector3(num2, num3, w * 0.5f);
			ref Vector2 reference3 = ref array2[i * 2];
			reference3 = new Vector2((float)i / 48f, 0f);
			ref Vector2 reference4 = ref array2[i * 2 + 1];
			reference4 = new Vector2((float)i / 48f, 1f);
		}
		for (int j = 0; j < 48; j++)
		{
			int num4 = j * 6;
			int num5 = (array3[num4] = j * 2);
			array3[num4 + 1] = num5 + 1;
			array3[num4 + 2] = num5 + 2;
			array3[num4 + 3] = num5 + 2;
			array3[num4 + 4] = num5 + 1;
			array3[num4 + 5] = num5 + 3;
		}
		Mesh val = new Mesh();
		((Object)val).name = "TreeWeakSpots_Band";
		val.vertices = array;
		val.uv = array2;
		val.triangles = array3;
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	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 = "TreeWeakSpots_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 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("TreeWeakSpots_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)
		{
			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);
			}
		}
	}

	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("TreeWeakSpots_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);
				}
			}
		}
	}

	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);
				}
			}
			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_0093: 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);
				val.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(num4 * 0.8f + num3)));
			}
		}
		val.Apply();
		return val;
	}

	private static Texture2D MakeBandTexture(int size)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(4, size, (TextureFormat)4, false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		for (int i = 0; i < size; i++)
		{
			float num = Mathf.Abs((float)i / (float)(size - 1) * 2f - 1f);
			float num2 = Mathf.Clamp01(1f - num * 2.5f);
			float num3 = Mathf.Pow(Mathf.Clamp01(1f - num), 1.8f);
			float num4 = Mathf.Clamp01(num3 * 0.75f + num2 * 0.6f);
			for (int j = 0; j < 4; j++)
			{
				val.SetPixel(j, i, new Color(1f, 1f, 1f, num4));
			}
		}
		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("TreeWeakSpots_Crit", num2, 1, num, false);
		val.SetData(array, 0);
		return val;
	}
}
public class LogRing
{
	private const float FadeIn = 0.5f;

	private const float FadeOut = 0.7f;

	private readonly WeakSpotManager _mgr;

	private GameObject _root;

	private Material _coreMat;

	private Material _haloMat;

	private Mesh _coreMesh;

	private Mesh _haloMesh;

	private Light _light;

	private float _t;

	private bool _placed;

	private float _bornAt;

	private float _lifetime;

	private float _retryAt;

	public float T => _t;

	public Color Color { get; private set; }

	public bool IsPlaced => _placed;

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

	public LogRing(WeakSpotManager mgr)
	{
		_mgr = mgr;
	}

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

	private void Build()
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		Transform meshTransform = _mgr.MeshTransform;
		float num = _mgr.AxisScale();
		float num2 = _mgr.RadiusLocal * 1.04f;
		float num3 = Plugin.BandWidth.Value / Mathf.Max(num, 0.001f);
		_root = new GameObject("TreeWeakSpot");
		_root.transform.SetParent(meshTransform, false);
		_root.transform.localRotation = Quaternion.FromToRotation(Vector3.forward, _mgr.AxisLocal);
		_coreMesh = WeakSpotManager.MakeBandMesh(num2, num3);
		_haloMesh = WeakSpotManager.MakeBandMesh(num2 * 1.06f, num3 * 2.6f);
		_coreMat = AddBand("Core", _coreMesh, 3101);
		_haloMat = AddBand("Halo", _haloMesh, 3100);
		_light = _root.AddComponent<Light>();
		_light.type = (LightType)2;
		_light.range = Mathf.Max(1.5f, num2 * num * 4f);
		_light.shadows = (LightShadows)0;
	}

	private Material AddBand(string name, Mesh mesh, int queue)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Expected O, but got Unknown
		GameObject val = new GameObject(name);
		val.transform.SetParent(_root.transform, false);
		val.AddComponent<MeshFilter>().sharedMesh = mesh;
		MeshRenderer val2 = val.AddComponent<MeshRenderer>();
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)val2).receiveShadows = false;
		if ((Object)(object)_mgr.BandShader == (Object)null)
		{
			((Renderer)val2).enabled = false;
			return null;
		}
		Material val3 = new Material(_mgr.BandShader);
		val3.mainTexture = (Texture)(object)_mgr.BandTexture;
		val3.renderQueue = queue;
		((Renderer)val2).material = val3;
		return val3;
	}

	private void TryPlace()
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_mgr.MeshTransform == (Object)null || !_mgr.PickPosition(this, out var t))
		{
			_retryAt = Time.time + 0.5f;
			return;
		}
		if ((Object)(object)_root == (Object)null)
		{
			Build();
		}
		_t = t;
		_root.transform.localPosition = _mgr.LocalPointAt(t);
		Color = _mgr.CurrentColor();
		_lifetime = Plugin.SpotLifetime.Value * Random.Range(0.85f, 1.15f);
		_bornAt = Time.time;
		_placed = true;
		_root.SetActive(true);
	}

	public void Tick()
	{
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: 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)
		if (!_placed)
		{
			if (Time.time >= _retryAt)
			{
				TryPlace();
			}
			return;
		}
		if ((Object)(object)_root == (Object)null)
		{
			_placed = false;
			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);
		_root.transform.localScale = new Vector3(1f, 1f, num6);
		Color color = Color;
		if ((Object)(object)_coreMat != (Object)null)
		{
			_coreMat.color = new Color(Mathf.Lerp(color.r, 1f, 0.5f), Mathf.Lerp(color.g, 1f, 0.5f), Mathf.Lerp(color.b, 1f, 0.5f), num4 * 0.95f);
		}
		if ((Object)(object)_haloMat != (Object)null)
		{
			_haloMat.color = new Color(color.r, color.g, color.b, 0.45f * num4 * num5);
		}
		_light.color = color;
		_light.intensity = 1.6f * num4 * num5;
	}

	public void Destroy()
	{
		if ((Object)(object)_root != (Object)null)
		{
			Object.Destroy((Object)(object)_root);
		}
		if ((Object)(object)_coreMat != (Object)null)
		{
			Object.Destroy((Object)(object)_coreMat);
		}
		if ((Object)(object)_haloMat != (Object)null)
		{
			Object.Destroy((Object)(object)_haloMat);
		}
		if ((Object)(object)_coreMesh != (Object)null)
		{
			Object.Destroy((Object)(object)_coreMesh);
		}
		if ((Object)(object)_haloMesh != (Object)null)
		{
			Object.Destroy((Object)(object)_haloMesh);
		}
	}
}
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;
		}
	}
}