Decompiled source of NoTerrainPenalty v1.0.2

NoTerrainPenalty.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NoTerrainPenalty")]
[assembly: AssemblyDescription("Only creatures count toward the melee multi-hit damage penalty in Valheim")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.2.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 NoTerrainPenalty
{
	[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
	public static class MeleePatch
	{
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			FieldInfo fieldInfo = AccessTools.Field(typeof(HitPoint), "go");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(Attack), "m_lowerDamagePerHit");
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(List<HitPoint>), "Count");
			MethodInfo methodInfo2 = AccessTools.Method(typeof(MeleePatch), "CountForPenalty", (Type[])null, (Type[])null);
			CodeInstruction val = null;
			int num = -1;
			for (int i = 0; i < list.Count - 1; i++)
			{
				if (num >= 0)
				{
					break;
				}
				if (CodeInstructionExtensions.LoadsField(list[i], fieldInfo, false) && CodeInstructionExtensions.IsStloc(list[i + 1], (LocalBuilder)null))
				{
					val = list[i + 1];
				}
				if (CodeInstructionExtensions.LoadsField(list[i], fieldInfo2, false))
				{
					num = i;
				}
			}
			List<int> list2 = new List<int>();
			int num2 = num + 1;
			while (num >= 0 && num2 < list.Count && list2.Count < 2)
			{
				if (CodeInstructionExtensions.Calls(list[num2], methodInfo))
				{
					list2.Add(num2);
				}
				num2++;
			}
			if (val == null || list2.Count != 2 || list2[1] - num > 12)
			{
				Plugin.Log.LogError((object)"could not find the multi-hit penalty in Attack.DoMeleeAttack (game update?), mod inactive");
				return list;
			}
			int[] array = new int[2]
			{
				list2[1],
				list2[0]
			};
			foreach (int index in array)
			{
				CodeInstruction val2 = CodeInstructionExtensions.MoveLabelsFrom(LoadLocal(val), list[index]);
				list[index] = new CodeInstruction(OpCodes.Call, (object)methodInfo2);
				list.InsertRange(index, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
				{
					val2,
					new CodeInstruction(OpCodes.Ldarg_0, (object)null)
				});
			}
			Plugin.Log.LogInfo((object)"patched the multi-hit penalty in Attack.DoMeleeAttack");
			return list;
		}

		public static int CountForPenalty(List<HitPoint> hits, GameObject hitObject, Attack attack)
		{
			if (!IsCreature(hitObject) || !Plugin.Applies(attack))
			{
				return hits.Count;
			}
			return hits.Count((HitPoint h) => IsCreature(h.go));
		}

		private static bool IsCreature(GameObject go)
		{
			if ((Object)(object)go != (Object)null)
			{
				return (Object)(object)go.GetComponent<Character>() != (Object)null;
			}
			return false;
		}

		private static CodeInstruction LoadLocal(CodeInstruction store)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			if (!(store.opcode == OpCodes.Stloc_0))
			{
				if (!(store.opcode == OpCodes.Stloc_1))
				{
					if (!(store.opcode == OpCodes.Stloc_2))
					{
						if (!(store.opcode == OpCodes.Stloc_3))
						{
							return new CodeInstruction(OpCodes.Ldloc, store.operand);
						}
						return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
					}
					return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
				}
				return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
			}
			return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
		}
	}
	[BepInPlugin("onononoki.NoTerrainPenalty", "NoTerrainPenalty", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "onononoki.NoTerrainPenalty";

		public const string ModName = "NoTerrainPenalty";

		public const string ModVersion = "1.0.2";

		internal static ManualLogSource Log;

		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<bool> _primary;

		private static ConfigEntry<bool> _secondary;

		private static ConfigEntry<string> _excludedSkills;

		private static ConfigEntry<string> _excludedItems;

		private static HashSet<string> _skipSkills = new HashSet<string>();

		private static HashSet<string> _skipItems = new HashSet<string>();

		private static readonly HashSet<ItemType> WeaponTypes = new HashSet<ItemType>
		{
			(ItemType)3,
			(ItemType)14,
			(ItemType)22
		};

		private static readonly FieldRef<Attack, Humanoid> AttackCharacter = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		private static readonly FieldRef<Attack, ItemData> AttackWeapon = AccessTools.FieldRefAccess<Attack, ItemData>("m_weapon");

		private static readonly FieldRef<Humanoid, bool> CurrentAttackIsSecondary = AccessTools.FieldRefAccess<Humanoid, bool>("m_currentAttackIsSecondary");

		private void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Only creatures (players, mobs, bosses) count toward the melee multi-hit damage penalty. Ground, walls, rocks, trees and building pieces no longer lower damage to creatures.", (AcceptableValueBase)null, new object[1] { val }));
			_primary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PrimaryAttack", true, new ConfigDescription("Apply to primary attacks.", (AcceptableValueBase)null, new object[1] { val }));
			_secondary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SecondaryAttack", true, new ConfigDescription("Apply to secondary attacks.", (AcceptableValueBase)null, new object[1] { val }));
			_excludedSkills = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "ExcludedSkills", "", new ConfigDescription("Comma separated weapon skill types to leave vanilla (Swords, Knives, Clubs, Polearms, Spears, Axes, Pickaxes).", (AcceptableValueBase)null, new object[1] { val }));
			_excludedItems = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "ExcludedItems", "", new ConfigDescription("Comma separated item prefab names to leave vanilla (example: THSwordKrom, SwordIron).", (AcceptableValueBase)null, new object[1] { val }));
			ParseFilters();
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				ParseFilters();
			};
			Harmony.CreateAndPatchAll(typeof(MeleePatch), "onononoki.NoTerrainPenalty");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"NoTerrainPenalty 1.0.2 loaded");
		}

		private static void ParseFilters()
		{
			_skipSkills = ParseList(_excludedSkills.Value);
			_skipItems = ParseList(_excludedItems.Value);
		}

		private static HashSet<string> ParseList(string value)
		{
			return new HashSet<string>(from s in (value ?? "").Split(new char[1] { ',' })
				select s.Trim() into s
				where s.Length > 0
				select s, StringComparer.OrdinalIgnoreCase);
		}

		internal static bool Applies(Attack attack)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!_enabled.Value)
			{
				return false;
			}
			Humanoid obj = AttackCharacter.Invoke(attack);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val == null)
			{
				return false;
			}
			ItemData val2 = AttackWeapon.Invoke(attack);
			if (val2?.m_shared == null || !WeaponTypes.Contains(val2.m_shared.m_itemType))
			{
				return false;
			}
			if (!(CurrentAttackIsSecondary.Invoke((Humanoid)(object)val) ? _secondary.Value : _primary.Value))
			{
				return false;
			}
			if (_skipSkills.Contains(((object)Unsafe.As<SkillType, SkillType>(ref val2.m_shared.m_skillType)/*cast due to .constrained prefix*/).ToString()))
			{
				return false;
			}
			if (_skipItems.Count == 0)
			{
				return true;
			}
			GameObject dropPrefab = val2.m_dropPrefab;
			if (!((Object)(object)dropPrefab == (Object)null))
			{
				return !_skipItems.Contains(((Object)dropPrefab).name);
			}
			return true;
		}
	}
}