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 MonsterFallDamage v1.1.0
plugins/MonsterFallDamagePlugin/MonsterFallDamagePlugin.dll
Decompiled 2 weeks agousing System; 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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("MonsterFallDamagePlugin")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MonsterFallDamagePlugin")] [assembly: AssemblyTitle("MonsterFallDamagePlugin")] [assembly: AssemblyVersion("1.0.0.0")] namespace MonsterFallDamagePlugin; [BepInPlugin("com.mods.monsterfallDamage", "MonsterFallDamage", "1.1.0")] [BepInProcess("valheim.exe")] public class Plugin : BaseUnityPlugin { public const string GUID = "com.mods.monsterfallDamage"; public const string NAME = "MonsterFallDamage"; public const string VERSION = "1.1.0"; internal static ManualLogSource Log; private readonly Harmony _harmony = new Harmony("com.mods.monsterfallDamage"); internal static ConfigEntry<bool> ApplyToPlayer; internal static ConfigEntry<float> MinFallHeight; internal static ConfigEntry<float> DamageDistance; internal static ConfigEntry<float> DamagePerUnit; internal static ConfigEntry<float> MaxDamage; internal static ConfigEntry<bool> IgnoreJumpAscent; internal static ConfigEntry<bool> IgnoreFlyingLandings; internal static ConfigEntry<float> FlyingLandingGraceSeconds; internal static ConfigEntry<bool> EnableDebugLog; internal static ConfigEntry<string> ExemptPrefabPrefixes; private void Awake() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ApplyToPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("Fall Damage", "Apply To Player", true, "If true, the same fall damage formula is applied to the player (overrides Valheim default)."); MinFallHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Fall Damage", "Min Fall Height (m)", 4f, new ConfigDescription("Falls below this height deal no damage. (Player default: 4)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>())); DamageDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Fall Damage", "Damage Interval (m)", 16f, new ConfigDescription("Damage is added for every X meters fallen above the minimum height. (Player default: 16)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 100f), Array.Empty<object>())); DamagePerUnit = ((BaseUnityPlugin)this).Config.Bind<float>("Fall Damage", "Damage Per Interval", 100f, new ConfigDescription("Damage dealt per interval distance. (Player default: 100)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); MaxDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Fall Damage", "Max Damage (0 for unlimited)", 100f, new ConfigDescription("Maximum fall damage cap. Set to 0 for no limit. (Player default: 100)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 99999f), Array.Empty<object>())); IgnoreJumpAscent = ((BaseUnityPlugin)this).Config.Bind<bool>("Fall Exemption", "IgnoreJumpAscent", true, "Height gained by a creature's own jump is not counted toward fall damage (hopping on flat ground deals no damage; jumping off a cliff only counts the drop below the take-off point)."); IgnoreFlyingLandings = ((BaseUnityPlugin)this).Config.Bind<bool>("Fall Exemption", "IgnoreFlyingLandings", true, "While flying, the altitude baseline is reset every frame, and no fall damage is applied for a short grace period after landing."); FlyingLandingGraceSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fall Exemption", "FlyingLandingGraceSeconds", 3f, new ConfigDescription("Grace period (seconds) after a flying creature lands during which fall damage is not applied.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); EnableDebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLog", false, "Logs verification details on each landing (prefab name, heights, exemption reason, etc). Can be left off once verified."); ExemptPrefabPrefixes = ((BaseUnityPlugin)this).Config.Bind<string>("Fall Exemption", "ExemptPrefabPrefixes", "Blob", "Creatures whose prefab name (after stripping \"(Clone)\", case-insensitive) starts with one of these comma-separated prefixes are fully immune to fall damage (other damage is unaffected). The default \"Blob\" covers all slime variants (Blob/BlobElite/BlobAspect/BlobLava/BlobTar/ BlobMork/BlobMorkMini/BlobFrost, etc)."); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"MonsterFallDamage 1.1.0 loaded."); } private void OnDestroy() { _harmony.UnpatchSelf(); } } internal static class FallExemptionState { internal sealed class State { public float? JumpStartY; public float JumpRecordedAt = -1f; public float FlyingGraceUntil = -1f; public bool WasAirborne; public bool? IsFallDamageExempt; } private static readonly ConditionalWeakTable<Character, State> _table = new ConditionalWeakTable<Character, State>(); public static State Get(Character c) { return _table.GetOrCreateValue(c); } } [HarmonyPatch(typeof(Character), "Jump")] public static class Patch_RecordJumpStart { public static void Postfix(Character __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (Plugin.IgnoreJumpAscent.Value) { FallExemptionState.State state = FallExemptionState.Get(__instance); float y = ((Component)__instance).transform.position.y; state.JumpStartY = y; state.JumpRecordedAt = Time.time; if (Plugin.EnableDebugLog.Value) { Plugin.Log.LogInfo((object)$"[MonsterFallDamage:점프기록] id={((Object)__instance).GetInstanceID()} {((Object)((Component)__instance).gameObject).name} | 기록Y={y:F2}"); } } } } [HarmonyPatch(typeof(Character), "UpdateFlying")] public static class Patch_FlyingBaselineReset { private static readonly FieldInfo f_maxAirAltitude = AccessTools.Field(typeof(Character), "m_maxAirAltitude"); public static void Postfix(Character __instance) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (Plugin.IgnoreFlyingLandings.Value) { f_maxAirAltitude.SetValue(__instance, ((Component)__instance).transform.position.y); } } } [HarmonyPatch(typeof(Character), "Land")] public static class Patch_FlyingLandGrace { public static void Postfix(Character __instance) { if (Plugin.IgnoreFlyingLandings.Value) { FallExemptionState.State state = FallExemptionState.Get(__instance); state.FlyingGraceUntil = Time.time + Plugin.FlyingLandingGraceSeconds.Value; } } } [HarmonyPatch(typeof(Character), "UpdateGroundContact")] public static class Patch_MonsterFallDamage { private const float JumpRecordExpirySeconds = 0.5f; private static readonly FieldInfo f_groundContact = AccessTools.Field(typeof(Character), "m_groundContact"); private static readonly FieldInfo f_maxAirAltitude = AccessTools.Field(typeof(Character), "m_maxAirAltitude"); private static readonly FieldInfo f_groundContactPoint = AccessTools.Field(typeof(Character), "m_groundContactPoint"); private static readonly FieldInfo f_groundContactNormal = AccessTools.Field(typeof(Character), "m_groundContactNormal"); public static void Prefix(Character __instance) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Expected O, but got Unknown //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) if (__instance.IsDead()) { return; } bool flag = __instance.IsPlayer(); if (flag && !Plugin.ApplyToPlayer.Value) { return; } FallExemptionState.State state = FallExemptionState.Get(__instance); if (!(bool)f_groundContact.GetValue(__instance)) { state.WasAirborne = true; return; } bool wasAirborne = state.WasAirborne; state.WasAirborne = false; if (!wasAirborne) { if (state.JumpStartY.HasValue && Time.time - state.JumpRecordedAt > 0.5f) { if (Plugin.EnableDebugLog.Value) { Plugin.Log.LogInfo((object)($"[MonsterFallDamage:점프기록만료] id={((Object)__instance).GetInstanceID()} {((Object)((Component)__instance).gameObject).name} | " + $"기록Y={state.JumpStartY.Value:F2} (공중 상태 진입 없이 {0.5f:F1}초 경과)")); } state.JumpStartY = null; } return; } float y = ((Component)__instance).transform.position.y; if (!state.IsFallDamageExempt.HasValue) { state.IsFallDamageExempt = IsExemptPrefab(((Object)((Component)__instance).gameObject).name); } if (state.IsFallDamageExempt.Value) { float num = (float)f_maxAirAltitude.GetValue(__instance); float num2 = num; if (Plugin.IgnoreJumpAscent.Value && state.JumpStartY.HasValue) { num2 = Mathf.Min(num2, state.JumpStartY.Value); } float fallHeight = Mathf.Max(0f, num2 - y); state.JumpStartY = null; Log(__instance, num, num2, y, fallHeight, 0f, "슬라임 면제"); return; } if (Plugin.IgnoreFlyingLandings.Value && Time.time < state.FlyingGraceUntil) { if (flag) { f_maxAirAltitude.SetValue(__instance, y); } state.JumpStartY = null; Log(__instance, 0f, null, y, 0f, 0f, "비행 착지 유예"); return; } float num3 = (float)f_maxAirAltitude.GetValue(__instance); float num4 = num3; if (Plugin.IgnoreJumpAscent.Value && state.JumpStartY.HasValue) { num4 = Mathf.Min(num4, state.JumpStartY.Value); } float num5 = Mathf.Max(0f, num4 - y); state.JumpStartY = null; float value = Plugin.MinFallHeight.Value; if (num5 <= value) { Log(__instance, num3, num4, y, num5, 0f, "최소 낙하 높이 미만"); return; } float num6 = (num5 - value) / Plugin.DamageDistance.Value * Plugin.DamagePerUnit.Value; float value2 = Plugin.MaxDamage.Value; if (value2 > 0f) { num6 = Mathf.Min(num6, value2); } if (num6 <= 0f) { Log(__instance, num3, num4, y, num5, 0f, "계산 데미지 0 이하"); return; } if (flag) { f_maxAirAltitude.SetValue(__instance, y); } Vector3 point = (Vector3)f_groundContactPoint.GetValue(__instance); Vector3 dir = (Vector3)f_groundContactNormal.GetValue(__instance); HitData val = new HitData(); val.m_damage.m_damage = num6; val.m_point = point; val.m_dir = dir; val.m_hitType = (HitType)3; __instance.Damage(val); Log(__instance, num3, num4, y, num5, num6, null); } private static bool IsExemptPrefab(string gameObjectName) { string text = (gameObjectName.EndsWith("(Clone)") ? gameObjectName.Substring(0, gameObjectName.Length - "(Clone)".Length) : gameObjectName); string[] array = Plugin.ExemptPrefabPrefixes.Value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text2 in array2) { string text3 = text2.Trim(); if (text3.Length != 0 && text.StartsWith(text3, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static void Log(Character c, float maxAlt, float? baseline, float currentY, float fallHeight, float damage, string exemptReason) { if (Plugin.EnableDebugLog.Value) { string name = ((Object)((Component)c).gameObject).name; string arg = (baseline.HasValue ? baseline.Value.ToString("F2") : "-"); Plugin.Log.LogInfo((object)($"[MonsterFallDamage:착지] id={((Object)c).GetInstanceID()} {name} | 최고높이={maxAlt:F2} " + $"기준점(점프반영)={arg} 착지높이={currentY:F2} 낙하높이={fallHeight:F2} " + string.Format("비행={0} 적용데미지={1:F1} 제외사유={2}", c.IsFlying(), damage, exemptReason ?? "없음"))); } } }