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 KnifeThrowAnimation v0.1.0
KnifeThrowAnim.dll
Decompiled 5 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; 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(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("KnifeThrowAnim")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("KnifeThrowAnim")] [assembly: AssemblyTitle("KnifeThrowAnim")] [assembly: AssemblyVersion("1.0.0.0")] namespace KnifeThrowAnim; [BepInPlugin("valheim.knifethrowanim", "Knife Throw Animation", "0.1.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "valheim.knifethrowanim"; public const string Name = "Knife Throw Animation"; public const string Version = "0.1.0"; internal const string BundleFile = "knifethrow.bundle"; internal const string ClipAsset = "KnifeThrow"; internal const string SpearTrigger = "spear_throw"; internal const string SpearClip = "throw_spear"; internal static ManualLogSource Log; internal static AnimationClip KnifeClip; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> RemotePlayers; internal static ConfigEntry<bool> SpawnFromHand; internal static ConfigEntry<float> SpawnForward; internal static ConfigEntry<float> SpawnUp; internal const string HandBone = "RightHand"; private void Awake() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Use the custom dagger-throw animation for thrown knives."); RemotePlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemotePlayers", true, "Also show it for other players' knife throws (judged by the weapon in their right hand)."); SpawnFromHand = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "FromHand", true, "Launch the thrown knife from the right hand (at the clip's release frame) instead of the spear's spawn point."); SpawnForward = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Forward", 0.2f, "Metres ahead of the hand (along the character's facing) where the knife appears."); SpawnUp = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Up", 0f, "Metres above the hand where the knife appears."); KnifeClip = LoadClip(); if (!((Object)(object)KnifeClip == (Object)null)) { new Harmony("valheim.knifethrowanim").PatchAll(typeof(Plugin).Assembly); } } private AnimationClip LoadClip() { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "knifethrow.bundle"); if (!File.Exists(text)) { Log.LogError((object)("Bundle not found: " + text)); return null; } AssetBundle val = AssetBundle.LoadFromFile(text); AnimationClip val2 = (((Object)(object)val != (Object)null) ? val.LoadAsset<AnimationClip>("KnifeThrow") : null); if ((Object)(object)val2 == (Object)null) { Log.LogError((object)("Clip 'KnifeThrow' not found in " + text)); return null; } if (!val2.events.Any((AnimationEvent e) => e.functionName == "OnAttackTrigger")) { Log.LogError((object)("Clip '" + ((Object)val2).name + "' has no OnAttackTrigger event; keeping the spear animation.")); return null; } Log.LogInfo((object)$"Loaded '{((Object)val2).name}' ({val2.length:0.###}s, {val2.events.Length} events)."); return val2; } } [HarmonyPatch(typeof(Attack), "Start")] internal static class SpawnFromHand { [HarmonyPriority(200)] private static void Prefix(Attack __instance, Humanoid character, ItemData weapon) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 if (Plugin.Enabled.Value && Plugin.SpawnFromHand.Value && !((Object)(object)character != (Object)(object)Player.m_localPlayer) && weapon != null && (int)weapon.m_shared.m_skillType == 2 && !(__instance.m_attackAnimation != "spear_throw") && !((Object)(object)__instance.m_attackProjectile == (Object)null)) { __instance.m_attackOriginJoint = "RightHand"; __instance.m_attackHeight = Plugin.SpawnUp.Value; __instance.m_attackRange = Plugin.SpawnForward.Value; __instance.m_attackOffset = 0f; } } } [HarmonyPatch(typeof(ZSyncAnimation), "RPC_SetTrigger")] internal static class ThrowTriggerPatch { private static readonly FieldRef<ZSyncAnimation, Animator> AnimatorOf = AccessTools.FieldRefAccess<ZSyncAnimation, Animator>("m_animator"); private static readonly FieldRef<VisEquipment, int> RightItemHashOf = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightItemHash"); private static void Prefix(ZSyncAnimation __instance, string name) { if (!(name != "spear_throw")) { Animator val = AnimatorOf.Invoke(__instance); if (!((Object)(object)val == (Object)null)) { Humanoid component = ((Component)__instance).GetComponent<Humanoid>(); ThrowOverride.Apply(val, Plugin.Enabled.Value && (Object)(object)component != (Object)null && HoldsKnife(component)); } } } private static bool HoldsKnife(Humanoid humanoid) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Invalid comparison between Unknown and I4 if ((Object)(object)humanoid == (Object)(object)Player.m_localPlayer) { ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (currentWeapon == null) { return false; } return (int)currentWeapon.m_shared.m_skillType == 2; } if (!Plugin.RemotePlayers.Value || !(humanoid is Player)) { return false; } VisEquipment visEquipment = humanoid.GetVisEquipment(); if ((Object)(object)visEquipment == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } int num = RightItemHashOf.Invoke(visEquipment); GameObject val = ((num != 0) ? ObjectDB.instance.GetItemPrefab(num) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 != (Object)null) { return (int)val2.m_itemData.m_shared.m_skillType == 2; } return false; } } internal static class ThrowOverride { private sealed class Slot { public AnimatorOverrideController Controller; public AnimationClip Original; public bool KnifeOn; } private static readonly ConditionalWeakTable<Animator, Slot> Slots = new ConditionalWeakTable<Animator, Slot>(); private static bool warnedNoClip; public static void Apply(Animator animator, bool knife) { Slots.TryGetValue(animator, out var slot); if (slot != null && (Object)(object)animator.runtimeAnimatorController != (Object)(object)slot.Controller) { Slots.Remove(animator); slot = null; } if (slot == null) { if (!knife) { return; } slot = Wrap(animator); if (slot == null) { return; } } if (slot.KnifeOn != knife) { slot.KnifeOn = knife; Preserving(animator, delegate { slot.Controller[slot.Original] = (knife ? Plugin.KnifeClip : null); }); } } private static Slot Wrap(Animator animator) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController; if ((Object)(object)runtimeAnimatorController == (Object)null) { return null; } AnimatorOverrideController val = (AnimatorOverrideController)(object)((runtimeAnimatorController is AnimatorOverrideController) ? runtimeAnimatorController : null); RuntimeAnimatorController val2 = (((Object)(object)val != (Object)null) ? val.runtimeAnimatorController : runtimeAnimatorController); AnimationClip val3 = null; AnimationClip[] animationClips = val2.animationClips; foreach (AnimationClip val4 in animationClips) { if ((Object)(object)val4 != (Object)null && ((Object)val4).name == "throw_spear") { val3 = val4; break; } } if ((Object)(object)val3 == (Object)null) { if (!warnedNoClip) { Plugin.Log.LogWarning((object)("'throw_spear' not found in '" + ((Object)val2).name + "'; leaving the animation alone.")); } warnedNoClip = true; return null; } AnimatorOverrideController controller = new AnimatorOverrideController(val2) { name = ((Object)val2).name + " (knife throw)" }; if ((Object)(object)val != (Object)null) { List<KeyValuePair<AnimationClip, AnimationClip>> list = new List<KeyValuePair<AnimationClip, AnimationClip>>(val.overridesCount); val.GetOverrides(list); controller.ApplyOverrides((IList<KeyValuePair<AnimationClip, AnimationClip>>)list); } Preserving(animator, delegate { animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)controller; }); Slot slot = new Slot { Controller = controller, Original = val3 }; Slots.Add(animator, slot); return slot; } private static void Preserving(Animator animator, Action change) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) //IL_00da: Unknown result type (might be due to invalid IL or missing references) int layerCount = animator.layerCount; AnimatorStateInfo[] array = (AnimatorStateInfo[])(object)new AnimatorStateInfo[layerCount]; float[] array2 = new float[layerCount]; for (int i = 0; i < layerCount; i++) { array[i] = (animator.IsInTransition(i) ? animator.GetNextAnimatorStateInfo(i) : animator.GetCurrentAnimatorStateInfo(i)); array2[i] = animator.GetLayerWeight(i); } AnimatorControllerParameter[] parameters = animator.parameters; float[] array3 = new float[parameters.Length]; for (int j = 0; j < parameters.Length; j++) { array3[j] = Read(animator, parameters[j]); } float speed = animator.speed; change(); animator.Update(0f); for (int k = 0; k < parameters.Length; k++) { Write(animator, parameters[k], array3[k]); } for (int l = 0; l < layerCount && l < animator.layerCount; l++) { animator.SetLayerWeight(l, array2[l]); AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(l); if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash != ((AnimatorStateInfo)(ref array[l])).fullPathHash) { animator.Play(((AnimatorStateInfo)(ref array[l])).fullPathHash, l, ((AnimatorStateInfo)(ref array[l])).normalizedTime); } } animator.speed = speed; } private static float Read(Animator animator, AnimatorControllerParameter p) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected I4, but got Unknown AnimatorControllerParameterType type = p.type; switch (type - 1) { case 0: return animator.GetFloat(p.nameHash); case 2: return animator.GetInteger(p.nameHash); case 3: if (!animator.GetBool(p.nameHash)) { return 0f; } return 1f; default: return 0f; } } private static void Write(Animator animator, AnimatorControllerParameter p, float value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected I4, but got Unknown AnimatorControllerParameterType type = p.type; switch (type - 1) { case 0: animator.SetFloat(p.nameHash, value); break; case 2: animator.SetInteger(p.nameHash, (int)value); break; case 3: animator.SetBool(p.nameHash, value != 0f); break; case 1: break; } } }