Decompiled source of CrownedButcher v1.0.0

CrownedButcher.dll

Decompiled 2 weeks 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 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("CrownedButcher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CrownedButcher")]
[assembly: AssemblyTitle("CrownedButcher")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CrownedButcher
{
	public static class Butchery
	{
		private const string CrownPrefab = "HelmetCrownofValheim";

		private const string KnifePrefab = "KnifeButcher";

		private static readonly int ArmedKey = StringExtensionMethods.GetStableHashCode("CrownedButcher_Armed");

		private static readonly int ExecutedKey = StringExtensionMethods.GetStableHashCode("CrownedButcher_Executed");

		public static void UpdateArmed(Player player)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
			{
				List<ItemData> equippedItems = ((Humanoid)player).GetInventory().GetEquippedItems();
				bool flag = equippedItems.Exists((ItemData i) => IsPrefab(i, "HelmetCrownofValheim")) && equippedItems.Exists((ItemData i) => IsPrefab(i, "KnifeButcher"));
				component.GetZDO().Set(ArmedKey, flag);
			}
		}

		public static bool CanHit(Character target, Humanoid attacker)
		{
			if (!target.IsTamed())
			{
				return CanExecute((Character)(object)attacker, target);
			}
			return true;
		}

		public static bool IsExecution(Character target, HitData hit)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)hit.m_hitType != 2 || hit.m_ranged)
			{
				return false;
			}
			return CanExecute(hit.GetAttacker(), target);
		}

		public static void MarkExecuted(Character target)
		{
			((Component)target).GetComponent<ZNetView>().GetZDO().Set(ExecutedKey, true);
		}

		public static bool WasExecuted(Component mob)
		{
			ZNetView component = mob.GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				return component.GetZDO().GetBool(ExecutedKey, false);
			}
			return false;
		}

		private static bool CanExecute(Character attacker, Character target)
		{
			if (!(attacker is Player) || target.IsPlayer() || target.IsBoss())
			{
				return false;
			}
			if ((Object)(object)((Component)target).GetComponent<Piece>() != (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)attacker).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				return component.GetZDO().GetBool(ArmedKey, false);
			}
			return false;
		}

		private static bool IsPrefab(ItemData item, string name)
		{
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name == name;
			}
			return false;
		}
	}
	[BepInPlugin("lance.crownedbutcher", "Crowned Butcher", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private const string Guid = "lance.crownedbutcher";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> GuaranteeTrophy;

		private Harmony harmony;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			GuaranteeTrophy = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GuaranteeTrophy", true, "Mobs you execute always drop their trophy (if they have one).");
			harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "lance.crownedbutcher");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
}
namespace CrownedButcher.Patches
{
	[HarmonyPatch(typeof(Humanoid), "SetupEquipment")]
	internal static class EquipmentPatch
	{
		private static void Postfix(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				Butchery.UpdateArmed(val);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class ExecutePatch
	{
		private static void Prefix(Character __instance, HitData hit, out bool __state)
		{
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			__state = (Object)(object)component != (Object)null && component.IsValid() && component.IsOwner() && Butchery.IsExecution(__instance, hit);
			if (__state)
			{
				hit.m_blockable = false;
				hit.m_dodgeable = false;
				hit.m_damage.m_damage += __instance.GetHealth();
				Butchery.MarkExecuted(__instance);
			}
		}

		private static void Postfix(Character __instance, bool __state)
		{
			if (__state && __instance.GetHealth() > 0f)
			{
				__instance.SetHealth(0f);
			}
		}
	}
	[HarmonyPatch]
	internal static class TamedOnlyPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from m in AccessTools.GetDeclaredMethods(typeof(Attack))
				where m.Name == "DoMeleeAttack" || m.Name.Contains("checkHits")
				select m;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			FieldInfo tamedOnly = AccessTools.Field(typeof(SharedData), "m_tamedOnly");
			MethodInfo isTamed = AccessTools.Method(typeof(Character), "IsTamed", Type.EmptyTypes, (Type[])null);
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(true, (CodeMatch[])(object)new CodeMatch[4]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, tamedOnly, false)), (string)null),
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => i.opcode == OpCodes.Brfalse || i.opcode == OpCodes.Brfalse_S), (string)null),
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => CodeInstructionExtensions.IsLdloc(i, (LocalBuilder)null)), (string)null),
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, isTamed)), (string)null)
			});
			if (val.IsInvalid)
			{
				Plugin.Log.LogError((object)("Couldn't find the tamed check in " + original.Name + ", did the game update?"));
				return val.InstructionEnumeration();
			}
			val.SetInstruction(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Butchery), "CanHit", (Type[])null, (Type[])null)));
			val.Insert((CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Attack), "m_character"))
			});
			return val.InstructionEnumeration();
		}
	}
	[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
	internal static class TrophyPatch
	{
		private static void Postfix(CharacterDrop __instance, List<KeyValuePair<GameObject, int>> __result)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			if (!Plugin.GuaranteeTrophy.Value || !Butchery.WasExecuted((Component)(object)__instance))
			{
				return;
			}
			foreach (Drop drop in __instance.m_drops)
			{
				if (!((Object)(object)drop.m_prefab == (Object)null))
				{
					ItemDrop component = drop.m_prefab.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && (int)component.m_itemData.m_shared.m_itemType == 13 && !__result.Exists((KeyValuePair<GameObject, int> d) => (Object)(object)d.Key == (Object)(object)drop.m_prefab))
					{
						__result.Add(new KeyValuePair<GameObject, int>(drop.m_prefab, 1));
					}
				}
			}
		}
	}
}