Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ArcherQuiverSlot v0.1.12
plugins/ArcherQuiverSlot/ArcherQuiverSlot.dll
Decompiled a month agousing 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; } } }