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 FistAttackMod v1.0.0
plugins/FistAttackPlugin.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("FistAttackPlugin")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("FistAttackPlugin")] [assembly: AssemblyTitle("FistAttackPlugin")] [assembly: AssemblyVersion("1.0.0.0")] namespace FistAttackPlugin; internal static class FistWeaponFilter { internal static bool Matches(ItemData weapon) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } if ((int)weapon.m_shared.m_skillType == 11) { return true; } GameObject dropPrefab = weapon.m_dropPrefab; string text = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? string.Empty; return text.IndexOf("Fist", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Claw", StringComparison.OrdinalIgnoreCase) >= 0; } } internal static class FistBaselineKick { private static Attack _cached; internal static Attack Get(Humanoid humanoid) { if (_cached != null) { return _cached; } Attack val = humanoid?.m_unarmedWeapon?.m_itemData?.m_shared?.m_secondaryAttack; if (val == null) { Plugin.Log.LogWarning((object)"[FistChain] Humanoid.m_unarmedWeapon에서 발차기(2차 공격)를 찾지 못했습니다. 3타 체인이 비활성화됩니다."); return null; } _cached = val; return _cached; } } internal static class FistChainSystem { private sealed class ChainState { public int Level; } private static readonly ConditionalWeakTable<Character, ChainState> _states = new ConditionalWeakTable<Character, ChainState>(); private static readonly HashSet<Character> _pendingPrimary = new HashSet<Character>(); private const float ChainMaxTime = 0.2f; internal static void OnPrimaryStartAttempt(Humanoid humanoid) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown if (!Plugin.FcEnable.Value) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!FistWeaponFilter.Matches(currentWeapon) || FistBaselineKick.Get(humanoid) == null) { return; } if (Plugin.FcMinSkillLevel.Value > 0f) { Player val = (Player)(object)((humanoid is Player) ? humanoid : null); if (val != null && ((Character)val).GetSkillLevel((SkillType)11) < Plugin.FcMinSkillLevel.Value) { return; } } _pendingPrimary.Add((Character)humanoid); } internal static void ClearPendingIfLeftover(Character ch) { _pendingPrimary.Remove(ch); } internal static bool TryConsumePending(Character ch) { return _pendingPrimary.Remove(ch); } internal static int GetLevel(Character ch, float timeSinceLastAttack) { ChainState value = _states.GetValue(ch, (Character _) => new ChainState()); if (timeSinceLastAttack > 0.2f) { value.Level = 0; } return value.Level; } internal static void SetLevel(Character ch, int level) { ChainState value = _states.GetValue(ch, (Character _) => new ChainState()); value.Level = level; } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] internal static class HumanoidStartAttack_FistChain_Patch { private static void Prefix(Humanoid __instance, bool secondaryAttack) { if (!secondaryAttack) { FistChainSystem.OnPrimaryStartAttempt(__instance); } } private static void Postfix(Humanoid __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown FistChainSystem.ClearPendingIfLeftover((Character)__instance); } } [HarmonyPatch(typeof(Attack), "Start")] internal static class AttackStart_FistChain_Patch { private static void Prefix(Attack __instance, Humanoid character, ItemData weapon, float timeSinceLastAttack) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) Character ch = (Character)character; if (!FistChainSystem.TryConsumePending(ch) || !FistWeaponFilter.Matches(weapon)) { return; } Attack val = FistBaselineKick.Get(character); if (val != null) { int level = FistChainSystem.GetLevel(ch, timeSinceLastAttack); if (level < 2) { FistChainSystem.SetLevel(ch, level + 1); return; } __instance.m_attackAnimation = val.m_attackAnimation; __instance.m_attackChainLevels = 0; __instance.m_attackRandomAnimations = 0; __instance.m_attackType = val.m_attackType; __instance.m_attackRange = val.m_attackRange; __instance.m_attackHeight = val.m_attackHeight; __instance.m_attackOffset = val.m_attackOffset; __instance.m_attackAngle = val.m_attackAngle; __instance.m_attackRayWidth = val.m_attackRayWidth; __instance.m_maxYAngle = val.m_maxYAngle; __instance.m_forceMultiplier = val.m_forceMultiplier; __instance.m_damageMultiplier = val.m_damageMultiplier * Mathf.Max(0f, Plugin.FcKickDamageMult.Value); __instance.m_staggerMultiplier = val.m_staggerMultiplier; __instance.m_attackStamina = val.m_attackStamina; __instance.m_attackEitr = val.m_attackEitr; __instance.m_attackHealth = val.m_attackHealth; __instance.m_attackHealthPercentage = val.m_attackHealthPercentage; __instance.m_attackHealthReturnHit = val.m_attackHealthReturnHit; __instance.m_attackHealthLowBlockUse = val.m_attackHealthLowBlockUse; __instance.m_attackStartNoise = val.m_attackStartNoise; __instance.m_attackHitNoise = val.m_attackHitNoise; __instance.m_hitTerrain = val.m_hitTerrain; __instance.m_hitFriendly = val.m_hitFriendly; __instance.m_hitThroughWalls = val.m_hitThroughWalls; __instance.m_multiHit = val.m_multiHit; __instance.m_lowerDamagePerHit = val.m_lowerDamagePerHit; __instance.m_hitPointtype = val.m_hitPointtype; __instance.m_recoilPushback = val.m_recoilPushback; FistChainSystem.SetLevel(ch, 0); } } } [BepInPlugin("com.fistattack.plugin", "FistAttackMod", "1.0.0")] [BepInProcess("valheim.exe")] public class Plugin : BaseUnityPlugin { public const string GUID = "com.fistattack.plugin"; public const string NAME = "FistAttackMod"; public const string VERSION = "1.0.0"; private readonly Harmony _harmony = new Harmony("com.fistattack.plugin"); internal static ManualLogSource Log; internal static ConfigEntry<bool> FcEnable; internal static ConfigEntry<float> FcKickDamageMult; internal static ConfigEntry<float> FcMinSkillLevel; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; FcEnable = ((BaseUnityPlugin)this).Config.Bind<bool>("FistChain", "Enable", true, "Fist(주먹/클로/Warfare 등) 계열 무기 — 좌클릭 3연타: 펀치 + 펀치 + 킥(바닐라 Fists 발차기 고정 사용). 무기 고유의 2차 공격(우클릭 특수기)은 그대로 유지되며 3타 체인과 무관함."); FcKickDamageMult = ((BaseUnityPlugin)this).Config.Bind<float>("FistChain", "KickDamageMult", 2f, "3타(킥) 데미지 배율 — 바닐라 Fists 발차기 데미지에 곱함 (1.0 = 원래 발차기 데미지 그대로)"); FcMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind<float>("FistChain", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Unarmed (0~100, 0 = 제한 없음)"); _harmony.PatchAll(); Log.LogInfo((object)"FistAttackMod 1.0.0 로드 완료"); } private void OnDestroy() { _harmony.UnpatchSelf(); } }