Decompiled source of BetterOreMining v1.0.0

BetterOreMining.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BetterOreMining.Config;
using BetterOreMining.Features;
using BetterOreMining.Infrastructure;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BetterOreMining")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7c103c8b5af121683d895a79b51f152b3ba67084")]
[assembly: AssemblyProduct("BetterOreMining")]
[assembly: AssemblyTitle("BetterOreMining")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BetterOreMining
{
	[BepInPlugin("JevMods.BetterOreMining", "BetterOreMining", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "JevMods.BetterOreMining";

		public const string PluginName = "BetterOreMining";

		private IFeature[] _features;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			GameEvents events = (GameEvents.Instance = new GameEvents());
			_features = CreateFeatures(events, new ModSettings(((BaseUnityPlugin)this).Config), LoadShader());
			IFeature[] features = _features;
			for (int i = 0; i < features.Length; i++)
			{
				features[i].Enable();
			}
			_harmony = new Harmony("JevMods.BetterOreMining");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded");
		}

		private void Update()
		{
			GameEvents.Instance?.RaiseFrameUpdated();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if (_features != null)
			{
				IFeature[] features = _features;
				for (int i = 0; i < features.Length; i++)
				{
					features[i].Disable();
				}
			}
			GameEvents.Instance = null;
		}

		private Shader LoadShader()
		{
			return ShaderBundle.Load(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "assets", "betteroremining"));
		}

		private static IFeature[] CreateFeatures(IGameEvents events, ModSettings settings, Shader rippleShader)
		{
			OreReachFeature oreReachFeature = new OreReachFeature(events, new PhysicsOreScanner());
			if (!((Object)(object)rippleShader == (Object)null))
			{
				RippleFeature rippleFeature = new RippleFeature(events, settings, new PhysicsVeinScanner(), new ZoneGroundProbe(), new OverlayGlowRenderer(rippleShader, settings, new GroundTextures()));
				return new IFeature[2] { rippleFeature, oreReachFeature };
			}
			return new IFeature[1] { oreReachFeature };
		}
	}
	internal static class BuildInfo
	{
		public const string Version = "1.0.0";
	}
}
namespace BetterOreMining.Patches
{
	internal static class AttackPatches
	{
		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static class DoMeleeAttack
		{
			private static void Prefix(Attack __instance)
			{
				GameEvents.Instance?.RaiseMeleeAttackStarting(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "AddHitPoint")]
		private static class AddHitPoint
		{
			private static void Postfix(Attack __instance, GameObject go, Vector3 point)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				if (IsLocalPickaxe(__instance) && !IsDynamic(go))
				{
					GameEvents.Instance?.RaisePickaxeStruck(point);
				}
			}

			private static bool IsLocalPickaxe(Attack attack)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Invalid comparison between Unknown and I4
				bool num = (Object)(object)attack.m_character == (Object)(object)Player.m_localPlayer;
				ItemData weapon = attack.m_weapon;
				bool flag = weapon != null && (int)weapon.m_shared.m_skillType == 12;
				return num && flag;
			}

			private static bool IsDynamic(GameObject go)
			{
				return (Object)(object)go.GetComponentInParent<Rigidbody>() != (Object)null;
			}
		}
	}
}
namespace BetterOreMining.Infrastructure
{
	public sealed class GameEvents : IGameEvents
	{
		internal static GameEvents Instance { get; set; }

		public event Action<Attack> MeleeAttackStarting;

		public event Action<Vector3> PickaxeStruck;

		public event Action FrameUpdated;

		internal void RaiseMeleeAttackStarting(Attack attack)
		{
			this.MeleeAttackStarting?.Invoke(attack);
		}

		internal void RaisePickaxeStruck(Vector3 point)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			this.PickaxeStruck?.Invoke(point);
		}

