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 ComboSpear v1.0.0
BepInEx\plugins\ComboSpear\ComboSpear.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ComboSpear")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ComboSpear")] [assembly: AssemblyTitle("ComboSpear")] [assembly: AssemblyVersion("1.0.0.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 SpearCombo { [BepInPlugin("andythedemon.combospear", "Combo Spear", "1.0.0")] public class Plugin : BaseUnityPlugin { internal readonly struct Setting<T> { private readonly T value; internal T Value => value; internal Setting(T v) { value = v; } } public const string Guid = "andythedemon.combospear"; public const string PluginName = "Combo Spear"; public const string Version = "1.0.0"; internal const string ComboTrigger = "spearcombo"; internal const string VanillaPoke = "spear_poke"; internal const string ThrowTrigger = "spear_throw"; internal const string GuardTrigger = "spearguard"; internal const string IgnoredTrigger = "spear_dup_ignored"; internal const float LungeHitSeconds = 0.667f; internal const float ThrowWindowSeconds = 1.6f; internal const string KnifeLunge = "knife-lunge"; internal static ManualLogSource Log; internal static ConfigEntry<float> NormalHitDamage; internal static ConfigEntry<float> BlockHitDamage; internal static ConfigEntry<float> ThrowDamage; internal static readonly Setting<string>[] Hit = new Setting<string>[3] { new Setting<string>("knife_stab0"), new Setting<string>("knife_stab1"), new Setting<string>("knife_stab2") }; internal static readonly Setting<float>[] HitSpeed = new Setting<float>[3] { new Setting<float>(1f), new Setting<float>(1f), new Setting<float>(1f) }; internal static readonly Setting<Vector3>[] HitRotation = new Setting<Vector3>[3] { new Setting<Vector3>(Vector3.zero), new Setting<Vector3>(Vector3.zero), new Setting<Vector3>(Vector3.zero) }; internal static readonly Setting<Vector3>[] HitOffset = new Setting<Vector3>[3] { new Setting<Vector3>(Vector3.zero), new Setting<Vector3>(Vector3.zero), new Setting<Vector3>(Vector3.zero) }; internal static readonly Setting<float> LastHitDamage = new Setting<float>(2f); internal static readonly Setting<float> Range = new Setting<float>(3.2f); internal static readonly Setting<Vector3> ComboGrip = new Setting<Vector3>(new Vector3(-8f, 23f, 12f)); internal static readonly Setting<float> ComboGripBlend = new Setting<float>(0.12f); internal static readonly Setting<bool> JumpBackThrow = new Setting<bool>(v: true); internal static readonly Setting<bool> DefenceCombo = new Setting<bool>(v: true); internal static readonly Setting<float> GuardReset = new Setting<float>(1f); internal static readonly Setting<float> GuardHold = new Setting<float>(0.3f); internal static readonly Setting<string>[] GuardClip = new Setting<string>[3] { new Setting<string>("SpearGuard1"), new Setting<string>("SpearGuard2"), new Setting<string>("SpearGuard3") }; internal static readonly Setting<float>[] GuardDamage = new Setting<float>[3] { new Setting<float>(0.5f), new Setting<float>(0.7f), new Setting<float>(1f) }; internal static readonly Setting<float> JumpBackHeight = new Setting<float>(1f); internal static readonly Setting<float> JumpBackDistance = new Setting<float>(2f); internal static readonly Setting<float> JumpBackDelay = new Setting<float>(0.2f); internal static readonly Setting<string> ThrowCustomClip = new Setting<string>("SpearThrowBack"); internal static readonly Setting<string> ThrowCustomClipFree = new Setting<string>("SpearThrowBack_Free"); internal static readonly Setting<string> ThrowReplacesClip = new Setting<string>("throw_spear"); internal static readonly Setting<bool> Flip = new Setting<bool>(v: true); internal static readonly Setting<bool> Dump = new Setting<bool>(v: false); internal static readonly Setting<string> CustomBundle = new Setting<string>("spearcombo.bundle"); internal static readonly Setting<string>[] HitCustomClip = new Setting<string>[3] { new Setting<string>("SpearJab1"), new Setting<string>("SpearJab2"), new Setting<string>("SpearLunge") }; internal static readonly Setting<string>[] HitCustomClipFree = new Setting<string>[3] { new Setting<string>("SpearJab1_Free"), new Setting<string>("SpearJab2_Free"), new Setting<string>("SpearLunge_Free") }; internal static readonly Setting<string>[] HitReplaceClip = new Setting<string>[3] { new Setting<string>("knife_slash0"), new Setting<string>("knife_slash1"), new Setting<string>("knife_slash2") }; internal static string PluginFolder; private bool dumped; private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Expected O, but got Unknown //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Expected O, but got Unknown //IL_0243: Expected O, but got Unknown //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Expected O, but got Unknown //IL_0497: Expected O, but got Unknown //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Expected O, but got Unknown //IL_04d9: Expected O, but got Unknown //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; NormalHitDamage = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Damage", "NormalHitsDamageMultiplier", 1f, new ConfigDescription("Damage of the three normal combo hits relative to vanilla. 1 = as designed, 0.5 = half, 2 = double.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); BlockHitDamage = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Damage", "BlockHitsDamageMultiplier", 1f, new ConfigDescription("Damage of the three block-combo hits. Their designed values are 50% / 70% / 100% of a normal hit; this scales that.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); ThrowDamage = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Damage", "SpearThrowDamageMultiplier", 0.5f, new ConfigDescription("Damage of the jump-back finishing throw relative to a normal spear throw. The plain middle-mouse throw is not affected.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>())); Log.LogInfo((object)$"Damage: normal hits x{NormalHitDamage.Value:0.##}, block hits x{BlockHitDamage.Value:0.##}, jump-back throw x{ThrowDamage.Value:0.##}."); PluginFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Refs.Init(); if (Chainloader.PluginInfos.ContainsKey("goldenrevolver.ProperSpears")) { Log.LogWarning((object)"Proper Spears is installed too - both change spears; disable one of them."); } Harmony val = new Harmony("andythedemon.combospear"); val.PatchAll(typeof(Plugin).Assembly); try { MethodInfo methodInfo = AccessTools.Method(typeof(Humanoid), "StartAttack", new Type[2] { typeof(Character), typeof(bool) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "InAttack", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo2 != null && Refs.CurrentAttack != null && Refs.Zanim != null) { val.Patch((MethodBase)methodInfo2, new HarmonyMethod(AccessTools.Method(typeof(LungeCancel), "InAttackPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(LungeCancel), "Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(LungeCancel), "Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null); } else { Log.LogError((object)"StartAttack / Player.InAttack / m_currentAttack / m_zanim not found; cancelling the lunge is off."); } } catch (Exception ex) { Log.LogError((object)("Could not patch the lunge cancel (" + ex.GetType().Name + "); cancelling the lunge is off.")); } try { MethodInfo methodInfo3 = AccessTools.Method(typeof(Humanoid), "StartAttack", new Type[2] { typeof(Character), typeof(bool) }, (Type[])null); if (methodInfo3 != null && Refs.CurrentAttack != null) { val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(SoftThrow), "Postfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogError((object)"Humanoid.StartAttack / m_currentAttack not found; the jump-back throw hits at full damage."); } } catch (Exception ex2) { Log.LogError((object)("Could not patch the jump-back throw damage (" + ex2.GetType().Name + "); it hits at full damage.")); } try { MethodInfo methodInfo4 = AccessTools.Method(typeof(Attack), "FireProjectileBurst", (Type[])null, (Type[])null); if (methodInfo4 != null) { val.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(GameThrowWatch), "BurstPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex3) { Log.LogError((object)("Could not watch projectile bursts (" + ex3.GetType().Name + "); the throw fallback may double-fire.")); } try { MethodInfo methodInfo5 = AccessTools.Method(typeof(Humanoid), "StartAttack", new Type[2] { typeof(Character), typeof(bool) }, (Type[])null); MethodInfo methodInfo6 = AccessTools.Method(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null); MethodInfo methodInfo7 = AccessTools.Method(typeof(Humanoid), "IsBlocking", (Type[])null, (Type[])null); if (methodInfo5 != null && methodInfo6 != null && methodInfo7 != null && Refs.Blocking != null && Refs.CurrentAttack != null) { val.Patch((MethodBase)methodInfo5, new HarmonyMethod(AccessTools.Method(typeof(GuardCombo), "Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(GuardCombo), "Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null); val.Patch((MethodBase)methodInfo6, new HarmonyMethod(AccessTools.Method(typeof(GuardCombo), "DamagePrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(GuardCombo), "DamageFinalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null); val.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(GuardCombo), "IsBlockingPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogError((object)"StartAttack / RPC_Damage / IsBlocking / m_blocking not found; the defence combo is off."); } } catch (Exception ex4) { Log.LogError((object)("Could not patch the defence combo (" + ex4.GetType().Name + "); it is off.")); } Log.LogInfo((object)"Combo Spear 1.0.0 loaded."); } private void Update() { WiresShim.Ensure(); if (dumped || !Dump.Value || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } dumped = true; try { AnimationDump.Write(Player.m_localPlayer); } catch (Exception ex) { Log.LogError((object)("Animation dump failed: " + ex)); } } } internal sealed class ConfigurationManagerAttributes { public Action<ConfigEntryBase> CustomDrawer; public int? Order; } internal static class Refs { internal static FieldRef<Attack, int> ChainLevels; internal static FieldRef<Attack, float> LastChainDamage; internal static FieldRef<Attack, int> ChainLevel; internal static FieldRef<ZSyncAnimation, Animator> AnimatorOf; internal static FieldRef<VisEquipment, GameObject> RightItem; internal static FieldRef<VisEquipment, int> LeftItemHash; internal static FieldRef<VisEquipment, int> RightItemHash; internal static FieldInfo SecondaryAttack; internal static FieldInfo CurrentAttack; internal static FieldInfo Zanim; internal static FieldInfo Blocking; internal static FieldRef<Humanoid, bool> InternalBlocking; internal static FieldRef<Player, float> QueuedAttack; internal static FieldRef<Humanoid, float> TimeSinceLastAttack; internal static FieldInfo BlockingAnimHash; internal static MethodInfo FireProjectileBurst; internal static void Init() { ChainLevels = Get<Attack, int>("m_attackChainLevels"); LastChainDamage = Get<Attack, float>("m_lastChainDamageMultiplier"); ChainLevel = Get<Attack, int>("m_currentAttackCainLevel"); AnimatorOf = Get<ZSyncAnimation, Animator>("m_animator"); RightItem = Get<VisEquipment, GameObject>("m_rightItemInstance"); LeftItemHash = Get<VisEquipment, int>("m_currentLeftItemHash"); RightItemHash = Get<VisEquipment, int>("m_currentRightItemHash"); SecondaryAttack = AccessTools.Field(typeof(SharedData), "m_secondaryAttack"); CurrentAttack = AccessTools.Field(typeof(Humanoid), "m_currentAttack"); Zanim = AccessTools.Field(typeof(Character), "m_zanim"); Blocking = AccessTools.Field(typeof(Character), "m_blocking"); InternalBlocking = Get<Humanoid, bool>("m_internalBlockingState"); QueuedAttack = Get<Player, float>("m_queuedAttackTimer"); TimeSinceLastAttack = Get<Humanoid, float>("m_timeSinceLastAttack"); BlockingAnimHash = AccessTools.Field(typeof(Humanoid), "s_blocking"); FireProjectileBurst = AccessTools.Method(typeof(Attack), "FireProjectileBurst", (Type[])null, (Type[])null); if (CurrentAttack == null || Zanim == null) { Plugin.Log.LogError((object)"m_currentAttack / m_zanim not found; cancelling the lunge is off."); } } private static FieldRef<T, F> Get<T, F>(string field) where T : class { try { return AccessTools.FieldRefAccess<T, F>(field); } catch (Exception ex) { Plugin.Log.LogError((object)("Field " + typeof(T).Name + "." + field + " not found (" + ex.GetType().Name + "); that feature is off.")); return null; } } internal static int Levels(Attack a) { if (ChainLevels == null) { return 1; } return ChainLevels.Invoke(a); } } internal static class Combo { private static string resolvedLunge; internal static bool IsComboSpear(SharedData s) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (s != null && (int)s.m_skillType == 5 && s.m_attack != null) { if (!(s.m_attack.m_attackAnimation == "spear_poke")) { return s.m_attack.m_attackAnimation == "spearcombo"; } return true; } return false; } internal static SharedData SharedOf(GameObject go) { ItemDrop val = (Object.op_Implicit((Object)(object)go) ? go.GetComponent<ItemDrop>() : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.m_itemData?.m_shared; } internal static SharedData SharedFromHash(int hash) { if (hash != 0 && !((Object)(object)ObjectDB.instance == (Object)null)) { return SharedOf(ObjectDB.instance.GetItemPrefab(hash)); } return null; } internal static void Apply(SharedData s) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if (s == null || (int)s.m_skillType != 5 || s.m_attack == null) { return; } Attack attack = s.m_attack; if (attack.m_attackAnimation != "spear_poke" || Refs.ChainLevels == null) { return; } attack.m_attackAnimation = "spearcombo"; Refs.ChainLevels.Invoke(attack) = 3; DestructibleType resetChainIfHit = attack.m_resetChainIfHit; attack.m_resetChainIfHit = (DestructibleType)0; if (Refs.LastChainDamage != null) { Refs.LastChainDamage.Invoke(attack) = Plugin.LastHitDamage.Value; } attack.m_attackRange = Plugin.Range.Value; attack.m_attackHeight = 1f; attack.m_attackAngle = 30f; attack.m_attackRayWidth = 0.4f; if (Plugin.JumpBackThrow.Value) { object? obj = Refs.SecondaryAttack?.GetValue(s); Attack val = (Attack)((obj is Attack) ? obj : null); if (val != null) { val.m_damageMultiplier = 1f; } } Plugin.Log.LogInfo((object)$"Combo applied to {s.m_name} (chain reset-if-hit {resetChainIfHit} -> None)."); } internal static string MapTrigger(string name, out int level) { return MapTrigger(name, "spearcombo", out level); } internal static string MapTrigger(string name, string prefix, out int level) { level = 0; if (name.Length > prefix.Length) { int.TryParse(name.Substring(prefix.Length), out level); } level = Mathf.Clamp(level, 0, 2); return Resolve(Plugin.Hit[level].Value); } internal static string Resolve(string configured) { if (!(configured == "knife-lunge")) { return configured; } return LungeTrigger(); } private static string LungeTrigger() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 if (resolvedLunge != null) { return resolvedLunge; } if ((Object)(object)ObjectDB.instance != (Object)null && Refs.ChainLevels != null) { foreach (GameObject item in ObjectDB.instance.m_items) { SharedData val = SharedOf(item); if (val != null && (int)val.m_skillType == 2 && val.m_attack != null) { int num = Refs.Levels(val.m_attack); if (num >= 3 && !string.IsNullOrEmpty(val.m_attack.m_attackAnimation)) { resolvedLunge = val.m_attack.m_attackAnimation + (num - 1); Plugin.Log.LogInfo((object)("knife-lunge = '" + resolvedLunge + "' (from " + ((Object)item).name + ").")); return resolvedLunge; } } } } resolvedLunge = "knife_stab2"; Plugin.Log.LogWarning((object)("Could not read the knife combo; guessing '" + resolvedLunge + "'. Pick the lunge from the list if it does nothing.")); return resolvedLunge; } } internal class AnimOption { public string Trigger; public string Label; } internal static class AnimationCatalog { private static readonly HashSet<string> PlayerItemTypes = new HashSet<string> { "OneHandedWeapon", "TwoHandedWeapon", "TwoHandedWeaponLeft", "Bow", "Torch", "Tool" }; private static List<AnimOption> cache; internal static List<AnimOption> Get() { if (cache != null) { return cache; } if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null || ObjectDB.instance.m_recipes.Count == 0) { return null; } HashSet<SharedData> hashSet = new HashSet<SharedData>(); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { SharedData val = ((!((Object)(object)recipe != (Object)null) || !((Object)(object)recipe.m_item != (Object)null)) ? null : recipe.m_item.m_itemData?.m_shared); if (val != null) { hashSet.Add(val); } } HashSet<string> seen = new HashSet<string> { "knife-lunge" }; List<AnimOption> list = new List<AnimOption>(); foreach (GameObject item in ObjectDB.instance.m_items) { SharedData val2 = Combo.SharedOf(item); if (val2 != null && hashSet.Contains(val2) && PlayerItemTypes.Contains(((object)Unsafe.As<ItemType, ItemType>(ref val2.m_itemType)/*cast due to .constrained prefix*/).ToString())) { string weapon = Localize(val2.m_name); AddAttack(list, seen, weapon, "primary", val2.m_attack); object? obj = Refs.SecondaryAttack?.GetValue(val2); AddAttack(list, seen, weapon, "secondary", (Attack)((obj is Attack) ? obj : null)); } } list.Sort((AnimOption a, AnimOption b) => string.CompareOrdinal(a.Label, b.Label)); List<AnimOption> list2 = new List<AnimOption>(); list2.Add(new AnimOption { Trigger = "knife-lunge", Label = "knife-lunge (knife combo finisher, auto-detected)" }); list2.AddRange(list); cache = list2; return cache; } private static string Localize(string token) { try { return (Localization.instance != null) ? Localization.instance.Localize(token) : token; } catch { return token; } } private static void AddAttack(List<AnimOption> list, HashSet<string> seen, string weapon, string kind, Attack a) { if (a == null || string.IsNullOrEmpty(a.m_attackAnimation)) { return; } bool num = a.m_attackAnimation == "spearcombo"; string text = (num ? "spear_poke" : a.m_attackAnimation); int num2 = (num ? 1 : Refs.Levels(a)); if (num2 <= 1) { if (seen.Add(text)) { list.Add(new AnimOption { Trigger = text, Label = text + " (" + weapon + ", " + kind + ")" }); } return; } for (int i = 0; i < num2; i++) { string text2 = text + i; if (seen.Add(text2)) { list.Add(new AnimOption { Trigger = text2, Label = $"{text2} ({weapon}, {kind} hit {i + 1}/{num2})" }); } } } } internal static class AnimPicker { private static readonly Dictionary<ConfigEntryBase, bool> open = new Dictionary<ConfigEntryBase, bool>(); private static readonly Dictionary<ConfigEntryBase, Vector2> scroll = new Dictionary<ConfigEntryBase, Vector2>(); internal static void Draw(ConfigEntryBase entryBase) { //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<string> val = (ConfigEntry<string>)(object)entryBase; List<AnimOption> list = AnimationCatalog.Get(); open.TryGetValue((ConfigEntryBase)(object)val, out var value); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("<", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }) && list != null) { Step(val, list, -1); } string text = GUILayout.TextField(val.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (text != val.Value) { val.Value = text; } if (GUILayout.Button(">", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }) && list != null) { Step(val, list, 1); } if (GUILayout.Button(value ? "Close" : "List", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) })) { value = (open[(ConfigEntryBase)(object)val] = !value); } GUILayout.EndHorizontal(); if (value) { if (list == null) { GUILayout.Label("Enter a world first - the list is read from the game.", Array.Empty<GUILayoutOption>()); } else { scroll.TryGetValue((ConfigEntryBase)(object)val, out var value2); scroll[(ConfigEntryBase)(object)val] = GUILayout.BeginScrollView(value2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(260f) }); foreach (AnimOption item in list) { if (GUILayout.Button((item.Trigger == val.Value) ? ("> " + item.Label) : item.Label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { val.Value = item.Trigger; open[(ConfigEntryBase)(object)val] = false; } } GUILayout.EndScrollView(); } } GUILayout.EndVertical(); } private static void Step(ConfigEntry<string> entry, List<AnimOption> options, int dir) { int num = options.FindIndex((AnimOption o) => o.Trigger == entry.Value); num = ((num >= 0) ? ((num + dir + options.Count) % options.Count) : 0); entry.Value = options[num].Trigger; } } internal static class AnimationDump { internal static void Write(Player player) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Valheim attack animations (written by Spear Combo). Use these names for Hit1..Hit3."); stringBuilder.AppendLine(); stringBuilder.AppendLine("== Attacks of player weapons (craftable) =="); List<AnimOption> list = AnimationCatalog.Get(); if (list != null) { foreach (AnimOption item in list) { stringBuilder.AppendLine(item.Label); } } Animator val = ((Refs.AnimatorOf != null) ? Refs.AnimatorOf.Invoke(((Component)player).GetComponent<ZSyncAnimation>()) : null); if ((Object)(object)val != (Object)null && (Object)(object)val.runtimeAnimatorController != (Object)null) { stringBuilder.AppendLine(); stringBuilder.AppendLine("== Animation clips in the player controller (for custom-clip replacement later) =="); SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.Ordinal); AnimationClip[] animationClips = val.runtimeAnimatorController.animationClips; foreach (AnimationClip val2 in animationClips) { if ((Object)(object)val2 != (Object)null) { sortedSet.Add($"{((Object)val2).name} ({val2.length:0.00}s)"); } } foreach (string item2 in sortedSet) { stringBuilder.AppendLine(item2); } } string text = Path.Combine(Paths.BepInExRootPath, "SpearCombo-animations.txt"); File.WriteAllText(text, stringBuilder.ToString()); Plugin.Log.LogInfo((object)("Animation list written to " + text)); } } internal class FlipMark : MonoBehaviour { public bool Flipped; public bool Fang; public bool PoseActive; public float ReflipAt; public float GripW; public float RegripW; public int Level = -1; private ComboState state; private void LateUpdate() { if (!Flipped) { GripW = 0f; return; } if ((Object)(object)state == (Object)null) { state = ((Component)this).GetComponentInParent<ComboState>(); } float num = (((Object)(object)state != (Object)null && (state.Level >= 0 || Time.time < state.LastActive + 0.15f)) ? 1f : 0f); if (GripW != num || GripW != 0f) { float num2 = Time.deltaTime / ((num > GripW) ? Mathf.Max(0.01f, Plugin.ComboGripBlend.Value) : 0.5f); GripW = Mathf.MoveTowards(GripW, num, num2); RegripW = (((Object)(object)state != (Object)null && state.ThrowAt > 0f) ? SpearFlip.Regrip(Time.time - state.ThrowAt) : 0f); SpearFlip.ApplyPose(((Component)this).gameObject, this, ((Object)(object)state != (Object)null) ? state.Level : (-1)); } } } internal static class SpearFlip { private static readonly Vector3 PalmOffset = new Vector3(-0.0171f, -0.0045f, 0f); private const float TossStart = 0.22f; private const float TossEnd = 0.53f; private const float TossLift = 0.15f; internal static Quaternion RegripRot(Quaternion r1, float w) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.Inverse(r1); float num = default(float); Vector3 val2 = default(Vector3); ((Quaternion)(ref val)).ToAngleAxis(ref num, ref val2); if (num > 180f) { num = 360f - num; val2 = -val2; } return r1 * Quaternion.AngleAxis((num - 360f) * w, val2); } internal static float Regrip(float t) { if (t < 0f || t > 2f) { return 0f; } float num = Mathf.Clamp01((t - 0.22f) / 0.30999997f); return num * num * (3f - 2f * num); } internal static void Flip(GameObject go, bool fang) { FlipMark flipMark = go.GetComponent<FlipMark>() ?? go.AddComponent<FlipMark>(); flipMark.Fang = fang; flipMark.Flipped = true; ApplyPose(go, flipMark, -1); } internal static void ApplyPose(GameObject go, FlipMark m, int hitLevel) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) Transform transform = go.transform; transform.localRotation = Quaternion.identity; transform.localPosition = Vector3.zero; m.PoseActive = false; if (m.Flipped) { transform.Rotate(180f, 25f, 0f); transform.Translate(Vector3.forward * (m.Fang ? (-0.72f) : (-0.5f)) + PalmOffset, (Space)1); if (m.GripW > 0f) { float num = m.GripW * m.GripW * (3f - 2f * m.GripW); Quaternion val = Quaternion.Slerp(Quaternion.identity, Quaternion.Euler(Plugin.ComboGrip.Value), num); transform.localRotation = val * transform.localRotation; transform.localPosition = val * transform.localPosition; m.PoseActive = true; } if (m.RegripW > 0f) { float regripW = m.RegripW; transform.localRotation = RegripRot(transform.localRotation, regripW); transform.localPosition = Vector3.Lerp(transform.localPosition, Vector3.zero, regripW); transform.position += Vector3.up * (0.15f * Mathf.Sin(MathF.PI * regripW)); m.PoseActive = true; } if (hitLevel >= 0) { transform.Rotate(Plugin.HitRotation[hitLevel].Value); transform.Translate(Plugin.HitOffset[hitLevel].Value); m.PoseActive = true; } } } internal static GameObject RightItemOf(Component c) { Humanoid component = c.GetComponent<Humanoid>(); VisEquipment val = (((Object)(object)component != (Object)null) ? component.GetVisEquipment() : null); if (!((Object)(object)val != (Object)null) || Refs.RightItem == null) { return null; } return Refs.RightItem.Invoke(val); } } internal class JumpBack : MonoBehaviour { private float fireAt = -1f; internal void Arm(float delay) { fireAt = Time.time + delay; ((Behaviour)this).enabled = true; } private void Update() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (!(fireAt < 0f) && !(Time.time < fireAt)) { fireAt = -1f; ((Behaviour)this).enabled = false; Character component = ((Component)this).GetComponent<Character>(); if (!((Object)(object)component == (Object)null) && !component.IsDead() && component.IsOnGround()) { float num = Mathf.Max(0.1f, 0f - Physics.gravity.y); float num2 = Mathf.Sqrt(2f * num * Mathf.Max(0f, Plugin.JumpBackHeight.Value)); float num3 = 2f * num2 / num; float num4 = ((num3 > 0.01f) ? (Plugin.JumpBackDistance.Value / num3) : 0f); Vector3 val = -((Component)component).transform.forward; val.y = 0f; ((Vector3)(ref val)).Normalize(); component.ForceJump(val * num4 + Vector3.up * num2, false); } } } } internal static class GuardCombo { internal static bool SwallowedSinceStart; private static float pendingGap; private static bool pendingContinuing; private static float guardStartedAt = -10f; private static float lastTraceAt = -10f; private static Character damaged; private static void Trace(string text) { if (!(Time.time - lastTraceAt < 0.25f)) { lastTraceAt = Time.time; Plugin.Log.LogDebug((object)("[guard] " + text)); } } private static bool BlockButtonHeld() { try { if (Hud.InRadial()) { return false; } return ZInput.GetButton("Block") || ZInput.GetButton("JoyBlock"); } catch { return false; } } internal static bool Prefix(Humanoid __instance, bool secondaryAttack, out bool __state, ref bool __result) { __state = false; if (secondaryAttack || !Plugin.DefenceCombo.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || Refs.Blocking == null) { return true; } object value = Refs.Blocking.GetValue(__instance); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0; bool flag3 = BlockButtonHeld(); bool flag4 = flag2 || flag3; if (!flag4) { ComboState component = ((Component)__instance).GetComponent<ComboState>(); if ((Object)(object)component == (Object)null || !component.Guard || Time.time > component.LastActive + 0.5f) { Trace("skip: block neither held nor recent -> game starts a NORMAL combo hit"); return true; } } SharedData val = __instance.GetCurrentWeapon()?.m_shared; if (val == null || val.m_attack == null) { if (flag4) { Trace("skip: no weapon/attack"); } return true; } string attackAnimation = val.m_attack.m_attackAnimation; if (attackAnimation != "spearcombo" && attackAnimation != "spearguard") { if (flag4) { Trace("skip: attack name '" + attackAnimation + "' (block held) -> game starts a NORMAL hit"); } return true; } object? obj = Refs.CurrentAttack?.GetValue(__instance); Attack val2 = (Attack)((obj is Attack) ? obj : null); ComboState component2 = ((Component)__instance).GetComponent<ComboState>(); bool flag5 = (Object)(object)component2 != (Object)null && component2.GuardHolding; bool flag6 = val2 != null && val2.m_attackAnimation == "spearguard" && !val2.IsDone() && !flag5 && Time.time - guardStartedAt < 1.5f; Trace(string.Format("block(field={0},button={1}) running='{2}' ", flag2, flag3, (val2 != null) ? val2.m_attackAnimation : "<none>") + string.Format("done={0} held={1} sinceStart={2:0.00} ", (val2 != null) ? val2.IsDone().ToString() : "-", flag5, Time.time - guardStartedAt) + "-> " + (flag6 ? "REFUSE (hit still playing)" : "allow")); if (flag6) { __state = false; __result = false; return false; } val.m_attack.m_attackAnimation = "spearguard"; if (Refs.LastChainDamage != null) { Refs.LastChainDamage.Invoke(val.m_attack) = 1f; } ComboState component3 = ((Component)__instance).GetComponent<ComboState>(); pendingGap = (((Object)(object)component3 != (Object)null) ? (Time.time - component3.LastActive) : 999f); pendingContinuing = (Object)(object)component3 != (Object)null && component3.Guard && pendingGap <= Plugin.GuardReset.Value; if (pendingContinuing && Refs.TimeSinceLastAttack != null) { Refs.TimeSinceLastAttack.Invoke(__instance) = 0f; } object? obj2 = Refs.Zanim?.GetValue(__instance); ZSyncAnimation val3 = (ZSyncAnimation)((obj2 is ZSyncAnimation) ? obj2 : null); if (val3 != null) { if (Refs.BlockingAnimHash != null) { ClearBlockPose(__instance, val3); } if (Refs.AnimatorOf != null) { Animator val4 = Refs.AnimatorOf.Invoke(val3); if ((Object)(object)val4 != (Object)null && val4.speed < 0.01f) { val4.speed = 1f; } } } guardStartedAt = Time.time; __state = true; return true; } internal static void Finalizer(Humanoid __instance, bool __state, bool __result) { if (!__state) { return; } SharedData val = __instance.GetCurrentWeapon()?.m_shared; if (val == null || val.m_attack == null) { return; } val.m_attack.m_attackAnimation = "spearcombo"; if (Refs.LastChainDamage != null) { Refs.LastChainDamage.Invoke(val.m_attack) = Plugin.LastHitDamage.Value; } if (!__result) { return; } object? obj = Refs.CurrentAttack?.GetValue(__instance); Attack val2 = (Attack)((obj is Attack) ? obj : null); if (val2 != null && val2.m_attackAnimation == "spearguard" && Refs.ChainLevel != null) { if (SwallowedSinceStart) { SwallowedSinceStart = false; return; } int num = Mathf.Clamp(Refs.ChainLevel.Invoke(val2), 0, 2); val2.m_damageMultiplier = Plugin.GuardDamage[num].Value; Plugin.Log.LogDebug((object)($"Defence hit {num + 1} of 3: damage x{val2.m_damageMultiplier:0.##} (" + string.Format("{0}, {1:0.00}s since the last defence hit).", pendingContinuing ? "continuing the combo" : "fresh chain", pendingGap))); } } internal static void DamagePrefix(Character __instance) { damaged = __instance; } internal static void DamageFinalizer() { damaged = null; } internal static void IsBlockingPostfix(Humanoid __instance, ref bool __result) { if ((Object)(object)damaged != (Object)(object)__instance) { if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { ComboState component = ((Component)__instance).GetComponent<ComboState>(); if (component != null && component.Guard && (component.Level >= 0 || Time.time < component.LastActive + 0.35f)) { __result = false; } } } else { if (__result || !(__instance is Player) || Refs.Blocking == null || Refs.CurrentAttack == null) { return; } object value = Refs.Blocking.GetValue(__instance); if (value is bool && (bool)value) { object? value2 = Refs.CurrentAttack.GetValue(__instance); Attack val = (Attack)((value2 is Attack) ? value2 : null); if (val != null && !(val.m_attackAnimation != "spearguard") && !((Character)__instance).IsStaggering() && !((Character)__instance).InDodge()) { __result = true; } } } } internal static void KeepQueuedClick(ComboState st, ZSyncAnimation zanim) { if ((Object)(object)st == (Object)null || !st.Guard || st.Level < 0 || Refs.QueuedAttack == null) { return; } Humanoid component = ((Component)zanim).GetComponent<Humanoid>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component != (Object)(object)Player.m_localPlayer)) { Player val = (Player)(object)((component is Player) ? component : null); if (!((Object)(object)val == (Object)null) && !(Refs.QueuedAttack.Invoke(val) <= 0f)) { Refs.QueuedAttack.Invoke(val) = 0.5f; } } } private static void ClearBlockPose(Humanoid h, ZSyncAnimation zanim) { if (Refs.BlockingAnimHash != null) { zanim.SetBool((int)Refs.BlockingAnimHash.GetValue(null), false); } if ((Object)(object)h != (Object)null && Refs.InternalBlocking != null) { Refs.InternalBlocking.Invoke(h) = false; } } internal static void SuppressBlockPose(ZSyncAnimation zanim, ComboState st) { if ((Object)(object)st == (Object)null || !Plugin.DefenceCombo.Value || Refs.BlockingAnimHash == null || !st.Guard || Time.time > st.LastActive + Plugin.GuardReset.Value) { return; } Humanoid component = ((Component)zanim).GetComponent<Humanoid>(); if ((Object)(object)component == (Object)null || (Object)(object)component != (Object)(object)Player.m_localPlayer) { return; } bool flag = default(bool); int num; if (Refs.Blocking != null) { object value = Refs.Blocking.GetValue(component); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0 || BlockButtonHeld()) { ClearBlockPose(component, zanim); } } } internal static class WiresShim { private static bool tried; private static float lastLogAt = -10f; internal static void Ensure() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown if (tried) { return; } tried = true; try { Assembly assembly = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly2 in assemblies) { if (assembly2.GetName().Name == "WiresCombatFlow") { assembly = assembly2; break; } } Type type = ((assembly != null) ? assembly.GetType("WiresCombatFlow.CombatFlow") : null); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "TryCancel", (Type[])null, (Type[])null) : null); if (methodInfo == null) { Plugin.Log.LogInfo((object)"Wires Combat Flow not detected - its recovery-cancel cannot touch the defence hits."); return; } new Harmony("andythedemon.combospear.wires").Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(WiresShim), "TryCancelPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Wires Combat Flow detected - its recovery-cancel is now skipped while a defence hit plays."); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not bind the Wires cancel immunity (" + ex.GetType().Name + "); defence hits stay cancellable by it.")); } } internal static bool TryCancelPrefix(Player player, int cancel) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || Refs.CurrentAttack == null) { return true; } object? value = Refs.CurrentAttack.GetValue(player); Attack val = (Attack)((value is Attack) ? value : null); if (val == null) { return true; } if (val.m_attackAnimation != "spearguard") { return true; } if (Time.time - lastLogAt > 2f) { lastLogAt = Time.time; Plugin.Log.LogDebug((object)"Wires recovery-cancel suppressed during a defence hit (its Stop/reject/crossfade skipped)."); } return false; } } internal static class SoftThrow { internal static void Postfix(Humanoid __instance, bool secondaryAttack, bool __result) { if (!__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } ComboState component = ((Component)__instance).GetComponent<ComboState>(); if (!secondaryAttack) { object? obj = Refs.CurrentAttack?.GetValue(__instance); Attack val = (Attack)((obj is Attack) ? obj : null); if (val != null && val.m_attackAnimation == "spearcombo") { float value = Plugin.NormalHitDamage.Value; if (!Mathf.Approximately(value, 1f)) { val.m_damageMultiplier = value; } } } else if (!((Object)(object)component == (Object)null) && component.SoftThrowPending) { component.SoftThrowPending = false; object? obj2 = Refs.CurrentAttack?.GetValue(__instance); Attack val2 = (Attack)((obj2 is Attack) ? obj2 : null); if (val2 != null) { val2.m_damageMultiplier = Plugin.ThrowDamage.Value; Plugin.Log.LogInfo((object)$"Jump-back throw damage x{Plugin.ThrowDamage.Value:0.##} (this throw only)."); } } } } internal static class GameThrowWatch { private struct Burst { public Attack attack; public float at; } private static readonly List<Burst> bursts = new List<Burst>(16); internal static void BurstPostfix(Attack __instance) { if (__instance != null) { bursts.Add(new Burst { attack = __instance, at = Time.time }); if (bursts.Count > 16) { bursts.RemoveAt(0); } } } internal static bool FiredSince(Attack attack, float sinceAt) { for (int num = bursts.Count - 1; num >= 0; num--) { if (bursts[num].attack == attack && bursts[num].at >= sinceAt) { return true; } } return false; } } internal static class LungeCancel { private static bool bypass; internal static bool InAttackPrefix(Player __instance, ref bool __result) { if (!bypass || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } __result = false; return false; } internal static void Prefix(Humanoid __instance, bool secondaryAttack, out bool __state) { __state = false; if (!secondaryAttack || !Plugin.JumpBackThrow.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } object? value = Refs.CurrentAttack.GetValue(__instance); Attack val = (Attack)((value is Attack) ? value : null); if (val != null && !(val.m_attackAnimation != "spearcombo")) { object? value2 = Refs.Zanim.GetValue(__instance); ZSyncAnimation val2 = (ZSyncAnimation)((value2 is ZSyncAnimation) ? value2 : null); if (val2 != null && ComboState.LungeHitLanded(val2) && ((Character)__instance).IsOnGround()) { bypass = true; __state = true; } } } internal static void Finalizer(Humanoid __instance, bool __state, bool __result) { if (!__state) { return; } bypass = false; if (__result) { Plugin.Log.LogInfo((object)"Special during the lunge: lunge cut, jump-back throw started."); return; } string text; try { ItemData currentWeapon = __instance.GetCurrentWeapon(); Attack val = currentWeapon?.m_shared?.m_secondaryAttack; text = (((Character)__instance).IsStaggering() ? "the character is staggering (took a hit)" : (((Character)__instance).InDodge() ? "the character is dodging" : ((!((Character)__instance).CanMove()) ? "the character cannot move" : (((Character)__instance).InMinorAction() ? "a minor action is playing" : ((currentWeapon == null) ? "nothing in hand" : ((!currentWeapon.HaveSecondaryAttack()) ? "the weapon has no secondary attack" : ((val != null && !string.IsNullOrEmpty(val.m_attackAnimation)) ? ((val.m_cantUseInDungeon && ((Character)__instance).InInterior()) ? "the throw is blocked indoors" : ((!val.m_requiresReload || __instance.IsWeaponLoaded()) ? "vanilla refused it, no blocking state detected" : "the weapon is not loaded")) : "the secondary attack has no animation"))))))); } catch (Exception ex) { text = "state read failed (" + ex.GetType().Name + ")"; } Plugin.Log.LogInfo((object)("Special during the lunge: the throw could not start - " + text + ".")); } } internal class ComboState : MonoBehaviour { public int Level = -1; public string Clip; public float CaptureAt; public float ExpireAt; public float LastActive = -10f; public float ThrowAt = -10f; public bool ThrowFired; public Attack PendingThrow; public int PreloadedSet = -1; public bool Guard; public bool GuardHolding; public bool GuardHoldDone; public float GuardHoldFrom = -10f; public float HitAt = -1f; public float LungeUntil = -10f; public bool SoftThrowPending; internal static void Begin(ZSyncAnimation zanim, int level, bool guard = false) { ComboState comboState = ((Component)zanim).GetComponent<ComboState>() ?? ((Component)zanim).gameObject.AddComponent<ComboState>(); comboState.Level = level; comboState.Guard = guard; comboState.GuardHolding = false; comboState.GuardHoldDone = false; comboState.Clip = null; comboState.CaptureAt = Time.time + 0.05f; comboState.LastActive = Time.time; comboState.ExpireAt = Time.time + 4f; if (guard) { comboState.HitAt = -1f; comboState.LungeUntil = -10f; } else if (level >= 2) { comboState.HitAt = Time.time + 0.667f; comboState.LungeUntil = comboState.HitAt + 1.6f; } } internal static bool InThrowWindow(ZSyncAnimation zanim) { ComboState comboState = (((Object)(object)zanim != (Object)null) ? ((Component)zanim).GetComponent<ComboState>() : null); if ((Object)(object)comboState != (Object)null && comboState.HitAt > 0f) { return Time.time <= comboState.LungeUntil; } return false; } internal static bool LungeHitLanded(ZSyncAnimation zanim) { ComboState comboState = (((Object)(object)zanim != (Object)null) ? ((Component)zanim).GetComponent<ComboState>() : null); if ((Object)(object)comboState != (Object)null && comboState.Level >= 2 && comboState.HitAt > 0f && Time.time >= comboState.HitAt) { return Time.time <= comboState.LungeUntil; } return false; } internal static void Spend(ZSyncAnimation zanim) { ComboState comboState = (((Object)(object)zanim != (Object)null) ? ((Component)zanim).GetComponent<ComboState>() : null); if (!((Object)(object)comboState == (Object)null)) { comboState.LungeUntil = -10f; comboState.Level = -1; } } internal static void MarkSoftThrow(ZSyncAnimation zanim) { (((Component)zanim).GetComponent<ComboState>() ?? ((Component)zanim).gameObject.AddComponent<ComboState>()).SoftThrowPending = true; } internal static void Throw(ZSyncAnimation zanim) { ComboState component = ((Component)zanim).GetComponent<ComboState>(); if ((Object)(object)component != (Object)null) { component.PreloadedSet = -1; } ComboState obj = ((Component)zanim).GetComponent<ComboState>() ?? ((Component)zanim).gameObject.AddComponent<ComboState>(); obj.Level = -1; obj.LastActive = Time.time + 1f; obj.ThrowAt = Time.time; obj.ThrowFired = false; obj.PendingThrow = null; } internal static void End(ZSyncAnimation zanim) { ComboState component = ((Component)zanim).GetComponent<ComboState>(); if ((Object)(object)component != (Object)null) { component.Level = -1; } } } internal static class CustomClips { private class Slot { public AnimatorOverrideController Controller; public RuntimeAnimatorController Base; public string AppliedSignature = ""; } private static AssetBundle bundle; private static bool bundleTried; private static readonly Dictionary<string, AnimationClip> clips = new Dictionary<string, AnimationClip>(); private static readonly ConditionalWeakTable<Animator, Slot> slots = new ConditionalWeakTable<Animator, Slot>(); internal const string EmbeddedBundleName = "spearcombo.bundle"; private static Stream embeddedBundleStream; internal const string TorchSuffix = "_Torch"; private static AssetBundle LoadEmbeddedBundle() { try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = null; string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (text2.EndsWith("spearcombo.bundle", StringComparison.OrdinalIgnoreCase)) { text = text2; break; } } if (text == null) { return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { return null; } MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); memoryStream.Position = 0L; embeddedBundleStream = memoryStream; return AssetBundle.LoadFromStream((Stream)memoryStream); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not load the embedded bundle (" + ex.GetType().Name + ": " + ex.Message + ").")); return null; } } internal static AnimationClip Clip(string name) { if (string.IsNullOrEmpty(name)) { return null; } if (clips.TryGetValue(name, out var value)) { return value; } if (!bundleTried) { bundleTried = true; string text = Path.Combine(Plugin.PluginFolder, Plugin.CustomBundle.Value); if (File.Exists(text)) { bundle = AssetBundle.LoadFromFile(text); Plugin.Log.Log((LogLevel)(Object.op_Implicit((Object)(object)bundle) ? 16 : 4), (object)(Object.op_Implicit((Object)(object)bundle) ? ("Loaded bundle " + text) : ("Bundle found but could not be read: " + text))); } else { bundle = LoadEmbeddedBundle(); Plugin.Log.Log((LogLevel)(Object.op_Implicit((Object)(object)bundle) ? 16 : 4), (object)(Object.op_Implicit((Object)(object)bundle) ? "No bundle file next to the DLL - loaded the embedded copy from this assembly (release build)." : ("Bundle not found: " + text + ", and this build has no embedded bundle."))); } } value = (Object.op_Implicit((Object)(object)bundle) ? bundle.LoadAsset<AnimationClip>(name) : null); if ((Object)(object)value == (Object)null) { Plugin.Log.LogWarning((object)("Custom clip '" + name + "' not found in the bundle.")); } else if (!Array.Exists(value.events, (AnimationEvent e) => e.functionName == "OnAttackTrigger")) { Plugin.Log.LogWarning((object)("Custom clip '" + name + "' has no OnAttackTrigger event - it would never hit. Ignoring it.")); value = null; } else { Plugin.Log.LogInfo((object)$"Custom clip '{name}' loaded ({value.length:0.00}s)."); } clips[name] = value; return value; } internal static void Apply(Animator animator, bool on, bool freeHand = false, bool throwing = false, bool torch = false, bool guard = false) { if ((Object)(object)animator == (Object)null) { return; } List<KeyValuePair<string, AnimationClip>> pairs = new List<KeyValuePair<string, AnimationClip>>(); if (throwing) { string name = ((freeHand && !string.IsNullOrEmpty(Plugin.ThrowCustomClipFree.Value)) ? Plugin.ThrowCustomClipFree.Value : Plugin.ThrowCustomClip.Value); if (torch && (Object)(object)Clip(Plugin.ThrowCustomClip.Value + "_Torch") != (Object)null) { name = Plugin.ThrowCustomClip.Value + "_Torch"; } AnimationClip val = Clip(name); if ((Object)(object)val != (Object)null) { pairs.Add(new KeyValuePair<string, AnimationClip>(Plugin.ThrowReplacesClip.Value, val)); } } else if (on) { for (int i = 0; i < 3; i++) { string value = Plugin.HitReplaceClip[i].Value; string name2 = ((freeHand && !string.IsNullOrEmpty(Plugin.HitCustomClipFree[i].Value)) ? Plugin.HitCustomClipFree[i].Value : Plugin.HitCustomClip[i].Value); if (guard) { string value2 = Plugin.GuardClip[i].Value; name2 = ((freeHand && (Object)(object)Clip(value2 + "_Free") != (Object)null) ? (value2 + "_Free") : ((torch && (Object)(object)Clip(value2 + "_Torch") != (Object)null) ? (value2 + "_Torch") : value2)); } else if (torch && (Object)(object)Clip(Plugin.HitCustomClip[i].Value + "_Torch") != (Object)null) { name2 = Plugin.HitCustomClip[i].Value + "_Torch"; } AnimationClip val2 = (string.IsNullOrEmpty(value) ? null : Clip(name2)); if ((Object)(object)val2 != (Object)null) { pairs.Add(new KeyValuePair<string, AnimationClip>(value, val2)); } } } string text = string.Join("|", pairs.ConvertAll((KeyValuePair<string, AnimationClip> p) => p.Key + ">" + ((Object)p.Value).name)); 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 (pairs.Count == 0) { return; } slot = Wrap(animator); if (slot == null) { return; } } if (slot.AppliedSignature == text) { return; } Preserving(animator, delegate { List<KeyValuePair<AnimationClip, AnimationClip>> list = new List<KeyValuePair<AnimationClip, AnimationClip>>(); slot.Controller.GetOverrides(list); for (int j = 0; j < list.Count; j++) { AnimationClip key = list[j].Key; AnimationClip value3 = null; foreach (KeyValuePair<string, AnimationClip> item in pairs) { if ((Object)(object)key != (Object)null && ((Object)key).name == item.Key) { value3 = item.Value; } } list[j] = new KeyValuePair<AnimationClip, AnimationClip>(key, value3); } slot.Controller.ApplyOverrides((IList<KeyValuePair<AnimationClip, AnimationClip>>)list); }); slot.AppliedSignature = text; } private static Slot Wrap(Animator animator) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController; if ((Object)(object)runtimeAnimatorController == (Object)null) { return null; } if (runtimeAnimatorController is AnimatorOverrideController) { Plugin.Log.LogWarning((object)"Player animator is already overridden by another mod; custom clips are off to avoid a conflict."); return null; } AnimatorOverrideController controller = new AnimatorOverrideController(runtimeAnimatorController) { name = ((Object)runtimeAnimatorController).name + " (SpearCombo)" }; Preserving(animator, delegate { animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)controller; }); Slot slot = new Slot { Controller = controller, Base = runtimeAnimatorController }; 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected I4, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected I4, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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++) { AnimatorControllerParameterType type = parameters[j].type; switch (type - 1) { case 0: array3[j] = animator.GetFloat(parameters[j].nameHash); break; case 2: array3[j] = animator.GetInteger(parameters[j].nameHash); break; case 3: array3[j] = (animator.GetBool(parameters[j].nameHash) ? 1f : 0f); break; } } float speed = animator.speed; change(); animator.Update(0f); for (int k = 0; k < parameters.Length; k++) { AnimatorControllerParameterType type = parameters[k].type; switch (type - 1) { case 0: animator.SetFloat(parameters[k].nameHash, array3[k]); break; case 2: animator.SetInteger(parameters[k].nameHash, (int)array3[k]); break; case 3: animator.SetBool(parameters[k].nameHash, array3[k] != 0f); break; } } 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; } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] internal static class EquipPatch { private static void Prefix(ItemData item) { Combo.Apply(item?.m_shared); } } [HarmonyPatch(typeof(VisEquipment), "AttachItem")] internal static class AttachPatch { private static void Postfix(int itemHash, GameObject __result) { if (Plugin.Flip.Value && !((Object)(object)__result == (Object)null)) { SharedData val = Combo.SharedFromHash(itemHash); if (Combo.IsComboSpear(val)) { SpearFlip.Flip(__result, val.m_name == "$item_spear_wolffang"); } } } } [HarmonyPatch(typeof(ZSyncAnimation), "RPC_SetTrigger")] internal static class TriggerPatch { private static string lastGuardName; private static float lastGuardAt = -10f; private static string lastComboName; private static float lastComboAt = -10f; private static void Prefix(ZSyncAnimation __instance, ref string name) { if (name == null || name.StartsWith("spear_dup_ignored", StringComparison.Ordinal)) { return; } if (name.StartsWith("spearguard", StringComparison.Ordinal)) { ComboState component = ((Component)__instance).GetComponent<ComboState>(); bool flag = (Object)(object)component != (Object)null && component.Level >= 0 && Time.time < component.LastActive + 0.05f; if (name == lastGuardName && (flag || Time.time - lastGuardAt < 0.12f)) { Plugin.Log.LogDebug((object)("Duplicate guard trigger '" + name + "' swallowed (would have restarted the hit).")); GuardCombo.SwallowedSinceStart = true; name = "spear_dup_ignored"; return; } lastGuardName = name; lastGuardAt = Time.time; name = Combo.MapTrigger(name, "spearguard", out var level); ComboState.Begin(__instance, level, guard: true); if (Refs.AnimatorOf != null) { CustomClips.Apply(Refs.AnimatorOf.Invoke(__instance), on: true, LeftHandEmpty((Component)(object)__instance), throwing: false, LeftHandTorch((Component)(object)__instance), guard: true); } return; } if (name.StartsWith("spearcombo", StringComparison.Ordinal)) { ComboState component2 = ((Component)__instance).GetComponent<ComboState>(); bool flag2 = (Object)(object)component2 != (Object)null && component2.Level >= 0 && Time.time < component2.LastActive + 0.05f; if (name == lastComboName && (flag2 || Time.time - lastComboAt < 0.12f)) { Plugin.Log.LogDebug((object)("Duplicate combo trigger '" + name + "' swallowed (would have restarted the hit).")); name = "spear_dup_ignored"; return; } lastComboName = name; lastComboAt = Time.time; name = Combo.MapTrigger(name, out var level2); ComboState.Begin(__instance, level2); if (Refs.AnimatorOf != null) { CustomClips.Apply(Refs.AnimatorOf.Invoke(__instance), on: true, LeftHandEmpty((Component)(object)__instance), throwing: false, LeftHandTorch((Component)(object)__instance)); } return; } if (name == "spear_throw" && Plugin.JumpBackThrow.Value && Combo.IsComboSpear(RightWeapon((Component)(object)__instance)) && ComboState.InThrowWindow(__instance) && Refs.AnimatorOf != null && (Object)(object)CustomClips.Clip(LeftHandEmpty((Component)(object)__instance) ? Plugin.ThrowCustomClipFree.Value : Plugin.ThrowCustomClip.Value) != (Object)null) { CustomClips.Apply(Refs.AnimatorOf.Invoke(__instance), on: true, LeftHandEmpty((Component)(object)__instance), throwing: true, LeftHandTorch((Component)(object)__instance)); ComboState.Throw(__instance); ComboState.MarkSoftThrow(__instance); ComboState.Spend(__instance); Character component3 = ((Component)__instance).GetComponent<Character>(); if ((Object)(object)component3 != (Object)null && (Object)(object)component3 == (Object)(object)Player.m_localPlayer) { (((Component)component3).GetComponent<JumpBack>() ?? ((Component)component3).gameObject.AddComponent<JumpBack>()).Arm(Plugin.JumpBackDelay.Value); } return; } if (Refs.AnimatorOf != null) { CustomClips.Apply(Refs.AnimatorOf.Invoke(__instance), on: false); } if (name == "spear_throw") { ComboState.End(__instance); GameObject val = SpearFlip.RightItemOf((Component)(object)__instance); FlipMark flipMark = (((Object)(object)val != (Object)null) ? val.GetComponent<FlipMark>() : null); if ((Object)(object)flipMark != (Object)null) { flipMark.Flipped = false; flipMark.ReflipAt = Time.time + 1.5f; SpearFlip.ApplyPose(val, flipMark, -1); } } } internal static SharedData RightWeapon(Component c) { Humanoid component = c.GetComponent<Humanoid>(); VisEquipment val = (((Object)(object)component != (Object)null) ? component.GetVisEquipment() : null); if (!((Object)(object)val != (Object)null) || Refs.RightItemHash == null) { return null; } return Combo.SharedFromHash(Refs.RightItemHash.Invoke(val)); } internal static bool LeftHandEmpty(Component c) { Humanoid component = c.GetComponent<Humanoid>(); VisEquipment val = (((Object)(object)component != (Object)null) ? component.GetVisEquipment() : null); if ((Object)(object)val != (Object)null && Refs.LeftItemHash != null) { return Refs.LeftItemHash.Invoke(val) == 0; } return false; } internal static bool LeftHandTorch(Component c) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 Humanoid component = c.GetComponent<Humanoid>(); VisEquipment val = (((Object)(object)component != (Object)null) ? component.GetVisEquipment() : null); if ((Object)(object)val == (Object)null || Refs.LeftItemHash == null) { return false; } SharedData val2 = Combo.SharedFromHash(Refs.LeftItemHash.Invoke(val)); if (val2 != null) { return (int)val2.m_itemType == 15; } return false; } } [HarmonyPatch(typeof(ZSyncAnimation), "SyncParameters")] internal static class ComboUpdatePatch { private const float ThrowFallbackSeconds = 1.3f; private static void Postfix(ZSyncAnimation __instance) { GameObject val = SpearFlip.RightItemOf((Component)(object)__instance); FlipMark flipMark = (((Object)(object)val != (Object)null) ? val.GetComponent<FlipMark>() : null); ComboState component = ((Component)__instance).GetComponent<ComboState>(); int num = Track(__instance, component); GuardCombo.KeepQueuedClick(component, __instance); GuardCombo.SuppressBlockPose(__instance, component); FireThrowIfDue(__instance, component); if (num < 0) { PreloadClips(__instance, component); } if ((Object)(object)flipMark != (Object)null && Plugin.Flip.Value) { if (!flipMark.Flipped && num < 0 && Time.time > flipMark.ReflipAt) { flipMark.Flipped = true; SpearFlip.ApplyPose(val, flipMark, -1); } else if (num >= 0 || flipMark.PoseActive) { SpearFlip.ApplyPose(val, flipMark, num); } } } private static void PreloadClips(ZSyncAnimation zanim, ComboState st) { if (Refs.AnimatorOf == null || !Combo.IsComboSpear(TriggerPatch.RightWeapon((Component)(object)zanim))) { return; } Humanoid component = ((Component)zanim).GetComponent<Humanoid>(); if ((Object)(object)component == (Object)null) { return; } int num; if (Plugin.DefenceCombo.Value) { if (!((Object)(object)component == (Object)(object)Player.m_localPlayer) || !(Refs.Blocking != null)) { num = (((Character)component).IsBlocking() ? 1 : 0); } else { object value = Refs.Blocking.GetValue(component); bool flag = default(bool); int num2; if (value is bool) { flag = (bool)value; num2 = 1; } else { num2 = 0; } num = num2 & (flag ? 1 : 0); } } else { num = 0; } bool flag2 = (byte)num != 0; bool flag3 = TriggerPatch.LeftHandEmpty((Component)(object)zanim); bool flag4 = TriggerPatch.LeftHandTorch((Component)(object)zanim); int num3 = (int)((flag2 ? 1u : 0u) | (uint)(flag3 ? 2 : 0)) | (flag4 ? 4 : 0); if ((Object)(object)st == (Object)null) { st = ((Component)zanim).gameObject.AddComponent<ComboState>(); } if (st.PreloadedSet != num3 && !(Time.time < st.LastActive + 0.3f)) { st.PreloadedSet = num3; CustomClips.Apply(Refs.AnimatorOf.Invoke(zanim), on: true, flag3, throwing: false, flag4, flag2); } } private static void FireThrowIfDue(ZSyncAnimation zanim, ComboState st) { if ((Object)(object)st == (Object)null || st.ThrowAt <= 0f || st.ThrowFired) { return; } if (st.PendingThrow == null && Refs.CurrentAttack != null) { Humanoid component = ((Component)zanim).GetComponent<Humanoid>(); if ((Object)(object)component != (Object)null) { object? value = Refs.CurrentAttack.GetValue(component); Attack val = (Attack)((value is Attack) ? value : null); if (val != null && val.m_attackAnimation == "spear_throw") { st.PendingThrow = val; } } } if (Time.time < st.ThrowAt + 1.3f) { return; } st.ThrowFired = true; Attack pendingThrow = st.PendingThrow; st.PendingThrow = null; if (pendingThrow == null || Refs.FireProjectileBurst == null) { Plugin.Log.LogError((object)"Jump-back throw: no attack captured, spear not released."); return; } if (GameThrowWatch.FiredSince(pendingThrow, st.ThrowAt)) { Plugin.Log.LogInfo((object)"Jump-back throw: spear released by its own trigger at the throwing motion (no duplicate)."); return; } try { Refs.FireProjectileBurst.Invoke(pendingThrow, null); Plugin.Log.LogWarning((object)("Jump-back throw: its trigger never arrived - fallback release from '" + pendingThrow.m_attackAnimation + "'.")); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not fire the throw projectile: " + ex.GetType().Name + ": " + ex.Message)); } } private static float HoldGuardPose(ComboState st, Animator anim, float playSpeed) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) float value = Plugin.GuardHold.Value; if (!st.Guard || value <= 0f) { st.GuardHolding = false; return playSpeed; } if (!st.GuardHolding && !st.GuardHoldDone) { AnimatorStateInfo currentAnimatorStateInfo = anim.GetCurrentAnimatorStateInfo(0); if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime >= 0.97f) { st.GuardHolding = true; st.GuardHoldFrom = Time.time; } } if (st.GuardHolding) { if (Time.time - st.GuardHoldFrom < value) { return 0.0001f; } st.GuardHolding = false; st.GuardHoldDone = true; } return playSpeed; } private static int Track(ZSyncAnimation zanim, ComboState st) { if ((Object)(object)st == (Object)null || st.Level < 0) { RestoreAnimSpeed(zanim); return -1; } if (Time.time > st.ExpireAt) { st.Level = -1; RestoreAnimSpeed(zanim); return -1; } if (Time.time < st.CaptureAt || Refs.AnimatorOf == null) { return st.Level; } Animator val = Refs.AnimatorOf.Invoke(zanim); if ((Object)(object)val == (Object)null) { return st.Level; } string text = TopClip(val.GetCurrentAnimatorClipInfo(0)); string text2 = (val.IsInTransition(0) ? TopClip(val.GetNextAnimatorClipInfo(0)) : null); if (st.Clip == null) { st.Clip = text2 ?? text; if (st.Clip == null) { return st.Level; } } if (text == st.Clip || text2 == st.Clip) { val.speed = HoldGuardPose(st, val, Plugin.HitSpeed[st.Level].Value); st.LastActive = Time.time; return st.Level; } st.Level = -1; RestoreAnimSpeed(zanim); return -1; } private static void RestoreAnimSpeed(ZSyncAnimation zanim) { if (Refs.AnimatorOf != null) { Animator val = Refs.AnimatorOf.Invoke(zanim); if ((Object)(object)val != (Object)null && !Mathf.Approximately(val.speed, 1f)) { val.speed = 1f; } } } private static string TopClip(AnimatorClipInfo[] infos) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) string result = null; float num = -1f; for (int i = 0; i < infos.Length; i++) { AnimatorClipInfo val = infos[i]; if ((Object)(object)((AnimatorClipInfo)(ref val)).clip != (Object)null && ((AnimatorClipInfo)(ref val)).weight > num) { num = ((AnimatorClipInfo)(ref val)).weight; result = ((Object)((AnimatorClipInfo)(ref val)).clip).name; } } return result; } } }