Decompiled source of Area Repair v0.1.0

FrizzQOL.AreaRepair.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("FrizzQOL.AreaRepair")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+390888ce9958d39dc59b6d4c12697e4d38569584")]
[assembly: AssemblyProduct("FrizzQOL.AreaRepair")]
[assembly: AssemblyTitle("FrizzQOL.AreaRepair")]
[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;
		}
	}
}
public static class RepairRules
{
	public static bool IsInRange(float distance, float radius)
	{
		if (radius > 0f)
		{
			return distance <= radius;
		}
		return false;
	}

	public static bool ShouldRepair(bool isDamaged, float distance, float radius)
	{
		if (isDamaged)
		{
			return IsInRange(distance, radius);
		}
		return false;
	}

	public static bool ShouldAreaRepair(bool hoveredRepairAccepted)
	{
		return hoveredRepairAccepted;
	}

	public static bool ShouldRepairNearby(float distance, float radius, bool wardAllows)
	{
		if (wardAllows)
		{
			return IsInRange(distance, radius);
		}
		return false;
	}
}
public sealed class RepairIndex<T> where T : class
{
	private readonly struct Pos
	{
		public readonly float X;

		public readonly float Y;

		public readonly float Z;

		public Pos(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}
	}

	private readonly struct Cell : IEquatable<Cell>
	{
		public readonly int X;

		public readonly int Y;

		public readonly int Z;

		public Cell(int x, int y, int z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public bool Equals(Cell other)
		{
			if (X == other.X && Y == other.Y)
			{
				return Z == other.Z;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is Cell other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((X * 397) ^ Y) * 397) ^ Z;
		}
	}

	private readonly float _cell;

	private readonly Dictionary<T, Cell> _cellOf = new Dictionary<T, Cell>();

	private readonly Dictionary<T, Pos> _pos = new Dictionary<T, Pos>();

	private readonly Dictionary<Cell, List<T>> _cells = new Dictionary<Cell, List<T>>();

	public int Count => _cellOf.Count;

	public int LastVisited { get; private set; }

	public RepairIndex(float cellSize)
	{
		if (cellSize <= 0f)
		{
			throw new ArgumentOutOfRangeException("cellSize");
		}
		_cell = cellSize;
	}

	public void Add(T item, float x, float y, float z)
	{
		if (item != null)
		{
			Remove(item);
			Cell cell = CellOf(x, y, z);
			_cellOf[item] = cell;
			_pos[item] = new Pos(x, y, z);
			if (!_cells.TryGetValue(cell, out var value))
			{
				value = new List<T>();
				_cells[cell] = value;
			}
			value.Add(item);
		}
	}

	public void Remove(T item)
	{
		if (item == null || !_cellOf.TryGetValue(item, out var value))
		{
			return;
		}
		_cellOf.Remove(item);
		_pos.Remove(item);
		if (_cells.TryGetValue(value, out var value2))
		{
			value2.Remove(item);
			if (value2.Count == 0)
			{
				_cells.Remove(value);
			}
		}
	}

	public void Collect(float x, float y, float z, float radius, List<T> results)
	{
		if (results == null)
		{
			throw new ArgumentNullException("results");
		}
		results.Clear();
		LastVisited = 0;
		if (radius <= 0f || _cellOf.Count == 0)
		{
			return;
		}
		double num = Math.Floor((x - radius) / _cell);
		double num2 = Math.Floor((x + radius) / _cell);
		double num3 = Math.Floor((y - radius) / _cell);
		double num4 = Math.Floor((y + radius) / _cell);
		double num5 = Math.Floor((z - radius) / _cell);
		double num6 = Math.Floor((z + radius) / _cell);
		double num7 = num2 - num + 1.0;
		double num8 = num4 - num3 + 1.0;
		double num9 = num6 - num5 + 1.0;
		if (num7 * num8 * num9 > (double)_cellOf.Count || num7 > 32.0 || num8 > 32.0 || num9 > 32.0 || num < -2147483648.0 || num2 > 2147483647.0 || num3 < -2147483648.0 || num4 > 2147483647.0 || num5 < -2147483648.0 || num6 > 2147483647.0)
		{
			ScanAll(x, y, z, radius * radius, results);
			return;
		}
		float r = radius * radius;
		int num10 = (int)num;
		int num11 = (int)num2;
		int num12 = (int)num3;
		int num13 = (int)num4;
		int num14 = (int)num5;
		int num15 = (int)num6;
		for (int i = num10; i <= num11; i++)
		{
			for (int j = num12; j <= num13; j++)
			{
				for (int k = num14; k <= num15; k++)
				{
					if (_cells.TryGetValue(new Cell(i, j, k), out var value))
					{
						Visit(value, x, y, z, r, results);
					}
				}
			}
		}
	}

	private void ScanAll(float x, float y, float z, float r2, List<T> results)
	{
		foreach (KeyValuePair<T, Pos> po in _pos)
		{
			LastVisited++;
			Pos value = po.Value;
			float num = value.X - x;
			float num2 = value.Y - y;
			float num3 = value.Z - z;
			if (num * num + num2 * num2 + num3 * num3 <= r2)
			{
				results.Add(po.Key);
			}
		}
	}

	private void Visit(List<T> list, float x, float y, float z, float r2, List<T> results)
	{
		for (int i = 0; i < list.Count; i++)
		{
			T val = list[i];
			LastVisited++;
			if (_pos.TryGetValue(val, out var value))
			{
				float num = value.X - x;
				float num2 = value.Y - y;
				float num3 = value.Z - z;
				if (num * num + num2 * num2 + num3 * num3 <= r2)
				{
					results.Add(val);
				}
			}
		}
	}

	private Cell CellOf(float x, float y, float z)
	{
		return new Cell(Floor(x), Floor(y), Floor(z));
	}

	private int Floor(float value)
	{
		return (int)Math.Floor(value / _cell);
	}
}
namespace AreaRepair
{
	[BepInPlugin("com.frizzqol.arearepair", "FrizzQOL Area Repair", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.frizzqol.arearepair";

		public const string PluginName = "FrizzQOL Area Repair";

		public const string PluginVersion = "0.1.0";

		internal static ConfigEntry<float> RepairRadius;

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			Instance = this;
			RepairRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RepairRadius", 5f, "Sphere radius in meters around the hammer-repair target. 0 or less disables area repair.");
			_harmony = new Harmony("com.frizzqol.arearepair");
			try
			{
				_harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"FrizzQOL Area Repair 0.1.0 loaded");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failed to patch Player.Repair: " + ex.Message));
			}
		}