		internal void RaiseFrameUpdated()
		{
			this.FrameUpdated?.Invoke();
		}
	}
	public sealed class GroundTextures
	{
		private readonly Dictionary<GroundMap, Texture2D> _textures = new Dictionary<GroundMap, Texture2D>();

		private readonly List<GroundMap> _stale = new List<GroundMap>();

		public Texture2D Get(GroundMap ground)
		{
			if (!_textures.TryGetValue(ground, out var value))
			{
				value = Upload(ground);
				_textures[ground] = value;
			}
			return value;
		}

		public void KeepOnly(IReadOnlyList<RippleWave> waves)
		{
			_stale.Clear();
			foreach (GroundMap key in _textures.Keys)
			{
				if (!IsUsed(key, waves))
				{
					_stale.Add(key);
				}
			}
			foreach (GroundMap item in _stale)
			{
				Object.Destroy((Object)(object)_textures[item]);
				_textures.Remove(item);
			}
		}

		private static bool IsUsed(GroundMap ground, IReadOnlyList<RippleWave> waves)
		{
			foreach (RippleWave wave in waves)
			{
				if (wave.Ground == ground)
				{
					return true;
				}
			}
			return false;
		}

		private static Texture2D Upload(GroundMap ground)
		{
			//IL_0008: 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_0014: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			Texture2D val = new Texture2D(32, 32, (TextureFormat)18, false, true)
			{
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1
			};
			val.SetPixelData<float>(ground.Heights, 0, 0);
			val.Apply(false, true);
			return val;
		}
	}
	internal static class OreRocks
	{
		private const string DepositPrefix = "MineRock_";

		private static readonly string[] OreSuffixes = new string[2] { "Ore", "OreNew" };

		private static readonly string[] OreItems = new string[4] { "Obsidian", "IronScrap", "CopperScrap", "Softtissue" };

		public static bool IsOre(GameObject target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return false;
			}
			MineRock5 component = target.GetComponent<MineRock5>();
			if ((Object)(object)component != (Object)null)
			{
				return DropsOre(component.m_dropItems);
			}
			MineRock component2 = target.GetComponent<MineRock>();
			if ((Object)(object)component2 != (Object)null)
			{
				return DropsOre(component2.m_dropItems);
			}
			Destructible component3 = target.GetComponent<Destructible>();
			if ((Object)(object)component3 != (Object)null)
			{
				return IsOreWhenIntact(target, component3);
			}
			return false;
		}

		private static bool IsOreWhenIntact(GameObject target, Destructible intact)
		{
			DropOnDestroyed component = target.GetComponent<DropOnDestroyed>();
			if (((Object)target).name.StartsWith("MineRock_") && (Object)(object)component != (Object)null && DropsOre(component.m_dropWhenDestroyed))
			{
				return true;
			}
			GameObject spawnWhenDestroyed = intact.m_spawnWhenDestroyed;
			if ((Object)(object)spawnWhenDestroyed != (Object)null)
			{
				return IsFracturedOre(spawnWhenDestroyed);
			}
			return false;
		}

		private static bool IsFracturedOre(GameObject fractured)
		{
			MineRock5 component = fractured.GetComponent<MineRock5>();
			if ((Object)(object)component != (Object)null)
			{
				return DropsOre(component.m_dropItems);
			}
			MineRock component2 = fractured.GetComponent<MineRock>();
			if ((Object)(object)component2 != (Object)null)
			{
				return DropsOre(component2.m_dropItems);
			}
			return false;
		}

		private static bool DropsOre(DropTable table)
		{
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			if (table == null)
			{
				return false;
			}
			foreach (DropData drop in table.m_drops)
			{
				if ((Object)(object)drop.m_item != (Object)null && IsOreItem(((Object)drop.m_item).name))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsOreItem(string name)
		{
			string[] oreSuffixes = OreSuffixes;
			foreach (string value in oreSuffixes)
			{
				if (name.EndsWith(value))
				{
					return true;
				}
			}
			return Array.IndexOf(OreItems, name) >= 0;
		}
	}
	public sealed class OverlayGlowRenderer : IGlowRenderer
	{
		private const int DepthPass = 0;

		private const int RingPass = 1;

		private const float DepthAboveMain = 0.5f;

		private const float CharacterRange = 40f;

		private const CameraEvent DrawEvent = (CameraEvent)17;

		private static readonly int CenterId = Shader.PropertyToID("_Center");

		private static readonly int FrontId = Shader.PropertyToID("_Front");

		private static readonly int WidthId = Shader.PropertyToID("_Width");

		private static readonly int OpacityId = Shader.PropertyToID("_Opacity");

		private static readonly int VisibleId = Shader.PropertyToID("_VisibleColor");

		private static readonly int BlockedId = Shader.PropertyToID("_BlockedColor");

		private static readonly int GroundMapId = Shader.PropertyToID("_GroundMap");

		private static readonly int GroundRectId = Shader.PropertyToID("_GroundRect");

		private readonly Material _material;

		private readonly IColorSettings _colors;

		private readonly GroundTextures _groundTextures;

		private readonly CommandBuffer _commands = new CommandBuffer
		{
			name = "BetterOreMining"
		};

		private readonly List<Renderer> _characterParts = new List<Renderer>();

		private readonly HashSet<Renderer> _depthDrawn = new HashSet<Renderer>();

		private IReadOnlyList<RippleWave> _waves = Array.Empty<RippleWave>();

		private float _ringWidth;

		private bool _subscribed;

		private Camera _overlay;

		public OverlayGlowRenderer(Shader shader, IColorSettings colors, GroundTextures groundTextures)
		{
			//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_0016: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			_material = new Material(shader);
			_colors = colors;
			_groundTextures = groundTextures;
		}

		public void Draw(IReadOnlyList<RippleWave> waves, float ringWidth)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			_waves = waves;
			_ringWidth = ringWidth;
			_groundTextures.KeepOnly(waves);
			if (!_subscribed)
			{
				Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull));
				_subscribed = true;
			}
			SyncOverlay();
		}

		public void Clear()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			_waves = Array.Empty<RippleWave>();
			_groundTextures.KeepOnly(_waves);
			if (_subscribed)
			{
				Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull));
				_subscribed = false;
			}
			if ((Object)(object)_overlay != (Object)null)
			{
				((Behaviour)_overlay).enabled = false;
			}
		}

		private static bool IsShown(Renderer renderer)
		{
			if ((Object)(object)renderer != (Object)null && renderer.enabled)
			{
				return ((Component)renderer).gameObject.activeInHierarchy;
			}
			return false;
		}

		private static bool IsMesh(Renderer renderer)
		{
			if (!(renderer is MeshRenderer))
			{
				return renderer is SkinnedMeshRenderer;
			}
			return true;
		}

		private void SyncOverlay()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null))
			{
				if ((Object)(object)_overlay == (Object)null)
				{
					_overlay = new GameObject("BetterOreMining.Overlay").AddComponent<Camera>();
				}
				if ((Object)(object)((Component)_overlay).transform.parent != (Object)(object)((Component)main).transform)
				{
					((Component)_overlay).transform.SetParent(((Component)main).transform, false);
				}
				_overlay.CopyFrom(main);
				_overlay.clearFlags = (CameraClearFlags)3;
				_overlay.cullingMask = 0;
				_overlay.renderingPath = (RenderingPath)1;
				_overlay.depth = main.depth + 0.5f;
				if (_overlay.commandBufferCount == 0)
				{
					_overlay.AddCommandBuffer((CameraEvent)17, _commands);
				}
				((Behaviour)_overlay).enabled = true;
			}
		}

		private void OnPreCull(Camera camera)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)camera != (Object)(object)_overlay)
			{
				return;
			}
			_commands.Clear();
			_depthDrawn.Clear();
			AddCharacterDepth(((Component)camera).transform.position);
			foreach (RippleWave wave in _waves)
			{
				AddOreDepth(wave);
			}
			_commands.SetGlobalColor(VisibleId, _colors.VisibleColor);
			_commands.SetGlobalColor(BlockedId, _colors.BlockedColor);
			_commands.SetGlobalFloat(WidthId, _ringWidth);
			foreach (RippleWave wave2 in _waves)
			{
				AddRing(wave2);
			}
		}

		private void AddCharacterDepth(Vector3 viewpoint)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			float num = 1600f;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				Vector3 val = ((Component)allCharacter).transform.position - viewpoint;
				if (!(((Vector3)(ref val)).sqrMagnitude < num))
				{
					continue;
				}
				((Component)allCharacter).GetComponentsInChildren<Renderer>(false, _characterParts);
				foreach (Renderer characterPart in _characterParts)
				{
					if (IsMesh(characterPart))
					{
						DrawIfShown(characterPart, 0);
					}
				}
			}
		}

		private void AddOreDepth(RippleWave wave)
		{
			Renderer[] ore = wave.Ore;
			foreach (Renderer val in ore)
			{
				if (_depthDrawn.Add(val))
				{
					DrawIfShown(val, 0);
				}
			}
		}

		private void AddRing(RippleWave wave)
		{
			//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)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			GroundMap ground = wave.Ground;
			float num = 1f / ground.Size;
			_commands.SetGlobalVector(CenterId, Vector4.op_Implicit(wave.Center));
			_commands.SetGlobalFloat(FrontId, wave.Front);
			_commands.SetGlobalFloat(OpacityId, wave.Alpha);
			_commands.SetGlobalTexture(GroundMapId, RenderTargetIdentifier.op_Implicit((Texture)(object)_groundTextures.Get(ground)));
			_commands.SetGlobalVector(GroundRectId, new Vector4(ground.Origin.x, ground.Origin.y, num, num));
			Renderer[] ore = wave.Ore;
			foreach (Renderer renderer in ore)
			{
				DrawIfShown(renderer, 1);
			}
		}

		private void DrawIfShown(Renderer renderer, int pass)
		{
			if (IsShown(renderer))
			{
				int num = renderer.sharedMaterials.Length;
				for (int i = 0; i < num; i++)
				{
					_commands.DrawRenderer(renderer, _material, i, pass);
				}
			}
		}
	}
	public sealed class PhysicsOreScanner : IOreScanner
	{
		public bool TryFindOre(Vector3 origin, Vector3 direction, float radius, float maxDistance, out float distance)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			distance = 0f;
			RaycastHit val = default(RaycastHit);
			if (!Physics.SphereCast(origin, radius, direction, ref val, maxDistance, Attack.m_attackMask, (QueryTriggerInteraction)1))
			{
				return false;
			}
			GameObject target = Projectile.FindHitObject(((RaycastHit)(ref val)).collider);
			distance = ((RaycastHit)(ref val)).distance;
			return OreRocks.IsOre(target);
		}
	}
	public sealed class PhysicsVeinScanner : IVeinScanner
	{
		private static readonly Collider[] Colliders = (Collider[])(object)new Collider[256];

		public VeinScan Scan(Vector3 center, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			int num = Physics.OverlapSphereNonAlloc(center, radius, Colliders, Attack.m_attackMask, (QueryTriggerInteraction)1);
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			float num2 = radius;
			for (int i = 0; i < num; i++)
			{
				Collider val = Colliders[i];
				GameObject val2 = Projectile.FindHitObject(val);
				if (OreRocks.IsOre(val2))
				{
					hashSet.Add(val2);
					Bounds bounds = val.bounds;
					Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(center);
					num2 = Mathf.Min(num2, Vector3.Distance(val3, center));
				}
			}
			List<Renderer> list = new List<Renderer>();
			foreach (GameObject item in hashSet)
			{
				list.AddRange((IEnumerable<Renderer>)(object)item.GetComponentsInChildren<MeshRenderer>());
			}
			return new VeinScan(list.ToArray(), num2);
		}
	}
	internal static class ShaderBundle
	{
		public static Shader Load(string path)
		{
			if (!File.Exists(path))
			{
				return null;
			}
			AssetBundle val = AssetBundle.LoadFromFile(path);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Shader[] array = val.LoadAllAssets<Shader>();
			if (array.Length == 0 || !array[0].isSupported)
			{
				return null;
			}
			return array[0];
		}
	}
	public sealed class ZoneGroundProbe : IGroundProbe
	{
		public float GroundHeight(Vector3 point)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return ZoneSystem.instance.GetGroundHeight(point);
		}
	}
}
namespace BetterOreMining.Features
{
	public sealed class GroundMap
	{
		public const int Resolution = 32;

