Decompiled source of OneHandedEarlyAxe v0.1.0

plugins/OneHandedEarlyAxe/OneHandedEarlyAxe.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyTitle("One-Handed Early Axe")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace OneHandedEarlyAxe;

[BepInPlugin("au.tyvalheim.onehandedearlyaxe", "One-Handed Early Axe", "0.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	private static class DB
	{
		private static void Prefix(ObjectDB __instance)
		{
			Instance.Register(__instance);
		}

		private static void Postfix()
		{
			Instance.Network(ZNetScene.instance);
		}
	}

	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	private static class CopyDB
	{
		private static void Postfix(ObjectDB __instance)
		{
			Instance.Register(__instance);
			AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null).Invoke(__instance, null);
			Instance.Network(ZNetScene.instance);
		}
	}

	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	private static class Scene
	{
		private static void Prefix(ZNetScene __instance)
		{
			Instance.Register(ObjectDB.instance);
			if (Instance.failed)
			{
				return;
			}
			foreach (GameObject value in Instance.prefabs.Values)
			{
				if (!__instance.m_prefabs.Contains(value))
				{
					__instance.m_prefabs.Add(value);
				}
			}
		}

		private static void Postfix(ZNetScene __instance)
		{
			Instance.Network(__instance);
		}
	}

	[HarmonyPatch(typeof(Attack), "Start")]
	private static class StartAttack
	{
		private static void Postfix(bool __result, ItemData ___m_weapon, ZSyncAnimation ___m_zanim)
		{
			if (__result && IsSingle(___m_weapon) && Object.op_Implicit((Object)(object)___m_zanim))
			{
				___m_zanim.SetSpeed(Instance.SwingSpeed.Value);
			}
		}
	}

	[HarmonyPatch(typeof(CharacterAnimEvent), "Speed")]
	private static class AnimationSpeed
	{
		private static void Prefix(ref float __0, Character ___m_character)
		{
			Humanoid val = (Humanoid)(object)((___m_character is Humanoid) ? ___m_character : null);
			if (Object.op_Implicit((Object)(object)val) && ((Character)val).InAttack() && IsSingle(val.GetCurrentWeapon()))
			{
				__0 *= Instance.SwingSpeed.Value;
			}
		}
	}

	public const string Id = "au.tyvalheim.onehandedearlyaxe";

	public const string Version = "0.1.0";

	public const string PrefabName = "OHEA_AxeEarly";

	internal static Plugin Instance;

	internal static readonly MethodInfo CloneObject = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null);

	internal ConfigEntry<float> SwingSpeed;

	internal static readonly string[] Sources = new string[1] { "AxeEarly" };

	internal static readonly string[] Names = new string[1] { "OHEA_AxeEarly" };

	internal static readonly string[] Titles = new string[1] { "One-handed Early Axe" };

	private GameObject root;

	private readonly Dictionary<string, GameObject> prefabs = new Dictionary<string, GameObject>();

	private readonly Dictionary<string, Recipe> recipes = new Dictionary<string, Recipe>();

	private bool failed;

	private void Awake()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		SwingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Combat", "AttackSpeed", 1.25f, new ConfigDescription("One-handed axe animation speed multiplier. 1 = normal; 1.25 = 25% faster. Use matching settings on all peers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 2f), new object[0]));
		root = new GameObject("OneHandedEarlyAxe_Prefabs");
		root.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)root);
		new Harmony("au.tyvalheim.onehandedearlyaxe").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"One-Handed Early Axe 0.1.0 loaded.");
	}

	internal static T Copy<T>(T value) where T : class
	{
		return (T)CloneObject.Invoke(value, null);
	}

	internal static GameObject CreateItem(GameObject source, GameObject axe, Transform parent)
	{
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(source, parent, false);
		try
		{
			int num = Array.IndexOf(Sources, ((Object)source).name);
			if (num < 0)
			{
				throw new InvalidOperationException("Unknown Early Axe source.");
			}
			((Object)val).name = Names[num];
			ItemDrop component = val.GetComponent<ItemDrop>();
			component.m_itemData = source.GetComponent<ItemDrop>().m_itemData.Clone();
			SharedData val2 = (component.m_itemData.m_shared = Copy<SharedData>(component.m_itemData.m_shared));
			SharedData shared = axe.GetComponent<ItemDrop>().m_itemData.m_shared;
			val2.m_name = Titles[num];
			val2.m_description = component.m_itemData.m_shared.m_description + "\nForged for a single hand. Leaves your other hand free for a shield.";
			val2.m_itemType = shared.m_itemType;
			val2.m_animationState = shared.m_animationState;
			val2.m_attachOverride = shared.m_attachOverride;
			val2.m_attack = Copy<Attack>(val2.m_attack);
			val2.m_secondaryAttack = Copy<Attack>(val2.m_secondaryAttack);
			AdaptAnimation(val2.m_attack, shared.m_attack);
			AdaptAnimation(val2.m_secondaryAttack, shared.m_secondaryAttack);
			component.m_itemData.m_dropPrefab = val;
			BuildVisual(val, axe);
			val.SetActive(true);
			return val;
		}
		catch
		{
			Object.DestroyImmediate((Object)(object)val);
			throw;
		}
	}

	private static void AdaptAnimation(Attack target, Attack template)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		target.m_attackAnimation = template.m_attackAnimation;
		target.m_attackChainLevels = template.m_attackChainLevels;
		target.m_attackRandomAnimations = template.m_attackRandomAnimations;
		target.m_attackType = template.m_attackType;
	}

	private static void BuildVisual(GameObject item, GameObject axe)
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: 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_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		Transform val = item.transform.Find("attach");
		MeshFilter[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshFilter>(true);
		if (componentsInChildren.Length == 2 && Object.op_Implicit((Object)(object)((Component)componentsInChildren[1]).transform.Find("UpgraderGlow (1)")))
		{
			Bounds bounds = componentsInChildren[1].sharedMesh.bounds;
			if (!(Mathf.Abs(((Bounds)(ref bounds)).size.z - 0.70629f) > 0.01f))
			{
				Transform transform = new GameObject("single_attach").transform;
				transform.SetParent(item.transform, false);
				Transform val2 = axe.transform.Find("attach");
				transform.localPosition = val2.localPosition;
				transform.localRotation = val2.localRotation;
				Transform transform2 = ((Component)componentsInChildren[1]).transform;
				transform2.SetParent(transform, false);
				((Object)transform2).name = "EarlyAxeRight";
				transform2.localPosition = new Vector3(0.02f, 0.0056f, 0.22f);
				transform2.localRotation = Quaternion.Euler(0f, 0f, 180f);
				transform2.localScale = Vector3.one;
				Transform val3 = val2.Find("equiped");
				if (!Object.op_Implicit((Object)(object)val3))
				{
					throw new InvalidOperationException("Native one-handed trail missing.");
				}
				Transform transform3 = Object.Instantiate<GameObject>(((Component)val3).gameObject, transform, false).transform;
				((Object)transform3).name = "equiped";
				transform3.Find("trail/base").localPosition = new Vector3(0.19f, 0f, 0.36f);
				transform3.Find("trail/tip").localPosition = new Vector3(0.19f, 0f, 0.55f);
				BoxCollider val4 = ((Component)transform2).gameObject.AddComponent<BoxCollider>();
				Bounds bounds2 = componentsInChildren[1].sharedMesh.bounds;
				val4.center = ((Bounds)(ref bounds2)).center;
				Bounds bounds3 = componentsInChildren[1].sharedMesh.bounds;
				val4.size = ((Bounds)(ref bounds3)).size;
				Transform[] array = ((IEnumerable)item.transform).Cast<Transform>().ToArray();
				foreach (Transform val5 in array)
				{
					if ((Object)(object)val5 != (Object)(object)transform && (((Object)val5).name == "attach" || ((Object)val5).name == "attach_skin" || ((Object)val5).name == "attach_back"))
					{
						Object.DestroyImmediate((Object)(object)((Component)val5).gameObject);
					}
				}
				((Object)transform).name = "attach";
				return;
			}
		}
		throw new InvalidOperationException("AxeEarly visual layout changed; inspect the native assets before updating.");
	}

	internal static Recipe CreateRecipe(Recipe source, GameObject item)
	{
		Recipe val = Object.Instantiate<Recipe>(source);
		((Object)val).name = "Recipe_" + ((Object)item).name;
		val.m_item = item.GetComponent<ItemDrop>();
		val.m_resources = source.m_resources.Select(Copy<Requirement>).ToArray();
		return val;
	}

	internal void Register(ObjectDB db)
	{
		if (failed || !Object.op_Implicit((Object)(object)db))
		{
			return;
		}
		try
		{
			GameObject val = ((IEnumerable<GameObject>)db.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == "AxeBronze"));
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			int i;
			for (i = 0; i < Sources.Length; i++)
			{
				GameObject val2 = ((IEnumerable<GameObject>)db.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == Sources[i]));
				if (Object.op_Implicit((Object)(object)val2) && !prefabs.ContainsKey(Sources[i]))
				{
					if (db.m_items.Any((GameObject x) => Object.op_Implicit((Object)(object)x) && StringExtensionMethods.GetStableHashCode(((Object)x).name) == StringExtensionMethods.GetStableHashCode(Names[i])))
					{
						throw new InvalidOperationException("One-Handed Early Axe prefab name/hash collision.");
					}
					prefabs.Add(Sources[i], CreateItem(val2, val, root.transform));
				}
			}
			foreach (KeyValuePair<string, GameObject> pair in prefabs)
			{
				List<GameObject> items = db.m_items;
				KeyValuePair<string, GameObject> keyValuePair = pair;
				if (!items.Contains(keyValuePair.Value))
				{
					List<GameObject> items2 = db.m_items;
					KeyValuePair<string, GameObject> keyValuePair2 = pair;
					items2.Add(keyValuePair2.Value);
				}
				Recipe val3 = ((IEnumerable<Recipe>)db.m_recipes).FirstOrDefault((Func<Recipe, bool>)delegate(Recipe x)
				{
					if (Object.op_Implicit((Object)(object)x) && Object.op_Implicit((Object)(object)x.m_item))
					{
						string name = ((Object)x.m_item).name;
						KeyValuePair<string, GameObject> keyValuePair7 = pair;
						return name == keyValuePair7.Key;
					}
					return false;
				});
				if (Object.op_Implicit((Object)(object)val3) && prefabs.ContainsKey(Sources[0]))
				{
					Dictionary<string, Recipe> dictionary = recipes;
					KeyValuePair<string, GameObject> keyValuePair3 = pair;
					if (!dictionary.TryGetValue(keyValuePair3.Key, out var value))
					{
						KeyValuePair<string, GameObject> keyValuePair4 = pair;
						value = CreateRecipe(val3, keyValuePair4.Value);
						Dictionary<string, Recipe> dictionary2 = recipes;
						KeyValuePair<string, GameObject> keyValuePair5 = pair;
						dictionary2.Add(keyValuePair5.Key, value);
						ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
						object[] array = new object[6] { "Registered ", null, null, null, null, null };
						KeyValuePair<string, GameObject> keyValuePair6 = pair;
						array[1] = ((Object)keyValuePair6.Value).name;
						array[2] = " with native recipe at ";
						array[3] = ((Object)val3.m_craftingStation).name;
						array[4] = ", level ";
						array[5] = val3.m_minStationLevel;
						logger.LogInfo((object)string.Concat(array));
					}
					if (!db.m_recipes.Contains(value))
					{
						db.m_recipes.Add(value);
					}
				}
			}
		}
		catch (Exception ex)
		{
			failed = true;
			((BaseUnityPlugin)this).Logger.LogError((object)("One-Handed Early Axe registration failed: " + ex));
		}
	}

	internal void Network(ZNetScene scene)
	{
		if (!Object.op_Implicit((Object)(object)scene) || failed)
		{
			return;
		}
		Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene);
		foreach (GameObject value2 in prefabs.Values)
		{
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)value2).name);
			if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value != (Object)(object)value2)
			{
				throw new InvalidOperationException("One-Handed Early Axe prefab hash collision.");
			}
			if (!scene.m_prefabs.Contains(value2))
			{
				scene.m_prefabs.Add(value2);
			}
			dictionary[stableHashCode] = value2;
		}
	}

	internal static bool IsSingle(ItemData item)
	{
		if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab))
		{
			return Array.IndexOf(Names, ((Object)item.m_dropPrefab).name) >= 0;
		}
		return false;
	}
}
internal static class VanillaVisuals
{
	[HarmonyPatch(typeof(VisEquipment), "SetRightItemVisual")]
	private static class PublishHand
	{
		[HarmonyAfter(new string[] { "au.tyvalheim.singleberserkir" })]
		private static void Postfix(int __0, ZNetView ___m_nview, bool ___m_isPlayer)
		{
			if (___m_isPlayer && Object.op_Implicit((Object)(object)___m_nview))
			{
				Publish(___m_nview.GetZDO(), ___m_nview.IsOwner(), ZDOVars.s_rightItem, HandKey, __0);
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetRightBackItem")]
	private static class PublishBack
	{
		[HarmonyAfter(new string[] { "au.tyvalheim.singleberserkir" })]
		private static void Postfix(int __0, ZNetView ___m_nview, bool ___m_isPlayer)
		{
			if (___m_isPlayer && Object.op_Implicit((Object)(object)___m_nview))
			{
				Publish(___m_nview.GetZDO(), ___m_nview.IsOwner(), ZDOVars.s_rightBackItem, BackKey, __0);
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetRightHandEquipped")]
	private static class ResolveHand
	{
		private static void Prefix(ref int __0, ZNetView ___m_nview, bool ___m_isPlayer)
		{
			if (___m_isPlayer && Object.op_Implicit((Object)(object)___m_nview))
			{
				__0 = Resolve(___m_nview.GetZDO(), HandKey, __0);
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetBackEquipped")]
	private static class ResolveBack
	{
		private static void Prefix(ref int __1, ZNetView ___m_nview, bool ___m_isPlayer)
		{
			if (___m_isPlayer && Object.op_Implicit((Object)(object)___m_nview))
			{
				__1 = Resolve(___m_nview.GetZDO(), BackKey, __1);
			}
		}
	}

	internal static readonly int Fallback = StringExtensionMethods.GetStableHashCode("AxeBronze");

	internal static readonly int HandKey = StringExtensionMethods.GetStableHashCode("au.tyvalheim.onehandedearlyaxe.rightHand");

	internal static readonly int BackKey = StringExtensionMethods.GetStableHashCode("au.tyvalheim.onehandedearlyaxe.rightBack");

	private static readonly int[] Custom = Array.ConvertAll(Plugin.Names, (string n) => StringExtensionMethods.GetStableHashCode(n));

	internal static bool IsCustom(int hash)
	{
		return Array.IndexOf(Custom, hash) >= 0;
	}

	internal static void Publish(ZDO data, bool owner, int slot, int marker, int actual)
	{
		if (data != null && owner)
		{
			bool flag = IsCustom(actual);
			data.Set(marker, flag ? actual : 0, false);
			if (flag)
			{
				data.Set(slot, Fallback, false);
			}
		}
	}

	internal static int Resolve(ZDO data, int marker, int publicHash)
	{
		if (data == null || publicHash != Fallback)
		{
			return publicHash;
		}
		int num = data.GetInt(marker, 0);
		if (!IsCustom(num) || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ObjectDB.instance.GetItemPrefab(num)))
		{
			return publicHash;
		}
		return num;
	}
}