		internal static float CurrentRadius()
		{
			if (RepairRadius == null)
			{
				return 5f;
			}
			return RepairRadius.Value;
		}

		internal static void LogInfo(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
			}
		}

		internal static void LogError(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogError((object)message);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Repair", new Type[]
	{
		typeof(ItemData),
		typeof(Piece)
	})]
	internal static class RepairPatch
	{
		private const float CellSize = 16f;

		private static readonly RepairIndex<Piece> Index = new RepairIndex<Piece>(16f);

		private static readonly List<Piece> Nearby = new List<Piece>();

		private static readonly FieldInfo GhostLayerField = AccessTools.Field(typeof(Piece), "s_ghostLayer");

		private static bool _busy;

		private static bool _watchHover;

		private static bool _hoverAccepted;

		private static int _ghostLayer = int.MinValue;

		internal static void NoteHoverRepair(bool accepted)
		{
			if (_watchHover)
			{
				_hoverAccepted = accepted;
			}
		}

		internal static void Track(Piece piece)
		{
			//IL_0010: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null))
			{
				Vector3 position = ((Component)piece).transform.position;
				Index.Add(piece, position.x, position.y, position.z);
			}
		}

		internal static void Untrack(Piece piece)
		{
			Index.Remove(piece);
		}

		private static void Prefix()
		{
			if (!_busy)
			{
				_watchHover = true;
				_hoverAccepted = false;
			}
		}

		private static void Postfix(Player __instance)
		{
			if (_busy)
			{
				return;
			}
			_watchHover = false;
			if (!RepairRules.ShouldAreaRepair(_hoverAccepted) || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			Piece hoveringPiece = __instance.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null)
			{
				return;
			}
			float num = Plugin.CurrentRadius();
			if (num <= 0f)
			{
				return;
			}
			try
			{
				_busy = true;
				RepairNearby(hoveringPiece, num);
			}
			finally
			{
				_busy = false;
			}
		}

		private static void Finalizer()
		{
			_watchHover = false;
		}

		private static void RepairNearby(Piece target, float radius)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)target).transform.position;
			Index.Collect(position.x, position.y, position.z, radius, Nearby);
			int num = 0;
			try
			{
				for (int i = 0; i < Nearby.Count; i++)
				{
					Piece val = Nearby[i];
					if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)target || IsGhost(val))
					{
						continue;
					}
					Vector3 position2 = ((Component)val).transform.position;
					float distance = Vector3.Distance(position, position2);
					bool wardAllows = PrivateArea.CheckAccess(position2, 0f, false, false);
					if (RepairRules.ShouldRepairNearby(distance, radius, wardAllows))
					{
						WearNTear component = ((Component)val).GetComponent<WearNTear>();
						if (!((Object)(object)component == (Object)null) && component.Repair())
						{
							num++;
						}
					}
				}
			}
			finally
			{
				Nearby.Clear();
			}
			if (num > 0)
			{
				Plugin.LogInfo("Repaired " + num + " extra pieces.");
			}
		}

		private static bool IsGhost(Piece piece)
		{
			if (_ghostLayer == int.MinValue)
			{
				_ghostLayer = ((((GhostLayerField != null) ? GhostLayerField.GetValue(null) : null) is int num) ? num : (-1));
			}
			if (_ghostLayer >= 0)
			{
				return ((Component)piece).gameObject.layer == _ghostLayer;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(WearNTear), "Repair")]
	internal static class WearRepairResultPatch
	{
		private static void Postfix(bool __result)
		{
			RepairPatch.NoteHoverRepair(__result);
		}
	}
	[HarmonyPatch(typeof(Piece), "Awake")]
	internal static class PieceTrackPatch
	{
		private static void Postfix(Piece __instance)
		{
			RepairPatch.Track(__instance);
		}
	}
	[HarmonyPatch(typeof(Piece), "OnDestroy")]
	internal static class PieceUntrackPatch
	{
		private static void Postfix(Piece __instance)
		{
			RepairPatch.Untrack(__instance);
		}
	}
}