		public Vector2 Origin { get; }

		public float Size { get; }

		public float[] Heights { get; }

		private GroundMap(Vector2 origin, float size, float[] heights)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Origin = origin;
			Size = size;
			Heights = heights;
		}

		public static GroundMap Sample(IGroundProbe ground, Vector3 center, float radius)
		{
			//IL_0012: 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_0097: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			float num = radius * 2f;
			float num2 = num / 32f;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(center.x - radius, center.z - radius);
			float[] array = new float[1024];
			Vector3 point = default(Vector3);
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					((Vector3)(ref point))..ctor(val.x + ((float)j + 0.5f) * num2, center.y, val.y + ((float)i + 0.5f) * num2);
					array[i * 32 + j] = ground.GroundHeight(point);
				}
			}
			return new GroundMap(val, num, array);
		}
	}
	public interface IColorSettings
	{
		Color VisibleColor { get; }

		Color BlockedColor { get; }
	}
	public interface IFeature
	{
		void Enable();

		void Disable();
	}
	public interface IGameEvents
	{
		event Action<Attack> MeleeAttackStarting;

		event Action<Vector3> PickaxeStruck;

		event Action FrameUpdated;
	}
	public interface IGlowRenderer
	{
		void Draw(IReadOnlyList<RippleWave> waves, float ringWidth);

		void Clear();
	}
	public interface IGroundProbe
	{
		float GroundHeight(Vector3 point);
	}
	public interface IOreScanner
	{
		bool TryFindOre(Vector3 origin, Vector3 direction, float radius, float maxDistance, out float distance);
	}
	public interface IRippleSettings
	{
		float Radius { get; }

		float WaveSpeed { get; }

		float RingWidth { get; }

		float Opacity { get; }
	}
	public interface IVeinScanner
	{
		VeinScan Scan(Vector3 center, float radius);
	}
	public sealed class OreReachFeature : IFeature
	{
		private const float MaxReach = 4f;

		private const float ReachMargin = 0.5f;

		private const float MaxPitchDegrees = 45f;

		private const float MinRayWidth = 0.2f;

		private readonly IGameEvents _events;

		private readonly IOreScanner _scanner;

		public OreReachFeature(IGameEvents events, IOreScanner scanner)
		{
			_events = events;
			_scanner = scanner;
		}

		public void Enable()
		{
			_events.MeleeAttackStarting += OnMeleeAttackStarting;
		}

		public void Disable()
		{
			_events.MeleeAttackStarting -= OnMeleeAttackStarting;
		}

		private static bool IsLocalPickaxeSwing(Attack attack)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			bool num = (Object)(object)attack.m_character == (Object)(object)Player.m_localPlayer;
			bool flag = (int)attack.m_weapon.m_shared.m_skillType == 12;
			return num && flag;
		}

		private void OnMeleeAttackStarting(Attack attack)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (IsLocalPickaxeSwing(attack))
			{
				float maxYAngle = attack.m_maxYAngle;
				attack.m_maxYAngle = Mathf.Max(maxYAngle, 45f);
				Transform val = default(Transform);
				Vector3 direction = default(Vector3);
				attack.GetMeleeAttackDir(ref val, ref direction);
				Vector3 origin = val.position + Vector3.up * attack.m_attackHeight + ((Component)attack.m_character).transform.right * attack.m_attackOffset;
				float num = Mathf.Max(attack.m_attackRayWidth, 0.2f);
				if (!_scanner.TryFindOre(origin, direction, num, 4f, out var distance))
				{
					attack.m_maxYAngle = maxYAngle;
					return;
				}
				attack.m_hitTerrain = false;
				attack.m_attackRange = Mathf.Max(attack.m_attackRange, distance + num + 0.5f);
			}
		}
	}
	public sealed class RippleFeature : IFeature
	{
		private const int MaxWaves = 4;

		private readonly IGameEvents _events;

		private readonly IRippleSettings _settings;

		private readonly IVeinScanner _scanner;

		private readonly IGroundProbe _ground;

		private readonly IGlowRenderer _renderer;

		private readonly List<RippleWave> _waves = new List<RippleWave>();

		private int _strikeFrame = -1;

		private Vector3? _pendingStrike;

		public RippleFeature(IGameEvents events, IRippleSettings settings, IVeinScanner scanner, IGroundProbe ground, IGlowRenderer renderer)
		{
			_events = events;
			_settings = settings;
			_scanner = scanner;
			_ground = ground;
			_renderer = renderer;
		}

		public void Enable()
		{
			_events.PickaxeStruck += OnPickaxeStruck;
			_events.FrameUpdated += OnFrameUpdated;
		}

		public void Disable()
		{
			_events.PickaxeStruck -= OnPickaxeStruck;
			_events.FrameUpdated -= OnFrameUpdated;
			_pendingStrike = null;
			_waves.Clear();
			_renderer.Clear();
		}

		private void OnPickaxeStruck(Vector3 point)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Time.frameCount != _strikeFrame)
			{
				_strikeFrame = Time.frameCount;
				_pendingStrike = point;
			}
		}

		private void StartWave(Vector3 point)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			float radius = _settings.Radius;
			VeinScan veinScan = _scanner.Scan(point, radius);
			if (veinScan.Renderers.Length != 0)
			{
				if (_waves.Count == 4)
				{
					_waves.RemoveAt(0);
				}
				_waves.Add(new RippleWave(point, veinScan.Renderers, GroundMap.Sample(_ground, point, radius), Time.time, veinScan.NearestDistance));
			}
		}

		private void OnFrameUpdated()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (_pendingStrike.HasValue && Time.frameCount > _strikeFrame)
			{
				StartWave(_pendingStrike.Value);
				_pendingStrike = null;
			}
			if (_waves.Count == 0)
			{
				return;
			}
			foreach (RippleWave wave in _waves)
			{
				wave.Advance(Time.time, _settings);
			}
			_waves.RemoveAll((RippleWave wave) => wave.IsFinished);
			if (_waves.Count == 0)
			{
				_renderer.Clear();
			}
			else
			{
				_renderer.Draw(_waves, _settings.RingWidth);
			}
		}
	}
	public static class RippleTimeline
	{
		public static float Front(float elapsed, float waveSpeed)
		{
			return elapsed * waveSpeed;
		}

		public static float End(float radius, float ringWidth)
		{
			return radius + ringWidth;
		}

		public static bool IsFinished(float front, float radius, float ringWidth)
		{
			return front >= End(radius, ringWidth);
		}

		public static float Fade(float front, float radius, float ringWidth)
		{
			return 1f - Mathf.Clamp01(front / End(radius, ringWidth));
		}
	}
	public sealed class RippleWave
	{
		private readonly float _startTime;

		private readonly float _startFront;

		public Vector3 Center { get; }

		public Renderer[] Ore { get; }

		public GroundMap Ground { get; }

		public float Front { get; private set; }

		public float Alpha { get; private set; }

		public bool IsFinished { get; private set; }

		public RippleWave(Vector3 center, Renderer[] ore, GroundMap ground, float startTime, float startFront)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Center = center;
			Ore = ore;
			Ground = ground;
			_startTime = startTime;
			_startFront = startFront;
		}

		public void Advance(float now, IRippleSettings settings)
		{
			float num = RippleTimeline.Front(now - _startTime, settings.WaveSpeed);
			Front = _startFront + num;
			float num2 = RippleTimeline.Fade(Front, settings.Radius, settings.RingWidth);
			Alpha = settings.Opacity * num2;
			IsFinished = RippleTimeline.IsFinished(Front, settings.Radius, settings.RingWidth);
		}
	}
	public sealed class VeinScan
	{
		public Renderer[] Renderers { get; }

		public float NearestDistance { get; }

		public VeinScan(Renderer[] renderers, float nearestDistance)
		{
			Renderers = renderers;
			NearestDistance = nearestDistance;
		}
	}
}
namespace BetterOreMining.Config
{
	public sealed class ModSettings : IRippleSettings, IColorSettings
	{
		private readonly ConfigEntry<float> _radius;

