using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Firewalker")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("HP")] [assembly: AssemblyProduct("Firewalker")] [assembly: AssemblyCopyright("Copyright © HP 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("d31623da-1e30-46b4-b2bb-1d153dbde9c0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = "")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 Firewalker { [BepInPlugin("YouDied.Firewalker", "Firewalker", "1.0.1")] [BepInProcess("valheim.exe")] public class FirewalkerPlugin : BaseUnityPlugin { public const string PluginGUID = "YouDied.Firewalker"; public const string PluginName = "Firewalker"; public const string PluginVersion = "1.0.1"; internal static ManualLogSource Log; public static ConfigEntry ModEnabled; public static ConfigEntry FirePotionStatusEffectName; private readonly Harmony _harmony = new Harmony("YouDied.Firewalker"); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable or disable the Firewalker mod."); FirePotionStatusEffectName = ((BaseUnityPlugin)this).Config.Bind("General", "FirePotionStatusEffect", "GP_MeadFireResist", "Prefab name prefix of the active StatusEffect that counts as a 'fire potion'. Default targets the vanilla Fire Resistance Mead."); if (ModEnabled.Value) { _harmony.PatchAll(typeof(Patches)); Log.LogInfo((object)"Firewalker 1.0.1 loaded – walk through fire, fear no lava."); } } private void OnDestroy() { _harmony.UnpatchSelf(); } public static bool LocalPlayerHasFirePotion() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } string value = FirePotionStatusEffectName.Value ?? string.Empty; foreach (StatusEffect statusEffect in ((Character)localPlayer).GetSEMan().GetStatusEffects()) { if ((Object)(object)statusEffect != (Object)null && ((Object)statusEffect).name != null && ((Object)statusEffect).name.StartsWith(value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static bool IsEnemyAttacker(HitData hit) { if (hit == null) { return false; } Character attacker = hit.GetAttacker(); return (Object)(object)attacker != (Object)null && !(attacker is Player); } } public static class Patches { private static readonly FieldInfo _fi_lavaDamageTimer = AccessTools.Field(typeof(Character), "m_lavaDamageTimer"); private static readonly FieldInfo _fi_aboveOrInLavaTimer = AccessTools.Field(typeof(Character), "m_aboveOrInLavaTimer"); private static readonly FieldInfo _fi_tolerateFire = AccessTools.Field(typeof(Character), "m_tolerateFire"); private static readonly FieldInfo _fi_semanCharacter = AccessTools.Field(typeof(SEMan), "m_character"); internal static bool s_currentHitIsEnemy = false; private static bool ICantSwimIsWalking { get { try { Type type = Type.GetType("ICantSwim.State, ICantSwim", throwOnError: false); if (type == null) { return false; } FieldInfo field = type.GetField("WalkingOnWater", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return field != null && (bool)field.GetValue(null); } catch { return false; } } } [HarmonyPatch(typeof(Character), "CustomFixedUpdate")] [HarmonyPrefix] public static void Character_FixedUpdate_Prefix(Character __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { _fi_tolerateFire.SetValue(__instance, true); } } [HarmonyPatch(typeof(Character), "UpdateLava")] [HarmonyPrefix] public static void UpdateLava_Prefix(Character __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { _fi_lavaDamageTimer.SetValue(__instance, 0f); _fi_aboveOrInLavaTimer.SetValue(__instance, 0f); } } [HarmonyPatch(typeof(Character), "RPC_Damage")] [HarmonyPrefix] public static void RPC_Damage_Prefix(long sender, HitData hit) { s_currentHitIsEnemy = FirewalkerPlugin.IsEnemyAttacker(hit); } [HarmonyPatch(typeof(Character), "RPC_Damage")] [HarmonyPostfix] public static void RPC_Damage_Postfix() { s_currentHitIsEnemy = false; } [HarmonyPatch(typeof(Character), "ApplyDamage")] [HarmonyPrefix] public static void Character_ApplyDamage_Prefix(Character __instance, ref HitData hit) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && hit != null && !s_currentHitIsEnemy) { hit.m_damage.m_fire = 0f; if (((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f) { hit.m_damage.m_blunt = 0f; hit.m_damage.m_slash = 0f; hit.m_damage.m_pierce = 0f; hit.m_damage.m_chop = 0f; hit.m_damage.m_pickaxe = 0f; hit.m_damage.m_frost = 0f; hit.m_damage.m_lightning = 0f; hit.m_damage.m_poison = 0f; hit.m_damage.m_spirit = 0f; } } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float) })] [HarmonyPrefix] public static bool SEMan_AddStatusEffect_Prefix(SEMan __instance, StatusEffect statusEffect) { if ((Object)(object)statusEffect == (Object)null) { return true; } object? value = _fi_semanCharacter.GetValue(__instance); Character val = (Character)((value is Character) ? value : null); if (!((Object)(object)val == (Object)null)) { Player val2 = (Player)(object)((val is Player) ? val : null); if (val2 != null) { if ((Object)(object)val2 != (Object)(object)Player.m_localPlayer) { return true; } if (statusEffect is SE_Burning) { return s_currentHitIsEnemy; } if (statusEffect is SE_Wet && ICantSwimIsWalking) { return false; } return true; } } return true; } } }