Decompiled source of ArcherQuiverSlot v0.1.12

plugins/ArcherQuiverSlot/ArcherQuiverSlot.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraSlots;
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("ArcherQuiverSlot")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.12.0")]
[assembly: AssemblyInformationalVersion("0.1.12")]
[assembly: AssemblyProduct("ArcherQuiverSlot")]
[assembly: AssemblyTitle("ArcherQuiverSlot")]
[assembly: AssemblyVersion("0.1.12.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 Vercadi.ArcherQuiverSlot
{
	internal static class BetterArcheryCompatibility
	{
		internal const string ReviewedHash = "941009C601F0386B1F843B3EAD73D9E2DF57EE85CDF0C8EA3306225DE01A125D";

		internal static Action Install(ManualLogSource log)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.TryGetValue("ishid4.mods.betterarchery", out var value))
			{
				return null;
			}
			Harmony val = new Harmony("vercadi.ArcherQuiverSlot.BetterArchery");
			try
			{
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				using (FileStream inputStream = File.OpenRead(assembly.Location))
				{
					using SHA256 sHA = SHA256.Create();
					if (value.Metadata.Version.ToString() != "2.0.2" || BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "") != "941009C601F0386B1F843B3EAD73D9E2DF57EE85CDF0C8EA3306225DE01A125D")
					{
						throw new NotSupportedException("BetterArchery binary differs from the reviewed 2.0.2 release.");
					}
				}
				MethodInfo[] array = ResolveTargets(assembly);
				foreach (MethodInfo methodInfo in array)
				{
					val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BetterArcheryCompatibility), "ResolveSuppliedAmmo", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
				}
				log.LogInfo((object)"ACTIVE: BetterArchery 2.0.2 now resolves quiver ammunition for its existing arrow speed, accuracy and aim-offset settings. No damage, inventory or ammunition consumption changes.");
				return val.UnpatchSelf;
			}
			catch (Exception ex)
			{
				val.UnpatchSelf();
				log.LogWarning((object)("Quiver slot remains available, but BetterArchery compatibility was not applied: " + ex.Message));
				return null;
			}
		}

		internal static MethodInfo[] ResolveTargets(Assembly assembly)
		{
			MethodInfo method = assembly.GetType("BetterArchery.Attack_FireProjectileBurst_Patch", throwOnError: true).GetMethod("Prefix", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Attack).MakeByRefType() }, null);
			MethodInfo method2 = assembly.GetType("BetterArchery.Attack_GetProjectileSpawnPoint_Patch", throwOnError: true).GetMethod("Postfix", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
			{
				typeof(Attack).MakeByRefType(),
				typeof(Vector3).MakeByRefType(),
				typeof(Vector3).MakeByRefType()
			}, null);
			if (method == null || !method.IsStatic || method.ReturnType != typeof(bool) || method2 == null || !method2.IsStatic || method2.ReturnType != typeof(void))
			{
				throw new MissingMethodException("BetterArchery projectile or aim-offset patch signature changed.");
			}
			return new MethodInfo[2] { method, method2 };
		}

		internal static IEnumerable<CodeInstruction> ResolveSuppliedAmmo(IEnumerable<CodeInstruction> source)
		{
			List<CodeInstruction> code = source.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction instruction) => new CodeInstruction(instruction))).ToList();
			FieldInfo player = typeof(Player).GetField("m_localPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo ammo = typeof(Humanoid).GetField("m_ammoItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo method = typeof(Humanoid).GetMethod("GetAmmoItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			int[] array = (from i in Enumerable.Range(1, Math.Max(0, code.Count - 1))
				where code[i - 1].opcode == OpCodes.Ldsfld && object.Equals(code[i - 1].operand, player) && code[i].opcode == OpCodes.Ldfld && object.Equals(code[i].operand, ammo)
				select i).ToArray();
			if (method == null || array.Length != 1 || code.Count((CodeInstruction i) => i.opcode == OpCodes.Ldfld && object.Equals(i.operand, ammo)) != 1)
			{
				throw new NotSupportedException("Expected exactly one reviewed local-player ammunition field read.");
			}
			code[array[0]].opcode = OpCodes.Callvirt;
			code[array[0]].operand = method;
			return code;
		}
	}
	[BepInPlugin("vercadi.ArcherQuiverSlot", "Archer Quiver Slot", "0.1.12")]
	[BepInDependency("radamanto.Vikings_Archer", "1.2.1")]
	[BepInDependency("shudnal.ExtraSlots", "1.2.13")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("Azumatt.AzuExtendedPlayerInventory")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "vercadi.ArcherQuiverSlot";

		private const string ArcherGuid = "radamanto.Vikings_Archer";

		private const string ExtraSlotsGuid = "shudnal.ExtraSlots";

		private const string SlotId = "VercadiArcherQuiver";

		private const string DiscoveryItems = "RDA_quiver_01,RDA_quiver_02,RDA_quiver_03";

		private Func<ItemData, bool> isQuiver;

		private Func<bool> isEnabled;

		private Action removeArcheryCompatibility;

		private Action removeVisualCompatibility;

		private void Awake()
		{
			if (!SupportsVersions(InstalledVersion("radamanto.Vikings_Archer"), InstalledVersion("shudnal.ExtraSlots")))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Quiver slot not registered: supported versions are Vikings Archer 1.2.1 / 1.2.2 / 1.2.3 / 1.2.4 / 1.2.5 and ExtraSlots 1.2.13 / 1.2.14 / 1.2.15 / 1.2.16. Found " + InstalledVersion("radamanto.Vikings_Archer") + " and " + InstalledVersion("shudnal.ExtraSlots") + ". Review the bridge after updating either dependency."));
				return;
			}
			try
			{
				ResolvePredicates(((object)Chainloader.PluginInfos["radamanto.Vikings_Archer"].Instance).GetType().Assembly, InstalledVersion("radamanto.Vikings_Archer"), out isQuiver, out isEnabled);
				if (API.FindSlot("VercadiArcherQuiver") != null)
				{
					throw new InvalidOperationException("The quiver slot ID is already registered.");
				}
				if (!API.AddSlot("VercadiArcherQuiver", (Func<string>)(() => "Quiver"), (Func<ItemData, bool>)Fits, (Func<bool>)IsAvailable))
				{
					throw new InvalidOperationException("ExtraSlots has no free custom equipment slot.");
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered one discovery-gated quiver slot. Vikings Archer retains equipment, effects, visuals and ammunition handling. No tome slot added.");
				removeArcheryCompatibility = BetterArcheryCompatibility.Install(((BaseUnityPlugin)this).Logger);
				removeVisualCompatibility = QuiverVisualCompatibility.Install(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Quiver slot registration failed: " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			removeVisualCompatibility?.Invoke();
			removeArcheryCompatibility?.Invoke();
		}

		internal static bool SupportsVersions(string archer, string extraSlots)
		{
			switch (archer)
			{
			case "1.2.1":
			case "1.2.2":
			case "1.2.3":
			case "1.2.4":
			case "1.2.5":
				switch (extraSlots)
				{
				default:
					return extraSlots == "1.2.16";
				case "1.2.13":
				case "1.2.14":
				case "1.2.15":
					return true;
				}
			default:
				return false;
			}
		}

		internal static void ResolvePredicates(Assembly assembly, string version, out Func<ItemData, bool> itemPredicate, out Func<bool> enabledPredicate)
		{
			if (version != "1.2.1" && version != "1.2.2" && version != "1.2.3" && version != "1.2.4" && version != "1.2.5")
			{
				throw new NotSupportedException("Unreviewed Archer quiver API version.");
			}
			bool flag = version == "1.2.3" || version == "1.2.4" || version == "1.2.5";
			Type type = assembly.GetType(flag ? "Vikings_Archer.VikingsArcherQuiverAPI" : "Vikings_Archer.QuiverCustomSlotManager", throwOnError: true);
			MethodInfo method = type.GetMethod(flag ? "IsQuiver" : "IsQuiverItem", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(ItemData) }, null);
			if (method == null || method.ReturnType != typeof(bool))
			{
				throw new MissingMethodException("Vikings Archer quiver predicate changed.");
			}
			itemPredicate = (Func<ItemData, bool>)Delegate.CreateDelegate(typeof(Func<ItemData, bool>), method);
			if (flag)
			{
				enabledPredicate = () => true;
				return;
			}
			MethodInfo method2 = type.GetMethod("IsSlotSystemEnabled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method2 == null || method2.ReturnType != typeof(bool))
			{
				throw new MissingMethodException("Vikings Archer slot predicate changed.");
			}
			enabledPredicate = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), method2);
		}

		private static string InstalledVersion(string guid)
		{
			if (!Chainloader.PluginInfos.TryGetValue(guid, out var value))
			{
				return null;
			}
			return value.Metadata.Version.ToString();
		}

		private bool Fits(ItemData item)
		{
			if (item?.m_shared == null || (Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			switch (((Object)item.m_dropPrefab).name)
			{
			case "RDA_quiver_01":
			case "RDA_quiver_02":
			case "RDA_quiver_03":
				return isQuiver(item);
			default:
				return false;
			}
		}

		private bool IsAvailable()
		{
			if (isEnabled())
			{
				return API.IsAnyMaterialDiscovered("RDA_quiver_01,RDA_quiver_02,RDA_quiver_03");
			}
			return false;
		}
	}
	internal static class QuiverVisualCompatibility
	{
		internal const string ReviewedHash = "ECCF76B50C5112D6F012CCB0B8A097C725599DBFBAAB32A0B6547920D1F10E18";

		internal const string ReviewedHash123 = "794103B77EE65000F7E79E00988887B4F110666619A709C45EF0D924D4FD60B2";

		internal const string ReviewedHash124 = "9D6A5C2C8C21A1BB29DC7E7DE74F4D8B4D868C2A092D27C6D6BCA475F27C99AC";

		internal const string ReviewedHash125 = "9676C90A11F5A0BF7E08676D12350F9479D7A278985ED057C5007946F0E45B08";

		private static ConfigEntry<bool> enabled;

		private static ConfigEntry<float> vertical;

		private static ConfigEntry<float> sideways;

		private static ConfigEntry<float> rearward;

		private static ConfigEntry<float> pitch;

		private static ConfigEntry<float> yaw;

		private static ConfigEntry<float> roll;

		internal static Action Install(ConfigFile config, ManualLogSource log)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			Harmony val = new Harmony("vercadi.ArcherQuiverSlot.VisualOffset");
			try
			{
				PluginInfo val2 = Chainloader.PluginInfos["radamanto.Vikings_Archer"];
				Assembly assembly = ((object)val2.Instance).GetType().Assembly;
				using (FileStream inputStream = File.OpenRead(assembly.Location))
				{
					using SHA256 sHA = SHA256.Create();
					if (!SupportsVisual(val2.Metadata.Version.ToString(), BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "")))
					{
						throw new NotSupportedException("Lower-back placement requires a reviewed Vikings Archer 1.2.2, 1.2.3, 1.2.4 or 1.2.5 binary.");
					}
				}
				MethodInfo methodInfo = ResolveTarget(assembly);
				enabled = config.Bind<bool>("Quiver appearance", "Lower back placement", true, "Adjust the view-only quiver on this client, for your character and other players. Disable to restore Vikings Archer's original placement. Does not affect ammunition or equipment.");
				vertical = Distance(config, "Vertical offset", -0.4f, "Metres relative to the character. Negative moves down.");
				sideways = Distance(config, "Sideways offset", 0f, "Metres relative to the character. Positive moves right.");
				rearward = Distance(config, "Rearward offset", 0.1f, "Metres relative to the character. Positive moves behind the character.");
				pitch = Angle(config, "Pitch", 0f, "Extra rotation around the character's right axis, in degrees.");
				yaw = Angle(config, "Yaw", 15f, "Extra rotation around the character's up axis, in degrees.");
				roll = Angle(config, "Roll", -70f, "Sideways tilt around the character's forward axis, in degrees. -70 places the quiver across the lower back, with its top angled toward the character's right. Set all three angles to 0 for the original orientation.");
				val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(QuiverVisualCompatibility), (methodInfo.GetParameters()[0].ParameterType == typeof(Player)) ? "AfterApplyTransform" : "AfterApplyTransform123", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"ACTIVE: adjustable lower-back quiver appearance. Cosmetic client settings; ammunition and inventory are unchanged.");
				return val.UnpatchSelf;
			}
			catch (Exception ex)
			{
				val.UnpatchSelf();
				log.LogWarning((object)("Original quiver appearance retained: " + ex.Message));
				return null;
			}
		}

		private static ConfigEntry<float> Distance(ConfigFile config, string name, float value, string description)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return config.Bind<float>("Quiver appearance", name, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1.5f, 1.5f), Array.Empty<object>()));
		}

		private static ConfigEntry<float> Angle(ConfigFile config, string name, float value, string description)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return config.Bind<float>("Quiver appearance", name, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), Array.Empty<object>()));
		}

		internal static MethodInfo ResolveTarget(Assembly assembly)
		{
			Type type = assembly.GetType("Vikings_Archer.QuiverBackVisual", throwOnError: true);
			MethodInfo methodInfo = type.GetMethod("ApplyTransform", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(Player),
				typeof(Transform)
			}, null) ?? type.GetMethod("ApplyTransform", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(Transform),
				typeof(Transform)
			}, null);
			if (methodInfo == null || methodInfo.ReturnType != typeof(void))
			{
				throw new MissingMethodException("Vikings Archer visual attachment signature changed.");
			}
			return methodInfo;
		}

		internal static bool SupportsVisual(string version, string hash)
		{
			if ((!(version == "1.2.2") || !string.Equals(hash, "ECCF76B50C5112D6F012CCB0B8A097C725599DBFBAAB32A0B6547920D1F10E18", StringComparison.OrdinalIgnoreCase)) && (!(version == "1.2.3") || !string.Equals(hash, "794103B77EE65000F7E79E00988887B4F110666619A709C45EF0D924D4FD60B2", StringComparison.OrdinalIgnoreCase)) && (!(version == "1.2.4") || !string.Equals(hash, "9D6A5C2C8C21A1BB29DC7E7DE74F4D8B4D868C2A092D27C6D6BCA475F27C99AC", StringComparison.OrdinalIgnoreCase)))
			{
				if (version == "1.2.5")
				{
					return string.Equals(hash, "9676C90A11F5A0BF7E08676D12350F9479D7A278985ED057C5007946F0E45B08", StringComparison.OrdinalIgnoreCase);
				}
				return false;
			}
			return true;
		}

		private static void AfterApplyTransform123(Transform __0, Transform __1)
		{
			if (enabled != null && enabled.Value && !((Object)(object)__0 == (Object)null) && !((Object)(object)__1 == (Object)null) && !((Object)(object)__0.parent != (Object)(object)__1) && !(((Object)__1).name != "BackShield_attach"))
			{
				Player componentInParent = ((Component)__1).GetComponentInParent<Player>();
				if (!((Object)(object)componentInParent == (Object)null))
				{
					ApplyPlacement(((Component)componentInParent).transform, __0, vertical.Value, sideways.Value, rearward.Value, pitch.Value, yaw.Value, roll.Value);
				}
			}
		}

		private static void AfterApplyTransform(Player __0, Transform __1)
		{
			if (enabled != null && enabled.Value && !((Object)(object)__0 == (Object)null) && !((Object)(object)__1 == (Object)null))
			{
				ApplyPlacement(((Component)__0).transform, __1, vertical.Value, sideways.Value, rearward.Value, pitch.Value, yaw.Value, roll.Value);
			}
		}

		internal static void ApplyPlacement(Transform player, Transform visual, float downUp, float leftRight, float frontBack, float rotationX, float rotationY, float rotationZ)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_005f: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !((Object)(object)visual == (Object)null) && !((Object)(object)visual.parent == (Object)null) && !(((Object)visual.parent).name != "BackShield_attach"))
			{
				Vector3 val = player.up * Safe(downUp, 1.5f) + player.right * Safe(leftRight, 1.5f) - player.forward * Safe(frontBack, 1.5f);
				visual.localPosition = visual.parent.InverseTransformVector(val);
				Quaternion rotation = player.rotation;
				Quaternion val2 = rotation * Quaternion.Euler(Safe(rotationX, 180f), Safe(rotationY, 180f), Safe(rotationZ, 180f)) * Quaternion.Inverse(rotation);
				visual.rotation = val2 * visual.parent.rotation;
			}
		}

		internal static float Safe(float value, float bound)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return Math.Max(0f - bound, Math.Min(bound, value));
			}
			return 0f;
		}
	}
}