		private readonly ConfigEntry<float> _waveSpeed;

		private readonly ConfigEntry<float> _ringWidth;

		private readonly ConfigEntry<float> _opacity;

		private readonly ConfigEntry<Color> _visibleColor;

		private readonly ConfigEntry<Color> _blockedColor;

		public float Radius => _radius.Value;

		public float WaveSpeed => _waveSpeed.Value;

		public float RingWidth => _ringWidth.Value;

		public float Opacity => _opacity.Value;

		public Color VisibleColor => _visibleColor.Value;

		public Color BlockedColor => _blockedColor.Value;

		public ModSettings(ConfigFile file)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			_radius = file.Bind<float>("Ripple", "Radius", 8f, new ConfigDescription("How far the ripple spreads from where you hit, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), Array.Empty<object>()));
			_waveSpeed = file.Bind<float>("Ripple", "WaveSpeed", 4.5f, new ConfigDescription("How fast the ripple spreads, in meters per second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), Array.Empty<object>()));
			_ringWidth = file.Bind<float>("Ripple", "RingWidth", 2f, new ConfigDescription("How thick the glowing ring is, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			_opacity = file.Bind<float>("Ripple", "Opacity", 0.8f, new ConfigDescription("How strong the ring is at its brightest, from 0 to 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			_visibleColor = file.Bind<Color>("Colors", "Visible", new Color(0.2f, 1f, 0.35f, 1f), "Ring color on ore at or above the ground, as RGBA hex (RRGGBBAA).");
			_blockedColor = file.Bind<Color>("Colors", "Blocked", new Color(1f, 0.15f, 0.1f, 1f), "Ring color on ore buried 2 meters or deeper, as RGBA hex (RRGGBBAA).");
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}