Decompiled source of SingleBerserkir v0.1.1

BepInEx/plugins/SingleBerserkir/SingleBerserkir.dll

Decompiled a week 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: AssemblyMetadata("AI_Assisted_Creation", "Coded with the assistance of ChatGPT 6.0; packaged with OpenAI Codex.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "OpenAI")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace SingleBerserkir;

[BepInPlugin("au.tyvalheim.singleberserkir", "Single Berserkir", "0.1.1")]
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.singleberserkir";

	public const string Version = "0.1.1";

	public const string PrefabName = "SB_AxeBerserkir";

	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[4] { "AxeBerzerkr", "AxeBerzerkrBlood", "AxeBerzerkrNature", "AxeBerzerkrLightning" };

	internal static readonly string[] Names = new string[4] { "SB_AxeBerserkir", "SB_AxeBerserkirBlood", "SB_AxeBerserkirNature", "SB_AxeBerserkirLightning" };

	internal static readonly string[] Titles = new string[4] { "Berserkir axe", "Bleeding Berserkir axe", "Primal Berserkir axe", "Thundering Berserkir 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("SingleBerserkir_Prefabs");
		root.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)root);
		new Harmony("au.tyvalheim.singleberserkir").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Single Berserkir 0.1.1 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 Berserkir variant.");
			}
			((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_007f: 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_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Expected O, but got Unknown
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		Transform val = item.transform.Find("attach");
		MeshFilter val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponentsInChildren<MeshFilter>(true).FirstOrDefault() : null);
		Transform val3 = axe.transform.Find("attach");
		MeshFilter val4 = (Object.op_Implicit((Object)(object)val3) ? ((Component)val3).GetComponentsInChildren<MeshFilter>(true).FirstOrDefault() : null);
		if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val2.sharedMesh))
		{
			throw new InvalidOperationException("Native axe visual layout changed.");
		}
		Transform transform = new GameObject("single_attach").transform;
		transform.SetParent(item.transform, false);
		GameObject val5 = Object.Instantiate<GameObject>(((Component)val2).gameObject, transform, false);
		((Object)val5).name = "BerserkirModel";
		val5.transform.localPosition = val3.InverseTransformPoint(((Component)val4).transform.position);
		val5.transform.localRotation = Quaternion.Inverse(val3.rotation) * ((Component)val4).transform.rotation;
		val5.transform.localScale = ((Component)val4).transform.localScale;
		foreach (Transform item2 in val)
		{
			Transform val6 = item2;
			if (!Object.op_Implicit((Object)(object)((Component)val6).GetComponent<MeshFilter>()))
			{
				Vector3 localPosition = ((Component)val2).transform.InverseTransformPoint(val6.position);
				Quaternion localRotation = Quaternion.Inverse(((Component)val2).transform.rotation) * val6.rotation;
				GameObject val7 = Object.Instantiate<GameObject>(((Component)val6).gameObject, val5.transform, false);
				val7.transform.localPosition = localPosition;
				val7.transform.localRotation = localRotation;
			}
		}
		Transform val8 = ((IEnumerable<Transform>)((Component)val3).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "equiped"));
		if (Object.op_Implicit((Object)(object)val8))
		{
			((Object)Object.Instantiate<GameObject>(((Component)val8).gameObject, transform, false)).name = "equiped";
		}
		Transform[] array = ((IEnumerable)item.transform).Cast<Transform>().ToArray();
		foreach (Transform val9 in array)
		{
			if ((Object)(object)val9 != (Object)(object)transform && (((Object)val9).name == "attach" || ((Object)val9).name == "attach_skin" || ((Object)val9).name == "attach_back"))
			{
				Object.DestroyImmediate((Object)(object)((Component)val9).gameObject);
			}
		}
		((Object)transform).name = "attach";
	}

	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 == "AxeBlackMetal"));
			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) && ((Object)x).name == Names[i]))
					{
						throw new InvalidOperationException("Duplicate Single Berserkir prefab name.");
					}
					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]))
				{
					continue;
				}
				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);
					Requirement[] resources = value.m_resources;
					foreach (Requirement val4 in resources)
					{
						if (Object.op_Implicit((Object)(object)val4.m_resItem) && prefabs.TryGetValue(((Object)val4.m_resItem).name, out var value2))
						{
							val4.m_resItem = value2.GetComponent<ItemDrop>();
						}
					}
					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)("Single Berserkir 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("Single Berserkir 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
	{
		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
	{
		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("AxeBlackMetal");

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

	internal static readonly int BackKey = StringExtensionMethods.GetStableHashCode("au.tyvalheim.singleberserkir.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);
			data.Set(slot, flag ? Fallback : actual, 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;
	}
}