Decompiled source of AreaRepair v1.0.2

BepInEx/plugins/AreaRepair.dll

Decompiled 16 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ConditionalConfigSync;
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("AreaRepair")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AreaRepair")]
[assembly: AssemblyTitle("AreaRepair")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 Wabbaka.AreaRepair
{
	internal static class AreaRepairRuntime
	{
		private static readonly FieldInfo HoveringPieceField = AccessTools.Field(typeof(Player), "m_hoveringPiece");

		private static readonly MethodInfo CreatorMethod = AccessTools.Method(typeof(Piece), "GetCreator", (Type[])null, (Type[])null);

		private static readonly MethodInfo HealthMethod = AccessTools.Method(typeof(WearNTear), "GetHealthPercentage", (Type[])null, (Type[])null);

		private static readonly Type LocalizationType = AccessTools.TypeByName("Localization");

		private static readonly PropertyInfo LocalizationInstanceProperty = ((LocalizationType == null) ? null : AccessTools.Property(LocalizationType, "instance"));

		private static readonly FieldInfo LocalizationInstanceField = ((LocalizationType == null) ? null : (AccessTools.Field(LocalizationType, "instance") ?? AccessTools.Field(LocalizationType, "m_instance")));

		private static readonly MethodInfo GetSelectedLanguageMethod = ((LocalizationType == null) ? null : AccessTools.Method(LocalizationType, "GetSelectedLanguage", (Type[])null, (Type[])null));

		private static readonly MethodInfo CharacterMessageMethod = AccessTools.GetDeclaredMethods(typeof(Character)).FirstOrDefault(delegate(MethodInfo method)
		{
			ParameterInfo[] parameters = method.GetParameters();
			return method.Name == "Message" && parameters.Length >= 2 && parameters[0].ParameterType.IsEnum && parameters[1].ParameterType == typeof(string);
		});

		internal static MethodInfo PlayerRepairMethod;

		internal static int AreaDepth;

		internal static bool SuppressMessages;

		internal static WearNTear DirectTarget;

		internal static bool DirectRepairSucceeded;

		internal static int RepairedCount;

		internal static Piece GetHoveringPiece(Player player)
		{
			object? obj = HoveringPieceField?.GetValue(player);
			return (Piece)((obj is Piece) ? obj : null);
		}

		internal static void SetHoveringPiece(Player player, Piece piece)
		{
			HoveringPieceField?.SetValue(player, piece);
		}

		internal static bool IsDamaged(WearNTear wear)
		{
			if ((Object)(object)wear == (Object)null || HealthMethod == null)
			{
				return (Object)(object)wear != (Object)null;
			}
			try
			{
				return Convert.ToSingle(HealthMethod.Invoke(wear, null)) < 0.9999f;
			}
			catch
			{
				return true;
			}
		}

		internal static bool IsPlayerBuilt(Piece piece)
		{
			if (!Plugin.OnlyPlayerBuilt.Value || CreatorMethod == null)
			{
				return true;
			}
			try
			{
				object obj = CreatorMethod.Invoke(piece, null);
				return obj != null && Convert.ToInt64(obj) != 0;
			}
			catch
			{
				return true;
			}
		}

		internal static bool CanContinue(Player player, ItemData tool)
		{
			try
			{
				if ((Object)(object)player == (Object)null || tool == null || ((Character)player).IsDead())
				{
					return false;
				}
				if (tool.m_shared.m_useDurability && tool.m_durability <= 0f)
				{
					return false;
				}
				return ((Character)player).HaveStamina(tool.m_shared.m_attack.m_attackStamina);
			}
			catch
			{
				return true;
			}
		}

		internal static string SummaryText(int count)
		{
			string text = GetCurrentLanguage().Replace("_", string.Empty).Replace("-", string.Empty).Replace(" ", string.Empty)
				.ToLowerInvariant();
			string format = ((text.Contains("traditional") && text.Contains("chinese")) ? "已修復建築部件:{0}" : (text.Contains("chinese") ? "已修复建筑部件:{0}" : (text.Contains("french") ? "Éléments réparés : {0}" : (text.Contains("german") ? "Reparierte Bauteile: {0}" : (text.Contains("spanish") ? "Piezas reparadas: {0}" : (text.Contains("russian") ? "Починено объектов: {0}" : (text.Contains("turkish") ? "Onarılan parçalar: {0}" : (text.Contains("japanese") ? "修理した建築パーツ: {0}" : ((text.Contains("portuguese") || text.Contains("brazil")) ? "Peças reparadas: {0}" : (text.Contains("polish") ? "Naprawione elementy: {0}" : (text.Contains("ukrain") ? "Відремонтовано об'єктів: {0}" : (text.Contains("italian") ? "Elementi riparati: {0}" : ((!text.Contains("korean")) ? "Pieces repaired: {0}" : "수리한 건축 부품: {0}")))))))))))));
			return string.Format(format, count);
		}

		private static string GetCurrentLanguage()
		{
			//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)
			try
			{
				object obj = LocalizationInstanceProperty?.GetValue(null, null) ?? LocalizationInstanceField?.GetValue(null);
				string text = GetSelectedLanguageMethod?.Invoke(obj, null)?.ToString();
				if (!string.IsNullOrWhiteSpace(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return ((object)Application.systemLanguage/*cast due to .constrained prefix*/).ToString();
		}

		internal static void ShowSummary(Player player, string text)
		{
			if ((Object)(object)player == (Object)null || CharacterMessageMethod == null)
			{
				return;
			}
			try
			{
				ParameterInfo[] parameters = CharacterMessageMethod.GetParameters();
				object[] array = new object[parameters.Length];
				array[0] = Enum.Parse(parameters[0].ParameterType, "TopLeft");
				array[1] = text;
				for (int i = 2; i < parameters.Length; i++)
				{
					if (parameters[i].HasDefaultValue)
					{
						array[i] = parameters[i].DefaultValue;
						continue;
					}
					Type parameterType = parameters[i].ParameterType;
					array[i] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null);
				}
				CharacterMessageMethod.Invoke(player, array);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Unable to show repair summary: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	internal static class PlayerRepairPatch
	{
		private sealed class RepairState
		{
			internal ItemData Tool;

			internal Piece TargetPiece;

			internal object[] Arguments;
		}

		private static MethodBase TargetMethod()
		{
			return AreaRepairRuntime.PlayerRepairMethod = AccessTools.GetDeclaredMethods(typeof(Player)).FirstOrDefault((MethodInfo candidate) => candidate.Name == "Repair" && candidate.GetParameters().Any((ParameterInfo parameter) => parameter.ParameterType == typeof(ItemData)));
		}

		private static void Prefix(Player __instance, object[] __args, out RepairState __state)
		{
			//IL_0029: 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)
			__state = null;
			if (AreaRepairRuntime.AreaDepth > 0 || !Plugin.Enabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			KeyboardShortcut value = Plugin.SingleRepairKey.Value;
			if (!((KeyboardShortcut)(ref value)).IsPressed())
			{
				ItemData val = __args?.OfType<ItemData>().FirstOrDefault();
				Piece hoveringPiece = AreaRepairRuntime.GetHoveringPiece(__instance);
				WearNTear val2 = ((hoveringPiece != null) ? ((Component)hoveringPiece).GetComponent<WearNTear>() : null);
				if (val != null && !((Object)(object)hoveringPiece == (Object)null) && !((Object)(object)val2 == (Object)null))
				{
					__state = new RepairState
					{
						Tool = val,
						TargetPiece = hoveringPiece,
						Arguments = __args
					};
					AreaRepairRuntime.DirectTarget = val2;
					AreaRepairRuntime.DirectRepairSucceeded = false;
				}
			}
		}

		private static void Postfix(Player __instance, RepairState __state)
		{
			if (__state == null)
			{
				return;
			}
			try
			{
				if (AreaRepairRuntime.PlayerRepairMethod != null)
				{
					RunAreaRepair(__instance, __state);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Area repair failed: {arg}");
			}
			finally
			{
				AreaRepairRuntime.DirectTarget = null;
				AreaRepairRuntime.DirectRepairSucceeded = false;
			}
		}

		private static void RunAreaRepair(Player player, RepairState state)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			List<Piece> list = new List<Piece>();
			Piece.GetAllPiecesInRadius(((Component)state.TargetPiece).transform.position, Plugin.Radius.Value, list);
			List<Piece> list2 = (from piece in list
				where (Object)(object)piece != (Object)null && (Object)(object)piece != (Object)(object)state.TargetPiece
				group piece by ((Object)piece).GetInstanceID() into @group
				select @group.First()).OrderBy(delegate(Piece piece)
			{
				//IL_0006: 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_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)
				Vector3 val = ((Component)piece).transform.position - ((Component)state.TargetPiece).transform.position;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).Take(Plugin.MaximumPieces.Value).ToList();
			Piece hoveringPiece = AreaRepairRuntime.GetHoveringPiece(player);
			AreaRepairRuntime.AreaDepth++;
			AreaRepairRuntime.SuppressMessages = true;
			AreaRepairRuntime.RepairedCount = 0;
			try
			{
				foreach (Piece item in list2)
				{
					if (!AreaRepairRuntime.CanContinue(player, state.Tool))
					{
						break;
					}
					if (!((Object)(object)item == (Object)null) && ((Component)item).gameObject.activeInHierarchy)
					{
						WearNTear component = ((Component)item).GetComponent<WearNTear>();
						if (!((Object)(object)component == (Object)null) && AreaRepairRuntime.IsDamaged(component) && AreaRepairRuntime.IsPlayerBuilt(item))
						{
							AreaRepairRuntime.SetHoveringPiece(player, item);
							AreaRepairRuntime.PlayerRepairMethod.Invoke(player, state.Arguments);
						}
					}
				}
			}
			finally
			{
				AreaRepairRuntime.SetHoveringPiece(player, hoveringPiece);
				AreaRepairRuntime.SuppressMessages = false;
				AreaRepairRuntime.AreaDepth--;
			}
			int num = AreaRepairRuntime.RepairedCount + (AreaRepairRuntime.DirectRepairSucceeded ? 1 : 0);
			if (Plugin.ShowCount.Value && num > 1)
			{
				AreaRepairRuntime.ShowSummary(player, AreaRepairRuntime.SummaryText(num));
			}
			Plugin.Log.LogDebug((object)$"Area repair: {num} piece(s), radius {Plugin.Radius.Value:0.##} m.");
		}
	}
	[HarmonyPatch(typeof(WearNTear), "Repair")]
	internal static class WearNTearRepairPatch
	{
		private static void Postfix(WearNTear __instance, bool __result)
		{
			if (__result)
			{
				if (AreaRepairRuntime.AreaDepth > 0)
				{
					AreaRepairRuntime.RepairedCount++;
				}
				else if ((Object)(object)__instance == (Object)(object)AreaRepairRuntime.DirectTarget)
				{
					AreaRepairRuntime.DirectRepairSucceeded = true;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class CharacterMessagePatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from method in AccessTools.GetDeclaredMethods(typeof(Character))
				where method.Name == "Message"
				select method;
		}

		private static bool Prefix(Character __instance)
		{
			if (AreaRepairRuntime.SuppressMessages)
			{
				return (Object)(object)__instance != (Object)(object)Player.m_localPlayer;
			}
			return true;
		}
	}
	[BepInPlugin("Wabbaka.AreaRepair", "AreaRepair", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "Wabbaka.AreaRepair";

		public const string Name = "AreaRepair";

		public const string Version = "1.0.1";

		private static readonly ConfigSync ConfigSync = new ConfigSync("Wabbaka.AreaRepair")
		{
			DisplayName = "AreaRepair",
			CurrentVersion = "1.0.1",
			MinimumRequiredVersion = "1.0.1",
			ModRequired = true
		};

		internal static ConfigEntry<bool> LockConfiguration;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> Radius;

		internal static ConfigEntry<int> MaximumPieces;

		internal static ConfigEntry<bool> OnlyPlayerBuilt;

		internal static ConfigEntry<KeyboardShortcut> SingleRepairKey;

		internal static ConfigEntry<bool> ShowCount;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			LockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "LockConfiguration", true, "Only server administrators may change synchronized settings.");
			((ConditionalConfigSync)ConfigSync).AddLockingConfigEntry<bool>(LockConfiguration);
			Enabled = BindServer("General", "Enabled", defaultValue: true, "Enable area repair.");
			Radius = BindServer("Repair", "Radius", 7.5f, new ConfigDescription("Repair radius in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			MaximumPieces = BindServer("Repair", "MaximumPieces", 250, new ConfigDescription("Safety limit per hammer action.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 2000), Array.Empty<object>()));
			OnlyPlayerBuilt = BindServer("Repair", "OnlyPlayerBuilt", defaultValue: false, "Ignore generated ruins and other pieces with no player creator.");
			SingleRepairKey = BindClient<KeyboardShortcut>("Controls", "SingleRepairKey", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Hold for normal single-piece repair.");
			ShowCount = BindClient("Interface", "ShowRepairCount", defaultValue: true, "Show the total number of repaired pieces.");
			_harmony = new Harmony("Wabbaka.AreaRepair");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"AreaRepair 1.0.1 loaded.");
		}

		private ConfigEntry<T> BindServer<T>(string section, string key, T defaultValue, string description)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return BindServer(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		private ConfigEntry<T> BindServer<T>(string section, string key, T defaultValue, ConfigDescription description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			((ConditionalConfigSync)ConfigSync).AddConfigEntry<T>(val, (ConfigSyncMode)0);
			return val;
		}

		private ConfigEntry<T> BindClient<T>(string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			((ConditionalConfigSync)ConfigSync).AddConfigEntry<T>(val, (ConfigSyncMode)2);
			return val;
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}